[Libreoffice-commits] core.git: Branch 'private/mst/sw_redlinehide_2' - 757 commits - android/source basctl/source basegfx/source basegfx/test basic/source bin/fuzzfiles bin/gen-boost-headers bin/get_config_variables bin/list-uitest.py bridges/source canvas/source chart2/CppunitTest_chart2_export.mk chart2/IwyuFilter_chart2.yaml chart2/qa chart2/source codemaker/source comphelper/source compilerplugins/clang config_host/config_cxxabi.h.in config_host/config_dbus.h.in config_host.mk.in configure.ac connectivity/source cppcanvas/source cppuhelper/CppunitTest_cppuhelper_qa_misc.mk cppuhelper/Module_cppuhelper.mk cppuhelper/qa cppuhelper/source cppu/source cui/source cui/uiconfig dbaccess/source desktop/source dictionaries distro-configs/Jenkins download.lst drawinglayer/source dtrans/source editeng/inc editeng/source embeddedobj/source embedserv/source emfio/source extensions/source external/boost external/cppunit external/gpgmepp external/harfbuzz external/icu external/libexttextcat external/liborc us external/libwps external/mdds external/nss external/pdfium external/xmlsec extras/source filter/qa filter/source forms/source formula/source fpicker/source framework/inc framework/source helpcompiler/inc helpcompiler/source helpcontent2 hwpfilter/source i18nlangtag/qa i18nlangtag/source i18npool/source icon-themes/karasa_jaga idlc/source idl/inc idl/source include/basegfx include/basic include/canvas include/comphelper include/connectivity include/cppcanvas include/cppuhelper include/drawinglayer include/editeng include/filter include/formula include/i18nlangtag include/IwyuFilter_include.yaml include/LibreOfficeKit include/o3tl include/oox include/osl include/rtl include/salhelper include/sfx2 include/svl include/svtools include/svx include/toolkit include/tools include/ucbhelper include/unotools include/vcl include/xmloff include/xmlreader include/xmlscript instsetoo_native/inc_openoffice io/source javaunohelper/source jurt/source jvmfwk/inc jvmfwk/plugins jvmfwk/source l10ntoo ls/inc l10ntools/source lingucomponent/source linguistic/source lotuswordpro/inc lotuswordpro/source Makefile.in odk/examples offapi/com officecfg/registry oox/inc oox/Library_oox.mk oox/source oox/util opencl/source package/inc package/Library_package2.mk package/source postprocess/CustomTarget_registry.mk pyuno/source qadevOOo/runner qadevOOo/tests readlicense_oo/license registry/source registry/tools reportdesign/inc reportdesign/source RepositoryExternal.mk sal/cppunittester salhelper/source sal/inc sal/Library_sal.mk sal/osl sal/qa sal/rtl sal/test sax/source sax/test sc/CppunitTest_sc_annotationobj.mk sc/CppunitTest_sc_annotationshapeobj.mk sc/CppunitTest_sc_annotationsobj.mk sc/CppunitTest_sc_arealinkobj.mk sc/CppunitTest_sc_arealinksobj.mk sc/CppunitTest_sc_autoformatobj.mk sc/CppunitTest_sc_check_data_pilot_field.mk sc/CppunitTest_sc_check_data_pilot_table.mk sc/CppunitTest_sc_check_xcell_ranges_query.mk sc/CppunitTest_sc_consolidationdescriptorobj.mk sc/CppunitTest_sc_data baserangeobj.mk sc/CppunitTest_sc_databaserangesobj.mk sc/CppunitTest_sc_datapilotfieldobj.mk sc/CppunitTest_sc_datapilottableobj.mk sc/CppunitTest_sc_documentconfigurationobj.mk sc/CppunitTest_sc_editfieldobj_cell.mk sc/CppunitTest_sc_editfieldobj_header.mk sc/CppunitTest_sc_filterdescriptorbaseobj.mk sc/CppunitTest_sc_filters_test.mk sc/CppunitTest_sc_functionlistobj.mk sc/CppunitTest_sc_headerfootercontentobj.mk sc/CppunitTest_sc_importdescriptorbaseobj.mk sc/CppunitTest_sc_labelrangeobj.mk sc/CppunitTest_sc_labelrangesobj.mk sc/CppunitTest_sc_namedrangesobj.mk sc/CppunitTest_sc_subsequent_filters_test.mk schema/mathml2 sc/inc sc/IwyuFilter_sc.yaml sc/Module_sc.mk sc/qa scripting/source sc/source sc/uiconfig sc/UITest_calc_tests6.mk sc/UITest_conditional_format.mk sdext/source sd/Library_sd.mk sd/Module_sd.mk sd/qa sd/source sd/uiconfig sd/UIConfig_sdraw.mk sd/UITest_impress_tests.mk sfx2/classification sfx2/inc sfx2/qa sfx2/source sfx2/uiconfig shell/source slideshow/source slid eshow/test solenv/bin solenv/clang-format solenv/CompilerTest_compilerplugins_clang.mk solenv/flatpak-manifest.in solenv/gbuild soltools/cpp soltools/mkdepend sot/source starmath/inc starmath/source stoc/source stoc/test svgio/inc svgio/source svl/qa svl/source svtools/langsupport svtools/source svx/inc svx/source svx/uiconfig svx/workben sw/inc sw/qa sw/source sw/uiconfig sysui/desktop test/source toolkit/inc toolkit/source tools/source translations ucbhelper/source ucb/source uitest/demo_ui UnoControls/source unodevtools/source unoidl/source unotest/source unotools/source unoxml/qa unoxml/source uui/source vbahelper/source vcl/backendtest vcl/Executable_docxfuzzer.mk vcl/Executable_fodpfuzzer.mk vcl/Executable_fodsfuzzer.mk vcl/Executable_fodtfuzzer.mk vcl/Executable_htmlfuzzer.mk vcl/Executable_pptxfuzzer.mk vcl/Executable_scrtffuzzer.mk vcl/Executable_wksfuzzer.mk vcl/Executable_xlsfuzzer.mk vcl/Executable_xlsxfuzzer.mk vcl/headless vcl/inc vcl/opengl vcl/osx vcl/qa vcl/qt5 vcl/ quartz vcl/source vcl/unx vcl/win vcl/workben wizards/source writerfilter/inc writerfilter/source xmlhelp/source xmloff/source xmlreader/source xmlscript/source xmlsecurity/source

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Mon Aug 13 09:10:20 UTC 2018


