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

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Fri Aug 10 16:24:04 UTC 2018


Rebased ref, commits from common ancestor:
commit faf79cec2ec4097f03b1f1c78c23e681dec6a40c
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Thu Aug 9 17:26:50 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: also reset Merge flag in CheckParaRedlineMerge
    
    If it sets the Merge flag, it needs to reset it too.
    
    Change-Id: I0b07ca87ff9911db37166312ca07edd15e8b496c

diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index f023d069b740..21de262420bf 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -102,6 +102,10 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode,
     }
     if (!bHaveRedlines)
     {
+        if (pNode->GetRedlineMergeFlag() != SwNode::Merge::None)
+        {
+            pNode->SetRedlineMergeFlag(SwNode::Merge::None);
+        }
         return nullptr;
     }
     if (nLastEnd != pNode->Len())
commit 7d10c2c6239c5a8912d6d99f668f801de4eddc86
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Thu Aug 9 17:25:15 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: when switching show/hide, invalidate Insert redlines
    
    ... so that the frames are repainted with/without font color.
    
    Change-Id: I68f105868d262c9d0a88f124c98243a64159aa38

diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index 513e8c339f8a..b7cde56120e1 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -31,6 +31,7 @@
 #include <IDocumentSettingAccess.hxx>
 #include <IDocumentFieldsAccess.hxx>
 #include <IDocumentRedlineAccess.hxx>
+#include <redline.hxx>
 #include <fesh.hxx>
 #include <docsh.hxx>
 #include <ftninfo.hxx>
@@ -4461,6 +4462,15 @@ void SwRootFrame::SetHideRedlines(bool const bHideRedlines)
         AppendAllObjs(rDoc.GetSpzFrameFormats(), this);
     }
 
+    for (auto const pRedline : rDoc.getIDocumentRedlineAccess().GetRedlineTable())
+    {   // DELETE are handled by the code above; for other types, need to
+        // trigger repaint of text frames to add/remove the redline color font
+        if (pRedline->GetType() != nsRedlineType_t::REDLINE_DELETE)
+        {
+            pRedline->InvalidateRange();
+        }
+    }
+
 //    InvalidateAllContent(SwInvalidateFlags::Size); // ??? TODO what to invalidate?  this is the big hammer
 }
 
commit 615a913ddb7019d13901ea24be08071d93f59aed
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Thu Aug 9 17:24:05 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: fix painting of "bars" in the margin
    
    If the layout wants to hide redlines, these should not be painted.
    
    Change-Id: I3cc725b466ca3874a00c6b96eb0e02ff70dcc42b

diff --git a/sw/source/core/text/frmpaint.cxx b/sw/source/core/text/frmpaint.cxx
index 4d2adf502528..4b3007087c6d 100644
--- a/sw/source/core/text/frmpaint.cxx
+++ b/sw/source/core/text/frmpaint.cxx
@@ -288,8 +288,12 @@ void SwTextFrame::PaintExtraData( const SwRect &rRect ) const
     bool bLineNum = !IsInTab() && rLineInf.IsPaintLineNumbers() &&
                ( !IsInFly() || rLineInf.IsCountInFlys() ) && rLineNum.IsCount();
     sal_Int16 eHor = static_cast<sal_Int16>(SW_MOD()->GetRedlineMarkPos());
-    if( eHor != text::HoriOrientation::NONE && !IDocumentRedlineAccess::IsShowChanges( rIDRA.GetRedlineFlags() ) )
+    if (eHor != text::HoriOrientation::NONE
+        && (!IDocumentRedlineAccess::IsShowChanges(rIDRA.GetRedlineFlags())
+            || getRootFrame()->IsHideRedlines()))
+    {
         eHor = text::HoriOrientation::NONE;
+    }
     bool bRedLine = eHor != text::HoriOrientation::NONE;
     if ( !bLineNum && !bRedLine )
         return;
@@ -475,7 +479,8 @@ bool SwTextFrame::PaintEmpty( const SwRect &rRect, bool bCheck ) const
             }
 
             const IDocumentRedlineAccess& rIDRA = rTextNode.getIDocumentRedlineAccess();
-            if( IDocumentRedlineAccess::IsShowChanges( rIDRA.GetRedlineFlags() ) )
+            if (IDocumentRedlineAccess::IsShowChanges(rIDRA.GetRedlineFlags())
+                && !getRootFrame()->IsHideRedlines())
             {
                 const SwRedlineTable::size_type nRedlPos = rIDRA.GetRedlinePos( rTextNode, USHRT_MAX );
                 if( SwRedlineTable::npos != nRedlPos )
diff --git a/sw/source/core/text/porrst.cxx b/sw/source/core/text/porrst.cxx
index 24778b6ec9d6..727e0319a730 100644
--- a/sw/source/core/text/porrst.cxx
+++ b/sw/source/core/text/porrst.cxx
@@ -250,7 +250,8 @@ SwTwips SwTextFrame::EmptyHeight() const
     }
 
     const IDocumentRedlineAccess& rIDRA = rTextNode.getIDocumentRedlineAccess();
-    if( IDocumentRedlineAccess::IsShowChanges( rIDRA.GetRedlineFlags() ) )
+    if (IDocumentRedlineAccess::IsShowChanges(rIDRA.GetRedlineFlags())
+        && !getRootFrame()->IsHideRedlines())
     {
         const SwRedlineTable::size_type nRedlPos = rIDRA.GetRedlinePos( rTextNode, USHRT_MAX );
         if( SwRedlineTable::npos != nRedlPos )
commit f9138d52ff6689bf757832a78bc9302070527345
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Thu Aug 9 17:22:36 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: fix init of SwRedlineIter::Mode
    
    If there are no delete redlines in a frame, the mode must be Ignore,
    otherwise the insert redlines will be colorful...
    
    Change-Id: Ibd57f2827b0805ac2fdb29ed347d9b2ed0b00737

diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index 5bcb4d1b4350..f023d069b740 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -287,7 +287,8 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
             }
         }
     }