Rebased ref, commits from common ancestor:
commit 347be3d80037b37d2c7cc162818971632bcd3f0c
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: Sun Aug 12 20:21:15 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 66ae7e2149b4c57c4a6454c5b053d24be19a08a5
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: Sun Aug 12 20:21:15 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 2995b6594686f0916cf1cb2c9ca6d8818201ea1c
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: Sun Aug 12 20:21:15 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 32323c96777981d1027c7b4b480792529c82dccb
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: Sun Aug 12 20:21:15 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 6cf9ff63be1c9e7909a156faaa545fa51bca3576
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: Sun Aug 12 20:21:15 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 68a8c29ea888..7703c1175094 100644
--- a/sw/source/core/doc/CntntIdxStore.cxx
+++ b/sw/source/core/doc/CntntIdxStore.cxx
@@ -152,26 +152,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 bb419904ef95..2f997aea27ec 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -1992,12 +1992,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();
@@ -2938,12 +2938,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 36b6defb5805..323c5a247ab6 100644
--- a/sw/source/core/docnode/ndtbl.cxx
+++ b/sw/source/core/docnode/ndtbl.cxx
@@ -1070,12 +1070,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 abe62e8b3968..b00851d7dd52 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 a082a7eac14a..5bfb81123ced 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -366,7 +366,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();
 