-    const bool bShow = IDocumentRedlineAccess::IsShowChanges( rIDRA.GetRedlineFlags() );
+    const bool bShow = IDocumentRedlineAccess::IsShowChanges(rIDRA.GetRedlineFlags())
+        && pRootFrame && !pRootFrame->IsHideRedlines();
     if (pExtInp || m_pMergedPara || bShow)
     {
         SwRedlineTable::size_type nRedlPos = rIDRA.GetRedlinePos( rTextNode, USHRT_MAX );
commit e1b24b66b5fecf70e649d901e70f33bbaa2d76f3
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Thu Aug 9 15:10:13 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: fix ordering of SplitNode usage of ContentIdxStore 2
    
    The flys have their anchor positions updated, and that causes lookups
    from the layout frame to the anchor SwTextFrame, but that isn't updated
    yet; it looks like the fly restore must be done after adapting the
    SwTextFrames, while the redline restore must be done before.
    
    Also RegisterToNode must call Check only for the 1st node.
    
    Change-Id: If87a62108f1bcaf794e5be1cc38dc936f08cd69e

diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx
index a32ea79c310a..82044796a5eb 100644
--- a/sw/inc/ndtxt.hxx
+++ b/sw/inc/ndtxt.hxx
@@ -62,6 +62,8 @@ class SwGrammarMarkUp;
 struct SwDocStat;
 struct SwParaIdleData_Impl;
 
+namespace sw { namespace mark { enum class RestoreMode; } }
+
 namespace com { namespace sun { namespace star {
     namespace uno {
         template < class > class Sequence;
@@ -349,7 +351,7 @@ public:
     /// Virtual methods from ContentNode.
     virtual SwContentFrame *MakeFrame( SwFrame* ) override;
     SwTextNode * SplitContentNode(const SwPosition &,
-            std::function<void (SwTextNode *)> const* pContentIndexRestore);
+            std::function<void (SwTextNode *, sw::mark::RestoreMode)> const* pContentIndexRestore);
     virtual SwContentNode *JoinNext() override;
     void JoinPrev();
 
diff --git a/sw/source/core/doc/CntntIdxStore.cxx b/sw/source/core/doc/CntntIdxStore.cxx
index ffdf2ff15764..0bdd11bae239 100644
--- a/sw/source/core/doc/CntntIdxStore.cxx
+++ b/sw/source/core/doc/CntntIdxStore.cxx
@@ -151,26 +151,38 @@ namespace
             SaveUnoCursors(pDoc, nNode, nContent);
             SaveShellCursors(pDoc, nNode, nContent);
         }
-        virtual void Restore(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nOffset=0, bool bAuto = false) override
+        virtual void Restore(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nOffset=0, bool bAuto = false, RestoreMode eMode = RestoreMode::All) override
         {
             SwContentNode* pCNd = pDoc->GetNodes()[ nNode ]->GetContentNode();
             updater_t aUpdater = OffsetUpdater(pCNd, nOffset);
-            RestoreBkmks(pDoc, aUpdater);
-            RestoreRedlines(pDoc, aUpdater);
-            RestoreFlys(pDoc, aUpdater, bAuto);
-            RestoreUnoCursors(aUpdater);
-            RestoreShellCursors(aUpdater);
+            if (eMode & RestoreMode::NonFlys)
+            {
+                RestoreBkmks(pDoc, aUpdater);
+                RestoreRedlines(pDoc, aUpdater);
+                RestoreUnoCursors(aUpdater);
+                RestoreShellCursors(aUpdater);
+            }
+            if (eMode & RestoreMode::Flys)
+            {
+                RestoreFlys(pDoc, aUpdater, bAuto);
+            }
         }
-        virtual void Restore(SwNode& rNd, sal_Int32 nLen, sal_Int32 nCorrLen) override
+        virtual void Restore(SwNode& rNd, sal_Int32 nLen, sal_Int32 nCorrLen, RestoreMode eMode = RestoreMode::All) override
         {
             SwContentNode* pCNd = rNd.GetContentNode();
             SwDoc* pDoc = rNd.GetDoc();
             updater_t aUpdater = LimitUpdater(pCNd, nLen, nCorrLen);
-            RestoreBkmks(pDoc, aUpdater);
-            RestoreRedlines(pDoc, aUpdater);
-            RestoreFlys(pDoc, aUpdater, false);
-            RestoreUnoCursors(aUpdater);
-            RestoreShellCursors(aUpdater);
+            if (eMode & RestoreMode::NonFlys)
+            {
+                RestoreBkmks(pDoc, aUpdater);
+                RestoreRedlines(pDoc, aUpdater);
+                RestoreUnoCursors(aUpdater);
+                RestoreShellCursors(aUpdater);
+            }
+            if (eMode & RestoreMode::Flys)
+            {
+                RestoreFlys(pDoc, aUpdater, false);
+            }
         }
 
         private:
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index acca6b19c0e2..20f237eafc1e 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -1991,12 +1991,12 @@ bool DocumentContentOperationsManager::MoveRange( SwPaM& rPaM, SwPosition& rPos,
         assert(aSavePam.GetPoint()->nNode == rPos.nNode.GetIndex());
         assert(rPos.nNode.GetIndex() == pOrigNode->GetIndex());
 
-        std::function<void (SwTextNode *)> restoreFunc(
-            [&](SwTextNode *const)
+        std::function<void (SwTextNode *, sw::mark::RestoreMode)> restoreFunc(
+            [&](SwTextNode *const, sw::mark::RestoreMode const eMode)
             {
                 if (!pContentStore->Empty())
                 {
-                    pContentStore->Restore(&m_rDoc, pOrigNode->GetIndex()-1, 0, true);
+                    pContentStore->Restore(&m_rDoc, pOrigNode->GetIndex()-1, 0, true, eMode);
                 }
             });
         pTNd = pTNd->SplitContentNode(rPos, &restoreFunc)->GetTextNode();
@@ -2937,12 +2937,12 @@ bool DocumentContentOperationsManager::SplitNode( const SwPosition &rPos, bool b
     const std::shared_ptr<sw::mark::ContentIdxStore> pContentStore(sw::mark::ContentIdxStore::Create());
     pContentStore->Save( &m_rDoc, rPos.nNode.GetIndex(), rPos.nContent.GetIndex(), true );
     assert(pNode->IsTextNode());
-    std::function<void (SwTextNode *)> restoreFunc(
-        [&](SwTextNode *const)
+    std::function<void (SwTextNode *, sw::mark::RestoreMode)> restoreFunc(
+        [&](SwTextNode *const, sw::mark::RestoreMode const eMode)
         {
             if (!pContentStore->Empty())
             {   // move all bookmarks, TOXMarks, FlyAtCnt
-                pContentStore->Restore(&m_rDoc, rPos.nNode.GetIndex()-1, 0, true);
+                pContentStore->Restore(&m_rDoc, rPos.nNode.GetIndex()-1, 0, true, eMode);
             }
         });
     pNode = pNode->GetTextNode()->SplitContentNode(rPos, &restoreFunc);
diff --git a/sw/source/core/docnode/ndtbl.cxx b/sw/source/core/docnode/ndtbl.cxx
index ed96fae59ee3..6041221efbe6 100644
--- a/sw/source/core/docnode/ndtbl.cxx
+++ b/sw/source/core/docnode/ndtbl.cxx
@@ -1072,12 +1072,12 @@ SwTableNode* SwNodes::TextToTable( const SwNodeRange& rRange, sal_Unicode cCh,
                 if (pTextNd->GetText()[nChPos] == cCh)
                 {
                     aCntPos.nContent = nChPos;
-                    std::function<void (SwTextNode *)> restoreFunc(
-                        [&](SwTextNode *const pNewNode)
+                    std::function<void (SwTextNode *, sw::mark::RestoreMode)> restoreFunc(
+                        [&](SwTextNode *const pNewNode, sw::mark::RestoreMode const eMode)
                         {
                             if (!pContentStore->Empty())
                             {
-                                pContentStore->Restore(*pNewNode, nChPos, nChPos + 1);
+                                pContentStore->Restore(*pNewNode, nChPos, nChPos + 1, eMode);
                             }
                         });
                     SwContentNode *const pNewNd =
diff --git a/sw/source/core/inc/mvsave.hxx b/sw/source/core/inc/mvsave.hxx
index 1279617ef313..ec0a1e412787 100644
--- a/sw/source/core/inc/mvsave.hxx
+++ b/sw/source/core/inc/mvsave.hxx
@@ -23,6 +23,7 @@
 #include <IDocumentMarkAccess.hxx>
 #include <vector>
 #include <deque>
+#include <o3tl/typed_flags_set.hxx>
 
 namespace sfx2 {
     class MetadatableUndo;
@@ -66,20 +67,27 @@ namespace sw { namespace mark
             std::shared_ptr< ::sfx2::MetadatableUndo > m_pMetadataUndo;
     };
 
+    enum class RestoreMode { Flys = 1, NonFlys = 2, All = 3 };
+
     /// Takes care of storing relevant attributes of an SwTextNode before split, then restore them on the new node.
     class ContentIdxStore
     {
     public:
+
             virtual void Clear() =0;
             virtual bool Empty() =0;
             virtual void Save(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nContent, bool bSaveFlySplit=false) =0;
-            virtual void Restore(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nOffset=0, bool bAuto = false) =0;
-            virtual void Restore(SwNode& rNd, sal_Int32 nLen, sal_Int32 nCorrLen) =0;
+            virtual void Restore(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nOffset=0, bool bAuto = false, RestoreMode = RestoreMode::All) =0;
+            virtual void Restore(SwNode& rNd, sal_Int32 nLen, sal_Int32 nCorrLen, RestoreMode = RestoreMode::All) =0;
             virtual ~ContentIdxStore() {};
             static std::shared_ptr<ContentIdxStore> Create();
     };
 }}
 
+namespace o3tl {
+    template<> struct typed_flags<sw::mark::RestoreMode> : is_typed_flags<sw::mark::RestoreMode, 3> {};
+}
+
 void DelBookmarks(const SwNodeIndex& rStt,
     const SwNodeIndex& rEnd,
     std::vector< ::sw::mark::SaveBookmark> * SaveBkmk =nullptr,
diff --git a/sw/source/core/layout/ssfrm.cxx b/sw/source/core/layout/ssfrm.cxx
index d847bf6f21bd..a6401fd07d7a 100644
--- a/sw/source/core/layout/ssfrm.cxx
+++ b/sw/source/core/layout/ssfrm.cxx
@@ -444,7 +444,8 @@ void SwTextFrame::RegisterToNode(SwTextNode & rNode)
 {
     assert(&rNode != GetDep());
     // sw_redlinehide: use New here, because the only caller also calls lcl_ChangeFootnoteRef
-    m_pMergedPara = sw::CheckParaRedlineMerge(*this, rNode, sw::FrameMode::New);
+    SwTextNode & rFirstNode(m_pMergedPara ? *m_pMergedPara->pFirstNode : rNode);
+    m_pMergedPara = sw::CheckParaRedlineMerge(*this, rFirstNode, sw::FrameMode::New);
     if (!m_pMergedPara)
     {
         rNode.Add(this);
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index a1e14f7a732f..6bd1913e4272 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -365,7 +365,7 @@ static void lcl_ChangeFootnoteRef( SwTextNode &rNode )
 }
 
 SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
-        std::function<void (SwTextNode *)> const*const pContentIndexRestore)
+        std::function<void (SwTextNode *, sw::mark::RestoreMode)> const*const pContentIndexRestore)
 {
     bool parentIsOutline = IsOutline();
 
@@ -478,7 +478,7 @@ SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
 
         if (pContentIndexRestore)
         {   // call before making frames and before RegisterToNode
-            (*pContentIndexRestore)(pNode);
+            (*pContentIndexRestore)(pNode, sw::mark::RestoreMode::NonFlys);
         }
 
         SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*this);
@@ -525,6 +525,10 @@ SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
         }
         pNode->MakeFramesForAdjacentContentNode(*this);
         lcl_ChangeFootnoteRef( *this );
+        if (pContentIndexRestore)
+        {   // call after making frames
+            (*pContentIndexRestore)(pNode, sw::mark::RestoreMode::Flys);
+        }
     }
     else
     {
@@ -582,7 +586,7 @@ SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
 
         if (pContentIndexRestore)
         {   // call before making frames
-            (*pContentIndexRestore)(pNode);
+            (*pContentIndexRestore)(pNode, sw::mark::RestoreMode::NonFlys);
         }
 
         if ( HasWriterListeners() )
@@ -590,6 +594,10 @@ SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
             MakeFramesForAdjacentContentNode(*pNode);
         }
         lcl_ChangeFootnoteRef( *pNode );
+        if (pContentIndexRestore)
+        {   // call after making frames
+            (*pContentIndexRestore)(pNode, sw::mark::RestoreMode::Flys);
+        }
     }
 
     {
diff --git a/sw/source/core/undo/untbl.cxx b/sw/source/core/undo/untbl.cxx
index e2912ddb2587..d8e8c75f90ae 100644
--- a/sw/source/core/undo/untbl.cxx
+++ b/sw/source/core/undo/untbl.cxx
@@ -557,12 +557,12 @@ SwTableNode* SwNodes::UndoTableToText( sal_uLong nSttNd, sal_uLong nEndNd,
 
             pTextNd->EraseText( aCntPos, 1 );
 
-            std::function<void (SwTextNode *)> restoreFunc(
-                [&](SwTextNode *const pNewNode)
+            std::function<void (SwTextNode *, sw::mark::RestoreMode)> restoreFunc(
+                [&](SwTextNode *const pNewNode, sw::mark::RestoreMode const eMode)
                 {
                     if (!pContentStore->Empty())
                     {
-                        pContentStore->Restore(*pNewNode, pSave->m_nContent, pSave->m_nContent + 1);
+                        pContentStore->Restore(*pNewNode, pSave->m_nContent, pSave->m_nContent + 1, eMode);
                     }
                 });
             pTextNd->SplitContentNode(
commit bbf4159638c303059d72b4d1b747de7693b33cca
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Wed Aug 8 16:13:58 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: fix ordering of SplitNode usage of ContentIdxStore
    
    The problem is that now the ctor of SwTextFrame will check the redline
    positions, but the call to MakeFramesForAdjacentContentNode()
    happens before the call to ContentIdxStore::Restore() that updates
    the SwPositions of the redlines, hence they point to the wrong node.
    
    Try to fix this by not calling Restore directly but pass in a closure
    to SwTextNode::SplitContentNode() so that it can call
    ContentIdxStore::Restore() before frames are created and redline positions
    are checked.
    
    Also remove the useless SwContentNode::SplitContentNode() - only the
    SwTextNode override actually did anything.
    
    Change-Id: I2088fd124d04cf354f4f0f691a50ff5217d778d7

diff --git a/sw/inc/ndgrf.hxx b/sw/inc/ndgrf.hxx
index a5e4e0cc2969..74c46f20b238 100644
--- a/sw/inc/ndgrf.hxx
+++ b/sw/inc/ndgrf.hxx
@@ -80,7 +80,6 @@ public:
     const Graphic&          GetGrf(bool bWait = false) const;
     const GraphicObject&    GetGrfObj(bool bWait = false) const;
     const GraphicObject* GetReplacementGrfObj() const;
-    virtual SwContentNode *SplitContentNode( const SwPosition & ) override;
 
     /// isolated only way to set GraphicObject to allow more actions when doing so
     void SetGraphic(const Graphic& rGraphic);
diff --git a/sw/inc/ndole.hxx b/sw/inc/ndole.hxx
index 4f6f4596736d..93139c986526 100644
--- a/sw/inc/ndole.hxx
+++ b/sw/inc/ndole.hxx
@@ -111,8 +111,6 @@ public:
           SwOLEObj& GetOLEObj()       { return maOLEObj; }
     virtual ~SwOLENode() override;
 
-    virtual SwContentNode *SplitContentNode( const SwPosition & ) override;
-
     /// Is in ndcopy.cxx.
     virtual SwContentNode* MakeCopy( SwDoc*, const SwNodeIndex& ) const override;
 
diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx
index d1a8801eb9c7..a32ea79c310a 100644
--- a/sw/inc/ndtxt.hxx
+++ b/sw/inc/ndtxt.hxx
@@ -34,6 +34,7 @@
 #include <memory>
 #include <vector>
 #include <set>
+#include <functional>
 
 class SfxHint;
 class SwNumRule;
@@ -347,7 +348,8 @@ public:
 
     /// Virtual methods from ContentNode.
     virtual SwContentFrame *MakeFrame( SwFrame* ) override;
-    virtual SwContentNode *SplitContentNode( const SwPosition & ) override;
+    SwTextNode * SplitContentNode(const SwPosition &,
+            std::function<void (SwTextNode *)> const* pContentIndexRestore);
     virtual SwContentNode *JoinNext() override;
     void JoinPrev();
 
diff --git a/sw/inc/node.hxx b/sw/inc/node.hxx
index 0c5ee9a9f309..2257446b2f9e 100644
--- a/sw/inc/node.hxx
+++ b/sw/inc/node.hxx
@@ -387,8 +387,6 @@ public:
        pSib is another SwFrame of the same layout (e.g. the SwRootFrame itself, a sibling, the parent) */
     virtual SwContentFrame *MakeFrame( SwFrame* pSib ) = 0;
 
-    virtual SwContentNode *SplitContentNode(const SwPosition & ) = 0;
-
     virtual SwContentNode *JoinNext();
     /** Is it possible to join two nodes?
        In pIdx the second position can be returned. */
diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx
index 256fce7bbe4d..acca6b19c0e2 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -1991,7 +1991,15 @@ bool DocumentContentOperationsManager::MoveRange( SwPaM& rPaM, SwPosition& rPos,
         assert(aSavePam.GetPoint()->nNode == rPos.nNode.GetIndex());
         assert(rPos.nNode.GetIndex() == pOrigNode->GetIndex());
 
-        pTNd = pTNd->SplitContentNode( rPos )->GetTextNode();
+        std::function<void (SwTextNode *)> restoreFunc(
+            [&](SwTextNode *const)
+            {
+                if (!pContentStore->Empty())
+                {
+                    pContentStore->Restore(&m_rDoc, pOrigNode->GetIndex()-1, 0, true);
+                }
+            });
+        pTNd = pTNd->SplitContentNode(rPos, &restoreFunc)->GetTextNode();
 
         //A new node was inserted before the orig pTNd and the content up to
         //rPos moved into it. The old node is returned with the remainder
@@ -2011,9 +2019,6 @@ bool DocumentContentOperationsManager::MoveRange( SwPaM& rPaM, SwPosition& rPos,
         aSavePam.GetPoint()->nContent.Assign(pOrigNode, 0);
         rPos = *aSavePam.GetMark() = *aSavePam.GetPoint();
 
-        if( !pContentStore->Empty() )
-            pContentStore->Restore( &m_rDoc, rPos.nNode.GetIndex()-1, 0, true );
-
         // correct the PaM!
         if( rPos.nNode == rPaM.GetMark()->nNode )
         {
@@ -2931,15 +2936,18 @@ bool DocumentContentOperationsManager::SplitNode( const SwPosition &rPos, bool b
 
     const std::shared_ptr<sw::mark::ContentIdxStore> pContentStore(sw::mark::ContentIdxStore::Create());
     pContentStore->Save( &m_rDoc, rPos.nNode.GetIndex(), rPos.nContent.GetIndex(), true );
-    // FIXME: only SwTextNode has a valid implementation of SplitContentNode!
-    OSL_ENSURE(pNode->IsTextNode(), "splitting non-text node?");
-    pNode = pNode->SplitContentNode( rPos );
+    assert(pNode->IsTextNode());
+    std::function<void (SwTextNode *)> restoreFunc(
+        [&](SwTextNode *const)
+        {
+            if (!pContentStore->Empty())
+            {   // move all bookmarks, TOXMarks, FlyAtCnt
+                pContentStore->Restore(&m_rDoc, rPos.nNode.GetIndex()-1, 0, true);
+            }
+        });
+    pNode = pNode->GetTextNode()->SplitContentNode(rPos, &restoreFunc);
     if (pNode)
     {
-        // move all bookmarks, TOXMarks, FlyAtCnt
-        if( !pContentStore->Empty() )
-            pContentStore->Restore( &m_rDoc, rPos.nNode.GetIndex()-1, 0, true );
-
         // To-Do - add 'SwExtraRedlineTable' also ?
         if( m_rDoc.getIDocumentRedlineAccess().IsRedlineOn() || (!m_rDoc.getIDocumentRedlineAccess().IsIgnoreRedline() && !m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty() ))
         {
diff --git a/sw/source/core/docnode/ndtbl.cxx b/sw/source/core/docnode/ndtbl.cxx
index d5b62a198d0a..ed96fae59ee3 100644
--- a/sw/source/core/docnode/ndtbl.cxx
+++ b/sw/source/core/docnode/ndtbl.cxx
@@ -1072,10 +1072,16 @@ SwTableNode* SwNodes::TextToTable( const SwNodeRange& rRange, sal_Unicode cCh,
                 if (pTextNd->GetText()[nChPos] == cCh)
                 {
                     aCntPos.nContent = nChPos;
-                    SwContentNode* pNewNd = pTextNd->SplitContentNode( aCntPos );
-
-                    if( !pContentStore->Empty() )
-                        pContentStore->Restore( *pNewNd, nChPos, nChPos + 1 );
+                    std::function<void (SwTextNode *)> restoreFunc(
+                        [&](SwTextNode *const pNewNode)
+                        {
+                            if (!pContentStore->Empty())
+                            {
+                                pContentStore->Restore(*pNewNode, nChPos, nChPos + 1);
+                            }
+                        });
+                    SwContentNode *const pNewNd =
+                        pTextNd->SplitContentNode(aCntPos, &restoreFunc);
 
                     // Delete separator and correct search string
                     pTextNd->EraseText( aCntPos.nContent, 1 );
diff --git a/sw/source/core/docnode/nodes.cxx b/sw/source/core/docnode/nodes.cxx
index 0747395460d8..b43e9e67d583 100644
--- a/sw/source/core/docnode/nodes.cxx
+++ b/sw/source/core/docnode/nodes.cxx
@@ -1512,7 +1512,7 @@ void SwNodes::MoveRange( SwPaM & rPam, SwPosition & rPos, SwNodes& rNodes )
             }
             else
             {
-                pDestNd->SplitContentNode( rPos );
+                pDestNd->SplitContentNode(rPos, nullptr);
             }
 
             if( rPos.nNode == aEndIdx )
@@ -1577,7 +1577,7 @@ void SwNodes::MoveRange( SwPaM & rPam, SwPosition & rPos, SwNodes& rNodes )
                 }
                 else
                 {
-                    pDestNd->SplitContentNode( rPos );
+                    pDestNd->SplitContentNode(rPos, nullptr);
                 }
 
                 if ( bCorrEnd )
diff --git a/sw/source/core/graphic/ndgrf.cxx b/sw/source/core/graphic/ndgrf.cxx
index 63a0c43d946c..d0f5173645c0 100644
--- a/sw/source/core/graphic/ndgrf.cxx
+++ b/sw/source/core/graphic/ndgrf.cxx
@@ -401,11 +401,6 @@ const GraphicObject* SwGrfNode::GetReplacementGrfObj() const
     return mpReplacementGraphic.get();
 }
 
-SwContentNode *SwGrfNode::SplitContentNode( const SwPosition & )
-{
-    return this;
-}
-
 SwGrfNode * SwNodes::MakeGrfNode( const SwNodeIndex & rWhere,
                                 const OUString& rGrfName,
                                 const OUString& rFltName,
diff --git a/sw/source/core/ole/ndole.cxx b/sw/source/core/ole/ndole.cxx
index e4b6115fd0ec..8d59c502817c 100644
--- a/sw/source/core/ole/ndole.cxx
+++ b/sw/source/core/ole/ndole.cxx
@@ -242,13 +242,6 @@ const Graphic* SwOLENode::GetGraphic()
     return nullptr;
 }
 
-SwContentNode *SwOLENode::SplitContentNode( const SwPosition & )
-{
-    // Multiply OLE objects?
-    OSL_FAIL( "OleNode: can't split." );
-    return this;
-}
-
 /**
  * Loading a OLE object that has been moved to the Undo Area
  */
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index 880ce8ea14a3..a1e14f7a732f 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -364,7 +364,8 @@ static void lcl_ChangeFootnoteRef( SwTextNode &rNode )
     }
 }
 
-SwContentNode *SwTextNode::SplitContentNode( const SwPosition &rPos )
+SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
+        std::function<void (SwTextNode *)> const*const pContentIndexRestore)
 {
     bool parentIsOutline = IsOutline();
 
@@ -475,6 +476,11 @@ SwContentNode *SwTextNode::SplitContentNode( const SwPosition &rPos )
 
         }
 
+        if (pContentIndexRestore)
+        {   // call before making frames and before RegisterToNode
+            (*pContentIndexRestore)(pNode);
+        }
+
         SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*this);
         for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
         {
@@ -574,6 +580,11 @@ SwContentNode *SwTextNode::SplitContentNode( const SwPosition &rPos )
             SetSmartTags( pList2, false );
         }
 
+        if (pContentIndexRestore)
+        {   // call before making frames
+            (*pContentIndexRestore)(pNode);
+        }
+
         if ( HasWriterListeners() )
         {
             MakeFramesForAdjacentContentNode(*pNode);
diff --git a/sw/source/core/undo/untbl.cxx b/sw/source/core/undo/untbl.cxx
index f84dca847425..e2912ddb2587 100644
--- a/sw/source/core/undo/untbl.cxx
+++ b/sw/source/core/undo/untbl.cxx
@@ -556,10 +556,17 @@ SwTableNode* SwNodes::UndoTableToText( sal_uLong nSttNd, sal_uLong nEndNd,
             SwIndex aCntPos( pTextNd, pSave->m_nContent - 1 );
 
             pTextNd->EraseText( aCntPos, 1 );
-            SwContentNode* pNewNd = pTextNd->SplitContentNode(
-                                        SwPosition( aSttIdx, aCntPos ));
-            if( !pContentStore->Empty() )
-                pContentStore->Restore( *pNewNd, pSave->m_nContent, pSave->m_nContent + 1 );
+
+            std::function<void (SwTextNode *)> restoreFunc(
+                [&](SwTextNode *const pNewNode)
+                {
+                    if (!pContentStore->Empty())
+                    {
+                        pContentStore->Restore(*pNewNode, pSave->m_nContent, pSave->m_nContent + 1);
+                    }
+                });
+            pTextNd->SplitContentNode(
+                        SwPosition(aSttIdx, aCntPos), &restoreFunc);
         }
         else
         {
commit 72bdec50dd0ccf536206c4d6940d7b2576ddc169
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Wed Aug 8 13:29:44 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: adapt SwFlyFrameFormat::MakeFrames() ...
    
    ... and SwDrawFrameFormat::MakeFrames() to do nothing if anchored in
    hidden redline.
    
    Change-Id: Idb0668db81b20ee52cd9c0237c22f8fa72beb7b3

diff --git a/sw/source/core/draw/dcontact.cxx b/sw/source/core/draw/dcontact.cxx
index 96c0787ae835..100fa538d120 100644
--- a/sw/source/core/draw/dcontact.cxx
+++ b/sw/source/core/draw/dcontact.cxx
@@ -1837,11 +1837,17 @@ void SwDrawContact::ConnectToLayout( const SwFormatAnchor* pAnch )
                     // (1) proposed anchor frame isn't a follow and
                     // (2) drawing object isn't a control object to be anchored
                     //     in header/footer.
-                    const bool bAdd = ( !pFrame->IsContentFrame() ||
+                    bool bAdd = ( !pFrame->IsContentFrame() ||
                                         !static_cast<SwContentFrame*>(pFrame)->IsFollow() ) &&
                                       ( !::CheckControlLayer( GetMaster() ) ||
                                         !pFrame->FindFooterOrHeader() );
 
+                    if (bAdd && RndStdIds::FLY_AT_FLY != pAnch->GetAnchorId())
+                    {
+                        assert(pFrame->IsTextFrame());
+                        bAdd = IsAnchoredObjShown(*static_cast<SwTextFrame*>(pFrame), *pAnch);
+                    }
+
                     if( bAdd )
                     {
                         if ( RndStdIds::FLY_AT_FLY == pAnch->GetAnchorId() && !pFrame->IsFlyFrame() )
diff --git a/sw/source/core/inc/frmtool.hxx b/sw/source/core/inc/frmtool.hxx
index 05b2dc237253..fdc014d8a101 100644
--- a/sw/source/core/inc/frmtool.hxx
+++ b/sw/source/core/inc/frmtool.hxx
@@ -66,6 +66,8 @@ void RemoveHiddenObjsOfNode(SwTextNode const& rNode,
         std::vector<sw::Extent>::const_iterator * pIter,
         std::vector<sw::Extent>::const_iterator const* pEnd);
 
+bool IsAnchoredObjShown(SwTextFrame const& rFrame, SwFormatAnchor const& rAnchor);
+
 void AppendAllObjs(const SwFrameFormats* pTable, const SwFrame* pSib);
 
 // draw background with brush or graphics
diff --git a/sw/source/core/layout/atrfrm.cxx b/sw/source/core/layout/atrfrm.cxx
index 98e6538d3c61..3e5abda010f0 100644
--- a/sw/source/core/layout/atrfrm.cxx
+++ b/sw/source/core/layout/atrfrm.cxx
@@ -56,6 +56,7 @@
 #include <rootfrm.hxx>
 #include <cntfrm.hxx>
 #include <notxtfrm.hxx>
+#include <txtfrm.hxx>
 #include <crsrsh.hxx>
 #include <dflyobj.hxx>
 #include <dcontact.hxx>
@@ -3027,7 +3028,24 @@ void SwFlyFrameFormat::MakeFrames()
                 }
             }
 
-            if( pFrame->GetDrawObjs() )
+            if (bAdd)
+            {
+                switch (aAnchorAttr.GetAnchorId())
+                {
+                    case RndStdIds::FLY_AS_CHAR:
+                    case RndStdIds::FLY_AT_PARA:
+                    case RndStdIds::FLY_AT_CHAR:
+                    {
+                        assert(pFrame->IsTextFrame());
+                        bAdd = IsAnchoredObjShown(*static_cast<SwTextFrame*>(pFrame), aAnchorAttr);
+                    }
+                    break;
+                    default:
+                    break;
+                }
+            }
+
+            if (bAdd && pFrame->GetDrawObjs())
             {
                 // #i28701# - new type <SwSortedObjs>
                 SwSortedObjs &rObjs = *pFrame->GetDrawObjs();
diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx
index 11cb79523ba7..b7fec8eac2aa 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -1192,6 +1192,46 @@ void AppendObjs(const SwFrameFormats *const pTable, sal_uLong const nIndex,
     }
 }
 
+bool IsAnchoredObjShown(SwTextFrame const& rFrame, SwFormatAnchor const& rAnchor)
+{
+    assert(rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA ||
+           rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR ||
+           rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR);
+    bool ret(true);
+    if (auto const pMergedPara = rFrame.GetMergedPara())
+    {
+        ret = false;
+        auto const pAnchor(rAnchor.GetContentAnchor());
+        auto iterFirst(pMergedPara->extents.cbegin());
+        auto iter(iterFirst);
+        SwTextNode const* pNode(pMergedPara->pFirstNode);
+        for ( ; ; ++iter)
+        {
+            if (iter == pMergedPara->extents.end()
+                || iter->pNode != pNode)
+            {
+                assert(pNode->GetRedlineMergeFlag() != SwNode::Merge::Hidden);
+                if (pNode == &pAnchor->nNode.GetNode())
+                {
+                    ret = IsShown(pNode->GetIndex(), rAnchor, &iterFirst, &iter);
+                    break;
+                }
+                if (iter == pMergedPara->extents.end())
+                {
+                    break;
+                }
+                pNode = iter->pNode;
+                if (pAnchor->nNode.GetIndex() < pNode->GetIndex())
+                {
+                    break;
+                }
+                iterFirst = iter;
+            }
+        }
+    }
+    return ret;
+}
+
 void AppendAllObjs(const SwFrameFormats* pTable, const SwFrame* pSib)
 {
     //Connecting of all Objects, which are described in the SpzTable with the
commit 49f9a42436592aaca26899f4884e5c2690d8d1fd
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Aug 7 16:40:02 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: handle flys anchored in flys
    
    There is no way to iterate over the nodes-array such that flys are
    ordered wrt. the flys in whose content they are anchored; this makes
    it hard to ensure that flys anchored in flys are handled only once.
    
    For the Hide implementation, when the flys anchored to a non-first
    merged SwTextNode in a fly are inserted, ensure that the content of
    the same fly is skipped if it happens to come later in the nodes-array.
    
    For the Show implementation, the ::MakeFrames() would call
    AppendAllObj() anyway; suppress that and manually call it at the end,
    which should avoid the problem.
    
    Change-Id: I7fb31cf14ef26c095fa7e09edd4ab530add9f253

diff --git a/sw/source/core/inc/frmtool.hxx b/sw/source/core/inc/frmtool.hxx
index e692bb900ef6..05b2dc237253 100644
--- a/sw/source/core/inc/frmtool.hxx
+++ b/sw/source/core/inc/frmtool.hxx
@@ -66,6 +66,8 @@ void RemoveHiddenObjsOfNode(SwTextNode const& rNode,
         std::vector<sw::Extent>::const_iterator * pIter,
         std::vector<sw::Extent>::const_iterator const* pEnd);
 
+void AppendAllObjs(const SwFrameFormats* pTable, const SwFrame* pSib);
+
 // draw background with brush or graphics
 // The 6th parameter indicates that the method should consider background
 // transparency, saved in the color of the brush item.
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index 617c15d94731..513e8c339f8a 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -40,6 +40,7 @@
 #include <txtftn.hxx>
 #include <fmtftn.hxx>
 #include <fmtsrnd.hxx>
+#include <fmtcntnt.hxx>
 #include <ftnfrm.hxx>
 #include <tabfrm.hxx>
 #include <flyfrms.hxx>
@@ -4166,7 +4167,8 @@ void SwRootFrame::InvalidateAllObjPos()
 }
 
 static void UnHideRedlines(SwRootFrame & rLayout,
-        SwNodes & rNodes, SwNode const& rEndOfSectionNode)
+        SwNodes & rNodes, SwNode const& rEndOfSectionNode,
+        std::set<sal_uLong> *const pSkipped)
 {
     assert(rEndOfSectionNode.IsEndNode());
     for (sal_uLong i = rEndOfSectionNode.StartOfSectionNode()->GetIndex() + 1;
@@ -4251,6 +4253,20 @@ static void UnHideRedlines(SwRootFrame & rLayout,
                                             pNode->GetIndex(), pFrame, pPage,
                                             rTextNode.GetDoc(),
                                             &iterFirst, &iter);
+                                        if (pSkipped)
+                                        {
+                                            // if a fly has been added by AppendObjsOfNode, it must be skipped; if not, then it doesn't matter if it's skipped or not because it has no frames and because of that it would be skipped anyway
+                                            if (auto const pFlys = pNode->GetAnchoredFlys())
+                                            {
+                                                for (auto const pFly : *pFlys)
+                                                {
+                                                    if (pFly->Which() != RES_DRAWFRMFMT)
+                                                    {
+                                                        pSkipped->insert(pFly->GetContent().GetContentIdx()->GetIndex());
+                                                    }
+                                                }
+                                            }
+                                        }
                                     }
                                     if (iter == pMerged->extents.end())
                                     {
@@ -4302,33 +4318,8 @@ static void UnHideRedlines(SwRootFrame & rLayout,
                                     pNode = rExtent.pNode;
                                 }
                             }
-                            // add all flys in first node that are hidden
-                            std::vector<sw::Extent> hidden;
-                            sal_Int32 nLast(0);
-                            for (auto const& rExtent : pMergedPara->extents)
-                            {
-                                if (rExtent.pNode != &rTextNode)
-                                {
-                                    break;
-                                }
-                                if (rExtent.nStart != 0)
-                                {
-                                    assert(rExtent.nStart != nLast);
-
-                                    hidden.emplace_back(&rTextNode, nLast, rExtent.nStart);
-                                }
-                                nLast = rExtent.nEnd;
-                            }
-                            if (nLast != rTextNode.Len())
-                            {
-                                hidden.emplace_back(&rTextNode, nLast, rTextNode.Len());
-                            }
-                            SwFrameFormats& rTable(*rTextNode.GetDoc()->GetSpzFrameFormats());
-                            auto iterBegin(hidden.cbegin());
-                            auto const iterEnd(hidden.cend());
-                            AppendObjsOfNode(&rTable, rTextNode.GetIndex(), pFrame,
-                                pFrame->FindPageFrame(), rTextNode.GetDoc(),
-                                &iterBegin, &iterEnd);
+                            // rely on AppendAllObjs call at the end to add
+                            // all flys in first node that are hidden
                         }
                         pFrame->SetMergedPara(nullptr);
                         // ??? TODO recreate? or is invalidate enough?
@@ -4356,6 +4347,7 @@ static void UnHideRedlines(SwRootFrame & rLayout,
             }
             else
             {
+                assert(!rNode.IsContentNode() || !rNode.GetContentNode()->getLayoutFrame(&rLayout));
                 sal_uLong j = i + 1;
                 for ( ; j < rEndOfSectionNode.GetIndex(); ++j)
                 {
@@ -4368,7 +4360,10 @@ static void UnHideRedlines(SwRootFrame & rLayout,
                 // InsertCnt_ also checks for hidden sections
                 SwNodeIndex const start(rNodes, i);
                 SwNodeIndex const end(rNodes, j);
+                assert(!bDontCreateObjects);
+                bDontCreateObjects = true; // suppress here, to be called once
                 ::MakeFrames(rLayout.GetFormat()->GetDoc(), start, end);
+                bDontCreateObjects = false;
                 i = j - 1; // will be incremented again
             }
         }
@@ -4376,7 +4371,8 @@ static void UnHideRedlines(SwRootFrame & rLayout,
 }
 
 static void UnHideRedlinesExtras(SwRootFrame & rLayout,
-        SwNodes & rNodes, SwNode const& rEndOfExtraSectionNode)
+        SwNodes & rNodes, SwNode const& rEndOfExtraSectionNode,
+        std::set<sal_uLong> *const pSkipped)
 {
     assert(rEndOfExtraSectionNode.IsEndNode());
     for (sal_uLong i = rEndOfExtraSectionNode.StartOfSectionNode()->GetIndex()
@@ -4386,8 +4382,8 @@ static void UnHideRedlinesExtras(SwRootFrame & rLayout,
         assert(rStartNode.IsStartNode());
         assert(rStartNode.GetRedlineMergeFlag() == SwNode::Merge::None);
         SwNode const& rEndNode(*rStartNode.EndOfSectionNode());
+        bool bSkip(pSkipped ? pSkipped->find(i) != pSkipped->end() : false);
         i = rEndNode.GetIndex();
-        bool bSkip(false);
         for (sal_uLong j = rStartNode.GetIndex() + 1; j < i; ++j)
         {
             // note: SwStartNode has no way to access the frames, so check
@@ -4411,7 +4407,7 @@ static void UnHideRedlinesExtras(SwRootFrame & rLayout,
         }
         if (!bSkip)
         {
-            UnHideRedlines(rLayout, rNodes, rEndNode);
+            UnHideRedlines(rLayout, rNodes, rEndNode, pSkipped);
         }
     }
 }
@@ -4445,12 +4441,25 @@ void SwRootFrame::SetHideRedlines(bool const bHideRedlines)
     // Flys before footnotes: because footnotes may contain flys but not
     // vice-versa; alas flys may contain flys, so we skip some of them
     // if they have already been created from scratch via their anchor flys.
-    UnHideRedlinesExtras(*this, rNodes, rNodes.GetEndOfAutotext());
+    std::set<sal_uLong> skippedFlys;
+    UnHideRedlinesExtras(*this, rNodes, rNodes.GetEndOfAutotext(),
+        // when un-hiding, delay all fly frame creation to AppendAllObjs below
+                         IsHideRedlines() ? &skippedFlys : nullptr);
     // Footnotes are created automatically (after invalidation etc.) by
     // ConnectFootnote(), but need to be deleted manually. Footnotes do not
     // occur in flys or headers/footers.
-    UnHideRedlinesExtras(*this, rNodes, rNodes.GetEndOfInserts());
-    UnHideRedlines(*this, rNodes, rNodes.GetEndOfContent());
+    UnHideRedlinesExtras(*this, rNodes, rNodes.GetEndOfInserts(), nullptr);
+    UnHideRedlines(*this, rNodes, rNodes.GetEndOfContent(), nullptr);
+
+    if (!IsHideRedlines())
+    {   // create all previously hidden flys at once:
+        // * Flys on first node of pre-existing merged frames that are hidden
+        //   (in delete redline), to be added to the existing frame
+        // * Flys on non-first (hidden/merged) nodes of pre-existing merged
+        //   frames, to be added to the new frame of their node
+        // * Flys anchored in other flys that are hidden
+        AppendAllObjs(rDoc.GetSpzFrameFormats(), this);
+    }
 
 //    InvalidateAllContent(SwInvalidateFlags::Size); // ??? TODO what to invalidate?  this is the big hammer
 }
commit 1d44635b26060f2495bf82c08906ee3eba25b7c2
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Mon Aug 6 13:31:37 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: disable hiding at-char flys again
    
    Needs changes in Delete for consistency.
    
    Change-Id: If9382ebca9b6335ffef8c738840813837316f841

diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx
index d0a847e849ef..11cb79523ba7 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -1043,7 +1043,10 @@ static bool IsShown(sal_uLong const nIndex,
     {
         return false;
     }
-    if (pIter && rAnch.GetAnchorId() != RndStdIds::FLY_AT_PARA)
+    if (pIter && rAnch.GetAnchorId() != RndStdIds::FLY_AT_PARA
+        // sw_redlinehide: we want to hide AT_CHAR, but currently can't
+        // because Delete and Accept Redline don't delete them!
+              && rAnch.GetAnchorId() != RndStdIds::FLY_AT_CHAR)
     {
         // note: frames are not sorted by anchor position.
         assert(pEnd);
commit 59ed3c75e960fefeb15d10cf3c791f39150105bd
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Mon Aug 6 12:42:27 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: fix use-after-free in SwFootnoteFrame
    
    On hide, the SwTextFootnote::DelFrames() for a note in a deleted frame
    must actually delete the frames; if there's a follow SwTextFrame, then it
    might erroneously return without deleting anything.
    
    Change-Id: I7e9473b94feaf939be72e285553a8990c2ce1a06

diff --git a/sw/source/core/inc/ftnboss.hxx b/sw/source/core/inc/ftnboss.hxx
index a04c8ae172eb..ba363e53a2f7 100644
--- a/sw/source/core/inc/ftnboss.hxx
+++ b/sw/source/core/inc/ftnboss.hxx
@@ -75,7 +75,7 @@ public:
 
     // footnote interface
     void AppendFootnote( SwContentFrame *, SwTextFootnote * );
-    void RemoveFootnote( const SwContentFrame *, const SwTextFootnote *, bool bPrep = true );
+    bool RemoveFootnote(const SwContentFrame *, const SwTextFootnote *, bool bPrep = true);
     static       SwFootnoteFrame     *FindFootnote( const SwContentFrame *, const SwTextFootnote * );
                  SwFootnoteContFrame *FindFootnoteCont();
     inline const SwFootnoteContFrame *FindFootnoteCont() const;
diff --git a/sw/source/core/layout/ftnfrm.cxx b/sw/source/core/layout/ftnfrm.cxx
index e34c2603d7bd..591b50dc4af8 100644
--- a/sw/source/core/layout/ftnfrm.cxx
+++ b/sw/source/core/layout/ftnfrm.cxx
@@ -1641,12 +1641,15 @@ SwFootnoteFrame *SwFootnoteBossFrame::FindFootnote( const SwContentFrame *pRef,
     return nullptr;
 }
 
-void SwFootnoteBossFrame::RemoveFootnote( const SwContentFrame *pRef, const SwTextFootnote *pAttr,
+bool SwFootnoteBossFrame::RemoveFootnote(
+        const SwContentFrame *const pRef, const SwTextFootnote *const pAttr,
                               bool bPrep )
 {
+    bool ret(false);
     SwFootnoteFrame *pFootnote = FindFootnote( pRef, pAttr );
     if( pFootnote )
     {
+        ret = true;
         do
         {
             SwFootnoteFrame *pFoll = pFootnote->GetFollow();
@@ -1663,6 +1666,7 @@ void SwFootnoteBossFrame::RemoveFootnote( const SwContentFrame *pRef, const SwTe
         }
     }
     FindPageFrame()->UpdateFootnoteNum();
+    return ret;
 }
 
 void SwFootnoteBossFrame::ChangeFootnoteRef( const SwContentFrame *pOld, const SwTextFootnote *pAttr,
diff --git a/sw/source/core/txtnode/atrftn.cxx b/sw/source/core/txtnode/atrftn.cxx
index 26f41e0333eb..cc0e6f0ea12a 100644
--- a/sw/source/core/txtnode/atrftn.cxx
+++ b/sw/source/core/txtnode/atrftn.cxx
@@ -444,8 +444,12 @@ void SwTextFootnote::DelFrames( const SwFrame* pSib )
             SwPageFrame* pPage = pFnd->FindPageFrame();
             if( pPage )
             {
-                pPage->RemoveFootnote( pFnd, this );
-                bFrameFnd = true;
+                // note: we have found the correct frame only if the footnote
+                // was actually removed; in case this is called from
+                // SwTextFrame::DestroyImpl(), then that frame isn't connected
+                // to SwPageFrame any more, and RemoveFootnote on any follow
+                // must not prevent the fall-back to the !bFrameFnd code.
+                bFrameFnd = pPage->RemoveFootnote(pFnd, this);
             }
         }
     }
commit 330684a4e739a3d21450f1beb3cdb3c833319247
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Fri Aug 3 18:48:10 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: try to minimise invalidation on show/hide
    
    InvalidateAllContent(Size) will basically format every paragraph
    in the document from scratch; let's try to optimise this a bit
    by invalidating only the SwTextFrames that actually contain redlines
    and the SwPageFrames they're on, and also invalidate the position
    of all flys anchored at these frames as a precautionary measure.
    
    Change-Id: I22ed683dc2225992ee48faa6084f277ef8733e8b

diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index bc5aadf13375..617c15d94731 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -4208,6 +4208,20 @@ static void UnHideRedlines(SwRootFrame & rLayout,
                             pFrame->SetMergedPara(std::move(pMerged));
                         }
                         auto const pMerged(pFrame->GetMergedPara());
+                        if (pMerged)
+                        {
+                            // invalidate SwInvalidateFlags::Size
+                            pFrame->Prepare(PREP_CLEAR, nullptr, false);
+                            pFrame->InvalidatePage();
+                            if (auto const pObjs = pFrame->GetDrawObjs())
+                            {   // also invalidate position of existing flys
+                                // because they may need to be moved
+                                for (auto const pObject : *pObjs)
+                                {
+                                    pObject->InvalidateObjPos();
+                                }
+                            }
+                        }
                         if (pMerged
                             // do this only *once*, for the *last* frame
                             // otherwise AppendObj would create multiple frames for fly-frames!
@@ -4253,6 +4267,16 @@ static void UnHideRedlines(SwRootFrame & rLayout,
                 {
                     if (auto const& pMergedPara = pFrame->GetMergedPara())
                     {
+                        // invalidate SwInvalidateFlags::Size
+                        pFrame->Prepare(PREP_CLEAR, nullptr, false);
+                        pFrame->InvalidatePage();
+                        if (auto const pObjs = pFrame->GetDrawObjs())
+                        {   // also invalidate position of existing flys
+                            for (auto const pObject : *pObjs)
+                            {
+                                pObject->InvalidateObjPos();
+                            }
+                        }
                         // SwFlyAtContentFrame::Modify() always appends to
                         // the master frame, so do the same here.
                         // (RemoveFootnotesForNode must be called at least once)
@@ -4428,7 +4452,7 @@ void SwRootFrame::SetHideRedlines(bool const bHideRedlines)
     UnHideRedlinesExtras(*this, rNodes, rNodes.GetEndOfInserts());
     UnHideRedlines(*this, rNodes, rNodes.GetEndOfContent());
 
-    InvalidateAllContent(SwInvalidateFlags::Size); // ??? TODO what to invalidate?
+//    InvalidateAllContent(SwInvalidateFlags::Size); // ??? TODO what to invalidate?  this is the big hammer
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit e0c375bb2622965753ebab0b950a20a0cf383b1c
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Thu Aug 2 17:09:53 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: show/hide flys in redlines
    
    The old implementation would not actually hide at-char flys but move
    the anchor, which is clearly not ideal; better to hide them.
    
    Change-Id: If21d0360e04857752a2c84f5329eadfad7818ac8

diff --git a/sw/source/core/inc/frmtool.hxx b/sw/source/core/inc/frmtool.hxx
index 0ffe4a75c0f6..e692bb900ef6 100644
--- a/sw/source/core/inc/frmtool.hxx
+++ b/sw/source/core/inc/frmtool.hxx
@@ -45,6 +45,8 @@ class GraphicAttr;
 class SwPageDesc;
 class SwFrameFormats;
 class SwRegionRects;
+class SwTextNode;
+namespace sw { struct Extent; }
 
 #define FAR_AWAY (SAL_MAX_INT32 - 20000)  // initial position of a Fly
 #define BROWSE_HEIGHT (56700L * 10L) // 10 Meters
@@ -55,6 +57,15 @@ class SwRegionRects;
 void AppendObjs( const SwFrameFormats *pTable, sal_uLong nIndex,
                        SwFrame *pFrame, SwPageFrame *pPage, SwDoc* doc );
 
+void AppendObjsOfNode(SwFrameFormats const* pTable, sal_uLong nIndex,
+        SwFrame * pFrame, SwPageFrame * pPage, SwDoc * pDoc,
+        std::vector<sw::Extent>::const_iterator * pIter,
+        std::vector<sw::Extent>::const_iterator const* pEnd);
+
+void RemoveHiddenObjsOfNode(SwTextNode const& rNode,
+        std::vector<sw::Extent>::const_iterator * pIter,
+        std::vector<sw::Extent>::const_iterator const* pEnd);
+
 // draw background with brush or graphics
 // The 6th parameter indicates that the method should consider background
 // transparency, saved in the color of the brush item.
diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx
index 9b1ab7417028..d0a847e849ef 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -1039,32 +1039,63 @@ static bool IsShown(sal_uLong const nIndex,
     std::vector<sw::Extent>::const_iterator const*const pEnd)
 {
     SwPosition const& rAnchor(*rAnch.GetContentAnchor());
+    if (rAnchor.nNode.GetIndex() != nIndex)
+    {
+        return false;
+    }
     if (pIter && rAnch.GetAnchorId() != RndStdIds::FLY_AT_PARA)
     {
-        // TODO are frames sorted by anchor positions perhaps?
+        // note: frames are not sorted by anchor position.
         assert(pEnd);
         assert(rAnch.GetAnchorId() != RndStdIds::FLY_AT_FLY);
-        for ( ; *pIter != *pEnd; ++*pIter)
+        for (auto iter = *pIter; iter != *pEnd; ++iter)
         {
-            assert((**pIter).pNode->GetIndex() == nIndex);
-            if ((**pIter).nStart <= rAnchor.nContent.GetIndex())
+            assert(iter->pNode->GetIndex() == nIndex);
+            if (rAnchor.nContent.GetIndex() < iter->nStart)
             {
-                // TODO off by one? need < for AS_CHAR but what for AT_CHAR?
-                if (rAnchor.nContent.GetIndex() < (**pIter).nEnd)
-                {
-                    return true;
-                }
-                else
-                {
-                    return false;
-                }
+                return false;
+            }
+            // for AS_CHAR obviously must be <
+            // for AT_CHAR it is questionable whether < or <= should be used
+            // and there is the additional corner case of Len() to consider
+            // prefer < for now for symmetry (and inverted usage with
+            // "hidden") and handle special case explicitly
+            if (rAnchor.nContent.GetIndex() < iter->nEnd
+                || iter->nEnd == iter->pNode->Len())
+            {
+                return true;
             }
         }
         return false;
     }
     else
     {
-        return rAnch.GetContentAnchor()->nNode.GetIndex() == nIndex;
+        return true;
+    }
+}
+
+void RemoveHiddenObjsOfNode(SwTextNode const& rNode,
+    std::vector<sw::Extent>::const_iterator *const pIter,
+    std::vector<sw::Extent>::const_iterator const*const pEnd)
+{
+    std::vector<SwFrameFormat*> const*const pFlys(rNode.GetAnchoredFlys());
+    if (!pFlys)
+    {
+        return;
+    }
+    for (SwFrameFormat * pFrameFormat : *pFlys)
+    {
+        SwFormatAnchor const& rAnchor = pFrameFormat->GetAnchor();
+        if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR
+            || (rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR
+                && RES_DRAWFRMFMT == pFrameFormat->Which()))
+        {
+            assert(rAnchor.GetContentAnchor()->nNode.GetIndex() == rNode.GetIndex());
+            if (!IsShown(rNode.GetIndex(), rAnchor, pIter, pEnd))
+            {
+                pFrameFormat->DelFrames();
+            }
+        }
     }
 }
 
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index cfe0d11b56c8..bc5aadf13375 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -4182,7 +4182,15 @@ static void UnHideRedlines(SwRootFrame & rLayout,
             {
                 if (pFrame->getRootFrame() == &rLayout)
                 {
-                    frames.push_back(pFrame);
+                    if (pFrame->IsFollow())
+                    {
+                        frames.push_back(pFrame);
+                    }    // when hiding, the loop must remove the anchored flys
+                    else // *before* resetting SetMergedPara anywhere - else
+                    {    // the fly deletion code will access multiple of the
+                         // frames with inconsistent MergedPara and assert
+                        frames.insert(frames.begin(), pFrame);
+                    }
                 }
             }
             // this messes with pRegisteredIn so do it outside SwIterator
@@ -4194,29 +4202,111 @@ static void UnHideRedlines(SwRootFrame & rLayout,
                         rNode.GetRedlineMergeFlag() == SwNode::Merge::NonFirst);
                     if (rNode.IsCreateFrameWhenHidingRedlines())
                     {
-                        pFrame->SetMergedPara(CheckParaRedlineMerge(*pFrame,
-                                rTextNode, sw::FrameMode::Existing));
-                        // ??? TODO flys etc.
+                        {
+                            auto pMerged(CheckParaRedlineMerge(*pFrame,
+                                    rTextNode, sw::FrameMode::Existing));
+                            pFrame->SetMergedPara(std::move(pMerged));
+                        }
+                        auto const pMerged(pFrame->GetMergedPara());
+                        if (pMerged
+                            // do this only *once*, for the *last* frame
+                            // otherwise AppendObj would create multiple frames for fly-frames!
+                            && !pFrame->GetFollow())
+                        {
+                            // add visible flys in non-first node to merged frame
+                            // (hidden flys remain and are deleted via DelFrames())
+                            SwFrameFormats& rTable(*rTextNode.GetDoc()->GetSpzFrameFormats());
+                            SwPageFrame *const pPage(pFrame->FindPageFrame());
+                            std::vector<sw::Extent>::const_iterator iterFirst(pMerged->extents.begin());
+                            std::vector<sw::Extent>::const_iterator iter(iterFirst);
+                            SwTextNode const* pNode(&rTextNode);
+                            for ( ; ; ++iter)
+                            {
+                                if (iter == pMerged->extents.end()
+                                    || iter->pNode != pNode)
+                                {
+                                    if (pNode == &rTextNode)
+                                    {   // remove existing hidden at-char anchored flys
+                                        RemoveHiddenObjsOfNode(
+                                            rTextNode, &iterFirst, &iter);
+                                    }
+                                    else
+                                    {
+                                        // pNode's frame has been deleted by CheckParaRedlineMerge()
+                                        AppendObjsOfNode(&rTable,
+                                            pNode->GetIndex(), pFrame, pPage,
+                                            rTextNode.GetDoc(),
+                                            &iterFirst, &iter);
+                                    }
+                                    if (iter == pMerged->extents.end())
+                                    {
+                                        break;
+                                    }
+                                    pNode = iter->pNode;
+                                    iterFirst = iter;
+                                }
+                            }
+                        }
                     }
                 }
                 else
                 {
                     if (auto const& pMergedPara = pFrame->GetMergedPara())
                     {
-                        // the new text frames don't exist yet, so at this point
-                        // we can only delete the footnote frames so they don't
-                        // point to the merged SwTextFrame any more...
-                        SwTextNode const* pNode(&rTextNode);
-                        for (auto const& rExtent : pMergedPara->extents)
+                        // SwFlyAtContentFrame::Modify() always appends to
+                        // the master frame, so do the same here.
+                        // (RemoveFootnotesForNode must be called at least once)
+                        if (!pFrame->IsFollow())
                         {
-                            if (rExtent.pNode != pNode)
+                            // the new text frames don't exist yet, so at this point
+                            // we can only delete the footnote frames so they don't
+                            // point to the merged SwTextFrame any more...
+                            SwTextNode const* pNode(&rTextNode);
+                            for (auto const& rExtent : pMergedPara->extents)
+                            {
+                                if (rExtent.pNode != pNode)
+                                {
+                                    sw::RemoveFootnotesForNode(*pFrame, *rExtent.pNode, nullptr);
+                                    // similarly, remove the anchored flys
+                                    if (auto const pFlys = rExtent.pNode->GetAnchoredFlys())
+                                    {
+                                        for (SwFrameFormat * pFormat : *pFlys)
+                                        {
+                                            pFormat->DelFrames(/*&rLayout*/);
+                                        }
+                                    }
+                                    pNode = rExtent.pNode;
+                                }
+                            }
+                            // add all flys in first node that are hidden
+                            std::vector<sw::Extent> hidden;
+                            sal_Int32 nLast(0);
+                            for (auto const& rExtent : pMergedPara->extents)
+                            {
+                                if (rExtent.pNode != &rTextNode)
+                                {
+                                    break;
+                                }
+                                if (rExtent.nStart != 0)
+                                {
+                                    assert(rExtent.nStart != nLast);
+
+                                    hidden.emplace_back(&rTextNode, nLast, rExtent.nStart);
+                                }
+                                nLast = rExtent.nEnd;
+                            }
+                            if (nLast != rTextNode.Len())
                             {
-                                sw::RemoveFootnotesForNode(*pFrame, *rExtent.pNode, nullptr);
-                                pNode = rExtent.pNode;
+                                hidden.emplace_back(&rTextNode, nLast, rTextNode.Len());
                             }
+                            SwFrameFormats& rTable(*rTextNode.GetDoc()->GetSpzFrameFormats());
+                            auto iterBegin(hidden.cbegin());
+                            auto const iterEnd(hidden.cend());
+                            AppendObjsOfNode(&rTable, rTextNode.GetIndex(), pFrame,
+                                pFrame->FindPageFrame(), rTextNode.GetDoc(),
+                                &iterBegin, &iterEnd);
                         }
                         pFrame->SetMergedPara(nullptr);
-                        // ??? TODO flys etc.
                         // ??? TODO recreate? or is invalidate enough?
                     }
                 }
commit 0ea52c21d94830cbdbccb7ce07253622aaf05dae
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Jul 31 19:11:16 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: add layout parameter to *Node::DelFrames
    
    A trivial patch to remove some FIXMEs; unfortunately one new FIXME
    because the SwSectionNode case isn't entirely trivial.
    
    Change-Id: I94f11ffd19b189b165ad1fb05488ba8617e81357

diff --git a/sw/inc/node.hxx b/sw/inc/node.hxx
index ecc7ab109d0a..0c5ee9a9f309 100644
--- a/sw/inc/node.hxx
+++ b/sw/inc/node.hxx
@@ -418,10 +418,8 @@ public:
 
     /** Method deletes all views of document for the node. The content-
         frames are removed from the respective layout.
-
-        Add an input param to identify if acc table should be disposed
     */
-    void DelFrames( bool bIsAccTableDispose = true );
+    void DelFrames(SwRootFrame const* pLayout = nullptr);
 
     /** @return count of elements of node content. Default is 1.
        There are differences between text node and formula node. */
@@ -508,7 +506,7 @@ public:
 
     /** Method deletes all views of document for the node.
        The content frames are removed from the respective layout. */
-    void DelFrames();
+    void DelFrames(SwRootFrame const* pLayout = nullptr);
 
     /** Method creates all views of the document for the previous node.
        The content frames that are created are put into the respective layout. */
@@ -556,7 +554,7 @@ public:
 
     /** Method deletes all views of document for the node. The
      content frames are removed from the respective layout. */
-    void DelFrames();
+    void DelFrames(SwRootFrame const* pLayout = nullptr);
 
     /** Method creates all views of document for the previous node.
        The content frames created are put into the respective layout. */
diff --git a/sw/source/core/docnode/ndsect.cxx b/sw/source/core/docnode/ndsect.cxx
index 360722fd6f04..ec6ac343b797 100644
--- a/sw/source/core/docnode/ndsect.cxx
+++ b/sw/source/core/docnode/ndsect.cxx
@@ -1150,7 +1150,7 @@ void SwSectionNode::MakeOwnFrames(SwNodeIndex* pIdxBehind, SwNodeIndex* pEndIdx)
     }
 }
 
-void SwSectionNode::DelFrames()
+void SwSectionNode::DelFrames(SwRootFrame const*const /*FIXME TODO*/)
 {
     sal_uLong nStt = GetIndex()+1, nEnd = EndOfSectionIndex();
     if( nStt >= nEnd )
diff --git a/sw/source/core/docnode/ndtbl.cxx b/sw/source/core/docnode/ndtbl.cxx
index 2f2a135d0d39..d5b62a198d0a 100644
--- a/sw/source/core/docnode/ndtbl.cxx
+++ b/sw/source/core/docnode/ndtbl.cxx
@@ -2425,7 +2425,7 @@ void SwTableNode::MakeOwnFrames(SwNodeIndex* pIdxBehind)
     }
 }
 
-void SwTableNode::DelFrames()
+void SwTableNode::DelFrames(SwRootFrame const*const pLayout)
 {
     /* For a start, cut out and delete the TabFrames (which will also delete the Columns and Rows)
        The TabFrames are attached to the FrameFormat of the SwTable.
@@ -2437,7 +2437,7 @@ void SwTableNode::DelFrames()
     {
         bool bAgain = false;
         {
-            if ( !pFrame->IsFollow() )
+            if (!pFrame->IsFollow() && (!pLayout || pLayout == pFrame->getRootFrame()))
             {
                 while ( pFrame->HasFollow() )
                     pFrame->JoinAndDelFollows();
diff --git a/sw/source/core/docnode/node.cxx b/sw/source/core/docnode/node.cxx
index b3a5ecc27438..7812c94fdc43 100644
--- a/sw/source/core/docnode/node.cxx
+++ b/sw/source/core/docnode/node.cxx
@@ -1016,7 +1016,7 @@ SwContentNode::~SwContentNode()
     // Thus, we need to delete all Frames in the dependency list.
     if (!IsTextNode()) // see ~SwTextNode
     {
-        DelFrames(false);
+        DelFrames(nullptr);
     }
 
     m_aCondCollListener.EndListeningAll();
@@ -1310,7 +1310,7 @@ void SwContentNode::MakeFramesForAdjacentContentNode(SwContentNode& rNode)
  *
  * An input param to identify if the acc table should be disposed.
  */
-void SwContentNode::DelFrames(bool /*removeme*/)
+void SwContentNode::DelFrames(SwRootFrame const*const pLayout)
 {
     if( !HasWriterListeners() )
         return;
@@ -1318,6 +1318,10 @@ void SwContentNode::DelFrames(bool /*removeme*/)
     SwIterator<SwContentFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*this);
     for( SwContentFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
     {
+        if (pLayout && pLayout != pFrame->getRootFrame())
+        {
+            continue; // skip it
+        }
         if (pFrame->IsTextFrame())
         {
             if (sw::MergedPara const* pMerged =
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index e5580ac8b2da..cfe0d11b56c8 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -4229,15 +4229,15 @@ static void UnHideRedlines(SwRootFrame & rLayout,
                 if (rNode.IsContentNode())
                 {
                     // note: no-op for NonFirst nodes, only Hidden will delete
-                    static_cast<SwContentNode&>(rNode).DelFrames(); // FIXME only those in this layout?
+                    static_cast<SwContentNode&>(rNode).DelFrames(&rLayout);
                 }
                 else if (rNode.IsTableNode())
                 {
-                    static_cast<SwTableNode&>(rNode).DelFrames(); // FIXME only those in this layout?
+                    static_cast<SwTableNode&>(rNode).DelFrames(&rLayout);
                 }
                 else if (rNode.IsSectionNode())
                 {
-                    static_cast<SwSectionNode&>(rNode).DelFrames(); // FIXME only those in this layout?
+                    static_cast<SwSectionNode&>(rNode).DelFrames(&rLayout);
                 }
             }
             else
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index b9d7afb7da55..5bcb4d1b4350 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -149,7 +149,7 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode,
         // otherwise footnotes cannot be deleted by SwTextFootnote::DelFrames!
         for (auto iter = ++nodes.begin(); iter != nodes.end(); ++iter)
         {
-            (**iter).DelFrames(); // FIXME only those in this layout?
+            (**iter).DelFrames(rFrame.getRootFrame());
         }
     }
     auto pRet(o3tl::make_unique<sw::MergedPara>(rFrame, std::move(extents),
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index d2901a640e11..880ce8ea14a3 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -263,7 +263,7 @@ SwTextNode::~SwTextNode()
 
     InitSwParaStatistics( false );
 
-    DelFrames(false); // must be called here while it's still a SwTextNode
+    DelFrames(nullptr); // must be called here while it's still a SwTextNode
     DelFrames_TextNodePart();
 }
 
commit 6c5c3fc5db5ebc9ca2e98b6ab11ff6ad63529b80
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Jul 31 18:39:36 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: show/hide footnotes in redlines
    
    This requires some manual work to delete the footnote frames.
    
    Change-Id: I2c5efccdd1e97f26e18402b809ca4f893147cba1

diff --git a/sw/source/core/inc/ftnfrm.hxx b/sw/source/core/inc/ftnfrm.hxx
index 7f964d654d4d..c0848948848f 100644
--- a/sw/source/core/inc/ftnfrm.hxx
+++ b/sw/source/core/inc/ftnfrm.hxx
@@ -23,12 +23,22 @@
 #include "layfrm.hxx"
 
 class SwContentFrame;
+class SwTextFrame;
+class SwTextNode;
 class SwTextFootnote;
 class SwBorderAttrs;
 class SwFootnoteFrame;
 
 void sw_RemoveFootnotes( SwFootnoteBossFrame* pBoss, bool bPageOnly, bool bEndNotes );
 
+namespace sw {
+
+void RemoveFootnotesForNode(
+        SwTextFrame const& rTextFrame, SwTextNode const& rTextNode,
+        std::vector<std::pair<sal_Int32, sal_Int32>> const*const pExtents);
+
+}
+
 // There exists a special section on a page for footnotes. It's called
 // SwFootnoteContFrame. Each footnote is separated by a SwFootnoteFrame which contains
 // the paragraphs of a footnote. SwFootnoteFrame can be splitted and will then
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index d5a38e17a455..3b6860cb4691 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -93,7 +93,8 @@ struct MergedPara;
 std::pair<SwTextNode*, sal_Int32> MapViewToModel(MergedPara const&, TextFrameIndex nIndex);
 TextFrameIndex MapModelToView(MergedPara const&, SwTextNode const* pNode, sal_Int32 nIndex);
 
-std::unique_ptr<sw::MergedPara> CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode);
+enum class FrameMode { New, Existing };
+std::unique_ptr<sw::MergedPara> CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode, FrameMode eMode);
 
 bool FrameContainsNode(SwContentFrame const& rFrame, sal_uLong nNodeIndex);
 
diff --git a/sw/source/core/layout/ssfrm.cxx b/sw/source/core/layout/ssfrm.cxx
index b16643c3e767..d847bf6f21bd 100644
--- a/sw/source/core/layout/ssfrm.cxx
+++ b/sw/source/core/layout/ssfrm.cxx
@@ -443,7 +443,8 @@ SwContentFrame::~SwContentFrame()
 void SwTextFrame::RegisterToNode(SwTextNode & rNode)
 {
     assert(&rNode != GetDep());
-    m_pMergedPara = sw::CheckParaRedlineMerge(*this, rNode);
+    // sw_redlinehide: use New here, because the only caller also calls lcl_ChangeFootnoteRef
+    m_pMergedPara = sw::CheckParaRedlineMerge(*this, rNode, sw::FrameMode::New);
     if (!m_pMergedPara)
     {
         rNode.Add(this);
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index 365b8a099ac3..e5580ac8b2da 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -4194,14 +4194,27 @@ static void UnHideRedlines(SwRootFrame & rLayout,
                         rNode.GetRedlineMergeFlag() == SwNode::Merge::NonFirst);
                     if (rNode.IsCreateFrameWhenHidingRedlines())
                     {
-                        pFrame->SetMergedPara(CheckParaRedlineMerge(*pFrame, rTextNode));
+                        pFrame->SetMergedPara(CheckParaRedlineMerge(*pFrame,
+                                rTextNode, sw::FrameMode::Existing));
                         // ??? TODO flys etc.
                     }
                 }
                 else
                 {
-                    if (pFrame->GetMergedPara())
+                    if (auto const& pMergedPara = pFrame->GetMergedPara())
                     {
+                        // the new text frames don't exist yet, so at this point
+                        // we can only delete the footnote frames so they don't
+                        // point to the merged SwTextFrame any more...
+                        SwTextNode const* pNode(&rTextNode);
+                        for (auto const& rExtent : pMergedPara->extents)
+                        {
+                            if (rExtent.pNode != pNode)
+                            {
+                                sw::RemoveFootnotesForNode(*pFrame, *rExtent.pNode, nullptr);
+                                pNode = rExtent.pNode;
+                            }
+                        }
                         pFrame->SetMergedPara(nullptr);
                         // ??? TODO flys etc.
                         // ??? TODO recreate? or is invalidate enough?
@@ -4215,6 +4228,7 @@ static void UnHideRedlines(SwRootFrame & rLayout,
             {
                 if (rNode.IsContentNode())
                 {
+                    // note: no-op for NonFirst nodes, only Hidden will delete
                     static_cast<SwContentNode&>(rNode).DelFrames(); // FIXME only those in this layout?
                 }
                 else if (rNode.IsTableNode())
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index aba968a8740f..b9d7afb7da55 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -36,6 +36,7 @@
 #include <vcl/commandevent.hxx>
 #include <vcl/settings.hxx>
 #include <txtfrm.hxx>
+#include <ftnfrm.hxx>
 #include <vcl/svapp.hxx>
 #include "redlnitr.hxx"
 #include <extinput.hxx>
@@ -47,7 +48,8 @@ using namespace ::com::sun::star;
 namespace sw {
 
 std::unique_ptr<sw::MergedPara>
-CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode)
+CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode,
+       FrameMode const eMode)
 {
     IDocumentRedlineAccess const& rIDRA = rTextNode.getIDocumentRedlineAccess();
     if (!rFrame.getRootFrame()->IsHideRedlines())
@@ -117,6 +119,39 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode)
         assert(!mergedText.isEmpty());
         pParaPropsNode = extents.begin()->pNode; // para props from first node that isn't empty
     }
+    if (eMode == FrameMode::Existing)
+    {
+        // remove existing footnote frames for first node;
+        // for non-first notes, DelFrames will remove all
+        // (could possibly call lcl_ChangeFootnoteRef, not sure if worth it)
+        // note: must be done *before* changing listeners!
+        sal_Int32 nLast(0);
+        std::vector<std::pair<sal_Int32, sal_Int32>> hidden;
+        for (auto const& rExtent : extents)
+        {
+            if (rExtent.pNode != &rTextNode)
+            {
+                break;
+            }
+            if (rExtent.nStart != 0)
+            {
+                assert(rExtent.nStart != nLast);
+                hidden.emplace_back(nLast, rExtent.nStart);
+            }
+            nLast = rExtent.nEnd;
+        }
+        if (nLast != rTextNode.Len())
+        {
+            hidden.emplace_back(nLast, rTextNode.Len());
+        }
+        sw::RemoveFootnotesForNode(rFrame, rTextNode, &hidden);
+        // unfortunately DelFrames() must be done before StartListening too,
+        // otherwise footnotes cannot be deleted by SwTextFootnote::DelFrames!
+        for (auto iter = ++nodes.begin(); iter != nodes.end(); ++iter)
+        {
+            (**iter).DelFrames(); // FIXME only those in this layout?
+        }
+    }
     auto pRet(o3tl::make_unique<sw::MergedPara>(rFrame, std::move(extents),
                 mergedText.makeStringAndClear(), pParaPropsNode, &rTextNode));
     for (SwTextNode * pTmp : nodes)
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index d5913ba9b3b4..a548c55ed2cc 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -612,7 +612,7 @@ SwTextFrame::SwTextFrame(SwTextNode * const pNode, SwFrame* pSib )
     , mnHeightOfLastLine( 0 )
     , mnAdditionalFirstLineOffset( 0 )
     // note: this may change this->pRegisteredIn to m_pMergedPara->listeners
-    , m_pMergedPara(CheckParaRedlineMerge(*this, *pNode)) // ensure it is inited
+    , m_pMergedPara(CheckParaRedlineMerge(*this, *pNode, sw::FrameMode::New)) // ensure it is inited
     , mnOffset( 0 )
     , mnCacheIndex( USHRT_MAX )
     , mbLocked( false )
@@ -631,9 +631,16 @@ SwTextFrame::SwTextFrame(SwTextNode * const pNode, SwFrame* pSib )
     mnFrameType = SwFrameType::Txt;
 }
 
-static void RemoveFootnotesForNode(
-        SwTextFrame const& rTextFrame, SwTextNode const& rTextNode)
+namespace sw {
+
+void RemoveFootnotesForNode(
+        SwTextFrame const& rTextFrame, SwTextNode const& rTextNode,
+        std::vector<std::pair<sal_Int32, sal_Int32>> const*const pExtents)
 {
+    if (pExtents && pExtents->empty())
+    {
+        return; // nothing to do
+    }
     const SwFootnoteIdxs &rFootnoteIdxs = rTextNode.GetDoc()->GetFootnoteIdxs();
     size_t nPos = 0;
     sal_uLong const nIndex = rTextNode.GetIndex();
@@ -645,16 +652,33 @@ static void RemoveFootnotesForNode(
         if (nPos || &rTextNode != &(rFootnoteIdxs[ nPos ]->GetTextNode()))
             ++nPos;
     }
-    while (nPos < rFootnoteIdxs.size())
+    size_t iter(0);
+    for ( ; nPos < rFootnoteIdxs.size(); ++nPos)
     {
         SwTextFootnote* pTextFootnote = rFootnoteIdxs[ nPos ];
         if (pTextFootnote->GetTextNode().GetIndex() > nIndex)
             break;
+        if (pExtents)
+        {
+            while ((*pExtents)[iter].second <= pTextFootnote->GetStart())
+            {
+                ++iter;
+                if (iter == pExtents->size())
+                {
+                    return;
+                }
+            }
+            if (pTextFootnote->GetStart() < (*pExtents)[iter].first)
+            {
+                continue;
+            }
+        }
         pTextFootnote->DelFrames( &rTextFrame );
-        ++nPos;
     }
 }
 
+} // namespace sw
+
 void SwTextFrame::DestroyImpl()
 {
     // Remove associated SwParaPortion from s_pTextCache
@@ -674,7 +698,7 @@ void SwTextFrame::DestroyImpl()
                     // sw_redlinehide: not sure if it's necessary to check
                     // if the nodes are still alive here, which would require
                     // accessing WriterMultiListener::m_vDepends
-                    RemoveFootnotesForNode(*this, *pNode);
+                    sw::RemoveFootnotesForNode(*this, *pNode, nullptr);
                 }
             }
         }
@@ -683,7 +707,7 @@ void SwTextFrame::DestroyImpl()
             SwTextNode *const pNode(static_cast<SwTextNode*>(GetDep()));
             if (pNode)
             {
-                RemoveFootnotesForNode(*this, *pNode);
+                sw::RemoveFootnotesForNode(*this, *pNode, nullptr);
             }
         }
     }
commit ac275cb0ec4108b4a3f043ae0166c960e49fee2b
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Jul 31 17:51:54 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: invalid position from SwTextCursor::GetCursorOfst()
    
    The problem here is that nCurrStart is incremented, but then the early
    return isn't taken, so a position of nCurrStart + nLength is returned,
    and if the portion is the last in the line it will be beyond the end
    of the paragraph.
    
    (regression from CWS smarttags3)
    
    Change-Id: I58a0591202bd664a89c395ea06098eb939a7ed93

diff --git a/sw/source/core/text/itrcrsr.cxx b/sw/source/core/text/itrcrsr.cxx
index 4103b8505b77..ea544492a358 100644
--- a/sw/source/core/text/itrcrsr.cxx
+++ b/sw/source/core/text/itrcrsr.cxx
@@ -1477,8 +1477,10 @@ TextFrameIndex SwTextCursor::GetCursorOfst( SwPosition *pPos, const Point &rPoin
     {
         if ( nWidth )
         {
-            // Else we may not enter the character-supplying frame...
-            if( !( bChgNode && pPos && pPor->IsFlyCntPortion() ) )
+            // no quick return for as-character frames, we want to peek inside
+            if (!(bChgNode && pPos && pPor->IsFlyCntPortion())
+            // if we want to get the position inside the field, we should not return
+                && (!pCMS || !pCMS->m_pSpecialPos))
             {
                 if ( pPor->InFieldGrp() ||
                      ( pPor->IsMultiPortion() &&
@@ -1507,9 +1509,7 @@ TextFrameIndex SwTextCursor::GetCursorOfst( SwPosition *pPos, const Point &rPoin
                          && ( bRightAllowed || !bLastHyph ))
                     ++nCurrStart;
 
-                // if we want to get the position inside the field, we should not return
-                if ( !pCMS || !pCMS->m_pSpecialPos )
-                    return nCurrStart;
+                return nCurrStart;
             }
         }
         else
commit d96ab97a1b2eb4d558f7d240e77edec162b25eb0
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Jul 31 15:20:00 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: fix use-after-free of SwFont
    
    SwTextSizeInfo::m_pFnt may be an alias of either SwAttrIter or
    SwAttrHandler's SwFont members; keep these alive if they exist when
    re-initialising from SwAttrIter::Seek().
    
    Change-Id: I8fcbcf3aa339dfc6fa33b5439facadc6034c8cf5

diff --git a/sw/source/core/text/atrstck.cxx b/sw/source/core/text/atrstck.cxx
index 345400cede4f..ecae4e4a8385 100644
--- a/sw/source/core/text/atrstck.cxx
+++ b/sw/source/core/text/atrstck.cxx
@@ -401,8 +401,17 @@ void SwAttrHandler::Init( const SfxPoolItem** pPoolItem, const SwAttrSet* pAS,
     }
 
     // It is possible, that Init is called more than once, e.g., in a
-    // SwTextFrame::FormatOnceMore situation.
-    m_pFnt.reset( new SwFont(rFnt) );
+    // SwTextFrame::FormatOnceMore situation or (since sw_redlinehide)
+    // from SwAttrIter::Seek(); in the latter case SwTextSizeInfo::m_pFnt
+    // is an alias of m_pFnt so it must not be deleted!
+    if (m_pFnt)
+    {
+        *m_pFnt = rFnt;
+    }
+    else
+    {
+        m_pFnt.reset(new SwFont(rFnt));
+    }
 }
 
 void SwAttrHandler::Reset( )
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index 0d2a39f5fdad..aba968a8740f 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -135,8 +135,18 @@ void SwAttrIter::InitFontAndAttrHandler(SwTextNode const& rTextNode,
 {
     // Build a font matching the default paragraph style:
     SwFontAccess aFontAccess( &rTextNode.GetAnyFormatColl(), m_pViewShell );
-    delete m_pFont;
-    m_pFont = new SwFont( aFontAccess.Get()->GetFont() );
+    // It is possible that Init is called more than once, e.g., in a
+    // SwTextFrame::FormatOnceMore situation or (since sw_redlinehide)
+    // from SwAttrIter::Seek(); in the latter case SwTextSizeInfo::m_pFnt
+    // is an alias of m_pFont so it must not be deleted!
+    if (m_pFont)
+    {
+        *m_pFont = aFontAccess.Get()->GetFont();
+    }
+    else
+    {
+        m_pFont = new SwFont( aFontAccess.Get()->GetFont() );
+    }
 
     // set font to vertical if frame layout is vertical
     // if it's a re-init, the vert flag never changes
commit a5838a428d240965e348232b87e94a4fe064a25b
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Jul 31 15:17:14 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: fix crash in SwAttrIter::Seek()
    
    There aren't necessarily hints in every merged node.
    
    Change-Id: Id83319d8846602b65d9d25b850a8254daf8c54ff

diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index bdc4d88b9f13..0eeeff080669 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -308,20 +308,23 @@ bool SwAttrIter::Seek(TextFrameIndex const nNewPos)
     {
         // Skipping to a different node - first seek until the end of this node
         // to get rid of all hint items
-        sal_Int32 nPos(m_nPosition);
-        do
+        if (m_pTextNode->GetpSwpHints())
         {
-            nPos = GetNextAttrImpl(m_pTextNode, m_nStartIndex, m_nEndIndex, nPos);
-            if (nPos <= m_pTextNode->Len())
-            {
-                SeekFwd(nPos);
-            }
-            else
+            sal_Int32 nPos(m_nPosition);
+            do
             {
-                SeekFwd(m_pTextNode->Len());
+                nPos = GetNextAttrImpl(m_pTextNode, m_nStartIndex, m_nEndIndex, nPos);
+                if (nPos <= m_pTextNode->Len())
+                {
+                    SeekFwd(nPos);
+                }
+                else
+                {
+                    SeekFwd(m_pTextNode->Len());
+                }
             }
+            while (nPos < m_pTextNode->Len());
         }
-        while (nPos < m_pTextNode->Len());
         assert(m_nChgCnt == 0); // should have reset it all? there cannot be ExtOn() inside of a Delete redline, surely?
         // Unapply current para items:
         // the SwAttrHandler doesn't appear to be capable of *unapplying*
commit c907f741fbc1a235badd59e8009032dba7d6cc8c
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Tue Jul 31 15:14:23 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: incorrect node returned by MergedAttrIterMulti
    
    Change-Id: I0aa83b5902b2e0e4d0c5371cdbf6ce6dccbf6e74

diff --git a/sw/source/core/text/pormulti.cxx b/sw/source/core/text/pormulti.cxx
index 13b7207b71d9..80982dd5dcc6 100644
--- a/sw/source/core/text/pormulti.cxx
+++ b/sw/source/core/text/pormulti.cxx
@@ -875,7 +875,7 @@ namespace sw {
                     rExtent.pNode != m_pMerged->extents[m_CurrentExtent].pNode)
                 {
                     m_CurrentHint = 0; // reset
-                    rpNode = rExtent.pNode;
+                    rpNode = m_pMerged->extents[m_CurrentExtent].pNode;
                     return nullptr;
                 }
             }
commit 0a9017b4acf800559a61c0476c7f527f2e7221c3
Author:     Michael Stahl <Michael.Stahl at cib.de>
AuthorDate: Fri Jul 27 18:25:59 2018 +0200
Commit:     Michael Stahl <Michael.Stahl at cib.de>
CommitDate: Fri Aug 10 18:22:36 2018 +0200

    sw_redlinehide_2: improve SwRootFrame::SetHideRedlines()
    
    Change-Id: If54585d20bbe0fbf5c071e3a96737015d7d62c05

diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index cdce7870a536..365b8a099ac3 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -30,6 +30,7 @@
 #include <viewopt.hxx>
 #include <IDocumentSettingAccess.hxx>
 #include <IDocumentFieldsAccess.hxx>
+#include <IDocumentRedlineAccess.hxx>
 #include <fesh.hxx>
 #include <docsh.hxx>
 #include <ftninfo.hxx>
@@ -4164,37 +4165,22 @@ void SwRootFrame::InvalidateAllObjPos()
     }
 }
 
-void SwRootFrame::SetHideRedlines(bool const bHideRedlines)
+static void UnHideRedlines(SwRootFrame & rLayout,
+        SwNodes & rNodes, SwNode const& rEndOfSectionNode)
 {
-    if (bHideRedlines == mbHideRedlines)
-    {
-        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)
+    assert(rEndOfSectionNode.IsEndNode());
+    for (sal_uLong i = rEndOfSectionNode.StartOfSectionNode()->GetIndex() + 1;
+         i < rEndOfSectionNode.GetIndex(); ++i)
     {
-        SwNode *const pNode(rNodes[i]);
-        if (pNode->IsTextNode())
+        SwNode & rNode(*rNodes[i]);
+        if (rNode.IsTextNode()) // only text nodes are 1st node of a merge
         {
-            SwTextNode & rTextNode(*pNode->GetTextNode());
+            SwTextNode & rTextNode(*rNode.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)
+                if (pFrame->getRootFrame() == &rLayout)
                 {
                     frames.push_back(pFrame);
                 }
@@ -4202,21 +4188,142 @@ void SwRootFrame::SetHideRedlines(bool const bHideRedlines)
             // this messes with pRegisteredIn so do it outside SwIterator
             for (SwTextFrame * pFrame : frames)
             {
-                if (mbHideRedlines && pNode->IsCreateFrameWhenHidingRedlines())
+                if (rLayout.IsHideRedlines())
                 {
-                    pFrame->SetMergedPara(CheckParaRedlineMerge(*pFrame, rTextNode));
+                    assert(!pFrame->GetMergedPara() ||
+                        rNode.GetRedlineMergeFlag() == SwNode::Merge::NonFirst);
+                    if (rNode.IsCreateFrameWhenHidingRedlines())
+                    {
+                        pFrame->SetMergedPara(CheckParaRedlineMerge(*pFrame, rTextNode));
+                        // ??? TODO flys etc.
+                    }
                 }
                 else
                 {
                     if (pFrame->GetMergedPara())
                     {
                         pFrame->SetMergedPara(nullptr);
-                        rTextNode.DelFrames(); // FIXME only those in this layout?
+                        // ??? TODO flys etc.
+                        // ??? TODO recreate? or is invalidate enough?
+                    }
+                }
+            }
+        }
+        if (!rNode.IsCreateFrameWhenHidingRedlines())
+        {
+            if (rLayout.IsHideRedlines())
+            {
+                if (rNode.IsContentNode())
+                {
+                    static_cast<SwContentNode&>(rNode).DelFrames(); // FIXME only those in this layout?
+                }
+                else if (rNode.IsTableNode())
+                {
+                    static_cast<SwTableNode&>(rNode).DelFrames(); // FIXME only those in this layout?
+                }
+                else if (rNode.IsSectionNode())
+                {
+                    static_cast<SwSectionNode&>(rNode).DelFrames(); // FIXME only those in this layout?
+                }
+            }
+            else
+            {
+                sal_uLong j = i + 1;
+                for ( ; j < rEndOfSectionNode.GetIndex(); ++j)
+                {
+                    if (rNodes[j]->IsCreateFrameWhenHidingRedlines())
+                    {
+                        break;
                     }
                 }
+                // call MakeFrames once, because sections/tables
+                // InsertCnt_ also checks for hidden sections
+                SwNodeIndex const start(rNodes, i);
+                SwNodeIndex const end(rNodes, j);
+                ::MakeFrames(rLayout.GetFormat()->GetDoc(), start, end);
+                i = j - 1; // will be incremented again
+            }
+        }
+    }
+}
+
+static void UnHideRedlinesExtras(SwRootFrame & rLayout,
+        SwNodes & rNodes, SwNode const& rEndOfExtraSectionNode)
+{
+    assert(rEndOfExtraSectionNode.IsEndNode());
+    for (sal_uLong i = rEndOfExtraSectionNode.StartOfSectionNode()->GetIndex()
+            + 1; i < rEndOfExtraSectionNode.GetIndex(); ++i)
+    {
+        SwNode const& rStartNode(*rNodes[i]);
+        assert(rStartNode.IsStartNode());
+        assert(rStartNode.GetRedlineMergeFlag() == SwNode::Merge::None);
+        SwNode const& rEndNode(*rStartNode.EndOfSectionNode());
+        i = rEndNode.GetIndex();
+        bool bSkip(false);
+        for (sal_uLong j = rStartNode.GetIndex() + 1; j < i; ++j)
+        {
+            // note: SwStartNode has no way to access the frames, so check
+            // whether the first content-node inside the section has frames
+            SwNode const& rNode(*rNodes[j]);
+            if (rNode.IsSectionNode() &&
+                static_cast<SwSectionNode const&>(rNode).GetSection().IsHiddenFlag())
+            {   // skip hidden sections - they can be inserted in fly-frames :(
+                j = rNode.EndOfSectionNode()->GetIndex();
+                continue;
+            }
+            if (rNode.IsContentNode())
+            {
+                SwContentNode const& rCNode(static_cast<SwContentNode const&>(rNode));
+                if (!rCNode.getLayoutFrame(&rLayout))
+                {   // ignore footnote/fly/header/footer with no layout frame
+                    bSkip = true; // they will be created from scratch later if needed
+                }
+                break;
             }
         }
+        if (!bSkip)
+        {
+            UnHideRedlines(rLayout, rNodes, rEndNode);
+        }
+    }
+}
+
+void SwRootFrame::SetHideRedlines(bool const bHideRedlines)
+{
+    if (bHideRedlines == mbHideRedlines)
+    {
+        return;
     }
+    mbHideRedlines = bHideRedlines;
+    SwDoc & rDoc(*GetFormat()->GetDoc());
+    if (rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())
+    {
+        return;
+    }
+    // Hide->Show: clear MergedPara, create frames

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list