@@ -479,7 +479,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);
@@ -526,6 +526,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
     {
@@ -583,7 +587,7 @@ SwTextNode *SwTextNode::SplitContentNode(const SwPosition & rPos,
 
         if (pContentIndexRestore)
         {   // call before making frames
-            (*pContentIndexRestore)(pNode);
+            (*pContentIndexRestore)(pNode, sw::mark::RestoreMode::NonFlys);
         }
 
         if ( HasWriterListeners() )
@@ -591,6 +595,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 e2577b6c31cc7d86e671698d87603f14c62c7607
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: Sun Aug 12 20:21:15 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 ab54c413f1a4..0e3d5aeb4692 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 788cb61dd7df..bb419904ef95 100644
--- a/sw/source/core/doc/DocumentContentOperationsManager.cxx
+++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx
@@ -1992,7 +1992,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
@@ -2012,9 +2020,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 )
         {
@@ -2932,15 +2937,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 bb2d470ec533..36b6defb5805 100644
--- a/sw/source/core/docnode/ndtbl.cxx
+++ b/sw/source/core/docnode/ndtbl.cxx
@@ -1070,10 +1070,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 e5bf6c36502d..a082a7eac14a 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -365,7 +365,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();
 
@@ -476,6 +477,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())
         {
@@ -575,6 +581,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 4d58ec1b7355be5fa71a38e2f827315fe1690467
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: Sun Aug 12 20:21:15 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 efe04fe60bc1..3a33d6994fe1 100644
--- a/sw/source/core/draw/dcontact.cxx
+++ b/sw/source/core/draw/dcontact.cxx
@@ -1838,11 +1838,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 16a015377fc4..ab1721c70d05 100644
--- a/sw/source/core/layout/atrfrm.cxx
+++ b/sw/source/core/layout/atrfrm.cxx
@@ -57,6 +57,7 @@
 #include <rootfrm.hxx>
 #include <cntfrm.hxx>
 #include <notxtfrm.hxx>
+#include <txtfrm.hxx>
 #include <crsrsh.hxx>
 #include <dflyobj.hxx>
 #include <dcontact.hxx>
@@ -2999,7 +3000,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 aa5b18415073..697b96f718ff 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -1193,6 +1193,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 c9e2feb2f3b9a6e342e48d2707a10efd797bca4a
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: Sun Aug 12 20:21:15 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 870478f361ad48e7cb091aced7ccd975ed74a0da
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: Sun Aug 12 20:21:15 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 6a7218bfe886..aa5b18415073 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -1044,7 +1044,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 30484997ecd8991be6e8676dcfdf033dba09d51e
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: Sun Aug 12 20:21:15 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 ed003618424e..b82f23e56198 100644
--- a/sw/source/core/layout/ftnfrm.cxx
+++ b/sw/source/core/layout/ftnfrm.cxx
@@ -1642,12 +1642,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();
@@ -1664,6 +1667,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 344853a5c6e62e032def7adb83125d0e0dd3285b
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: Sun Aug 12 20:21:15 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 42a8577d86b3c0f6d217e1de833c0a9cee4d44b2
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: Sun Aug 12 20:21:15 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 7a0d11e4a5c6..6a7218bfe886 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -1040,32 +1040,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 603c95d0591e995ee0856d03d6b0f1b9852cea96
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: Sun Aug 12 20:21:15 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 e9ea70cc549c..ab54c413f1a4 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. */
@@ -513,7 +511,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. */
@@ -561,7 +559,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 fbe5b6eb5ba5..4b38cdf56004 100644
--- a/sw/source/core/docnode/ndsect.cxx
+++ b/sw/source/core/docnode/ndsect.cxx
@@ -1151,7 +1151,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 a8085fa7dff1..bb2d470ec533 100644
--- a/sw/source/core/docnode/ndtbl.cxx
+++ b/sw/source/core/docnode/ndtbl.cxx
@@ -2423,7 +2423,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.
@@ -2435,7 +2435,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 f3270f704db9..ed457c195156 100644
--- a/sw/source/core/docnode/node.cxx
+++ b/sw/source/core/docnode/node.cxx
@@ -1023,7 +1023,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();
@@ -1317,7 +1317,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;
@@ -1325,6 +1325,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 4debdb4d3b9a..e5bf6c36502d 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -264,7 +264,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 7200b3a11859fd3110bb3d61517cc979e4743c5e
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: Sun Aug 12 20:21:15 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 bbd0c447d36e..965b4f911647 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -97,7 +97,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 a5c4355fed1b..abe62e8b3968 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 cd8cd2b188f7ad6122a94428ae7e1416f1c302ac
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: Sun Aug 12 20:21:15 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 66833905ec17055a10ed2d1446b8e8945a0e9b42
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: Sun Aug 12 20:21:15 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 dec7522fc5f3348bed8c59b3e6f22ccf19873a3b
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: Sun Aug 12 20:21:15 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 efc2c5969f8bb31ab75646f8e18aed0c05318071
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: Sun Aug 12 20:21:15 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 78423e440a6f..5efb04aee21b 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 194ed9bd1f95c4d2a1417e9ab35050bbb470ba75
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: Sun Aug 12 20:21:15 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