sw/qa/core/data/ww6/pass/ofz41398-1.doc |binary
 sw/source/filter/ww8/ww8par.cxx         |   39 +++++++++++++++++++++++++++++++-
 sw/source/filter/ww8/ww8par.hxx         |   32 ++++++++++++++++----------
 sw/source/filter/ww8/ww8par6.cxx        |    2 -
 4 files changed, 59 insertions(+), 14 deletions(-)

New commits:
commit 7d3aadce8d184f72e4785827ad706d27c31a2edb
Author:     Caolán McNamara <caol...@redhat.com>
AuthorDate: Fri Nov 26 12:40:37 2021 +0000
Commit:     Caolán McNamara <caol...@redhat.com>
CommitDate: Fri Nov 26 20:21:20 2021 +0100

    ofz#41398 drop a para scheduled for deletion if something else deletes it
    
    Change-Id: I0b7d7f5224b78658951c7d0b71eb793057059bca
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/125886
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caol...@redhat.com>

diff --git a/sw/qa/core/data/ww6/pass/ofz41398-1.doc 
b/sw/qa/core/data/ww6/pass/ofz41398-1.doc
new file mode 100644
index 000000000000..34c6e357d82a
Binary files /dev/null and b/sw/qa/core/data/ww6/pass/ofz41398-1.doc differ
diff --git a/sw/source/filter/ww8/ww8par.cxx b/sw/source/filter/ww8/ww8par.cxx
index 818e3b013549..181bc2ce0a62 100644
--- a/sw/source/filter/ww8/ww8par.cxx
+++ b/sw/source/filter/ww8/ww8par.cxx
@@ -4692,7 +4692,10 @@ void wwExtraneousParas::delete_all_from_doc()
     auto aEnd = m_aTextNodes.rend();
     for (auto aI = m_aTextNodes.rbegin(); aI != aEnd; ++aI)
     {
-        SwTextNode *pTextNode = *aI;
+        const TextNodeListener& rListener = *aI;
+        SwTextNode *pTextNode = rListener.m_pTextNode;
+        pTextNode->Remove(const_cast<TextNodeListener*>(&rListener));
+
         SwNodeIndex aIdx(*pTextNode);
         SwPaM aTest(aIdx);
         m_rDoc.getIDocumentContentOperations().DelFullPara(aTest);
@@ -4700,6 +4703,40 @@ void wwExtraneousParas::delete_all_from_doc()
     m_aTextNodes.clear();
 }
 
+void wwExtraneousParas::insert(SwTextNode *pTextNode)
+{
+    auto it = m_aTextNodes.emplace(pTextNode, this).first;
+    const TextNodeListener& rListener = *it;
+    pTextNode->Add(const_cast<TextNodeListener*>(&rListener));
+}
+
+void wwExtraneousParas::remove_if_present(SwTextNode *pTextNode)
+{
+    auto it = std::find_if(m_aTextNodes.begin(), m_aTextNodes.end(),
+        [pTextNode](const wwExtraneousParas::TextNodeListener& rEntry) { 
return rEntry.m_pTextNode == pTextNode; });
+    if (it == m_aTextNodes.end())
+        return;
+    SAL_WARN("sw.ww8", "It is unexpected to drop a para scheduled for 
removal");
+    const TextNodeListener& rListener = *it;
+    pTextNode->Remove(const_cast<TextNodeListener*>(&rListener));
+    m_aTextNodes.erase(it);
+}
+
+void wwExtraneousParas::TextNodeListener::SwClientNotify(const SwModify& 
rModify, const SfxHint& rHint)
+{
+    if (rHint.GetId() != SfxHintId::SwLegacyModify)
+        return;
+    auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
+    // ofz#41398 drop a para scheduled for deletion if something else deletes 
it
+    // before wwExtraneousParas gets its chance to do so. Not the usual 
scenario,
+    // indicates an underlying bug.
+    if (pLegacy->GetWhich() == RES_OBJECTDYING)
+    {
+        const SwTextNode& rNode(static_cast<SwTextNode const&>(rModify));
+        m_pOwner->remove_if_present(const_cast<SwTextNode*>(&rNode));
+    }
+}
+
 void SwWW8ImplReader::StoreMacroCmds()
 {
     if (!m_xWwFib->m_lcbCmds)
diff --git a/sw/source/filter/ww8/ww8par.hxx b/sw/source/filter/ww8/ww8par.hxx
index 63d0e1baa1b1..4126763a5512 100644
--- a/sw/source/filter/ww8/ww8par.hxx
+++ b/sw/source/filter/ww8/ww8par.hxx
@@ -909,30 +909,38 @@ public:
 //Safest thing is to not delete SwTextNodes from a document during import, and
 //remove these extraneous paragraphs at the end after all SwFltControlStack are
 //destroyed.
-class wwExtraneousParas
+class wwExtraneousParas : public SwClient
 {
 private:
+    struct TextNodeListener : public SwClient
+    {
+        TextNodeListener(SwTextNode* pTextNode, wwExtraneousParas* pOwner)
+            : m_pTextNode(pTextNode)
+            , m_pOwner(pOwner)
+        {
+        }
+        bool operator<(const TextNodeListener& rOther) const
+        {
+            return m_pTextNode->GetIndex() < rOther.m_pTextNode->GetIndex();
+        }
+        virtual void SwClientNotify(const SwModify&, const SfxHint&) override;
+
+        SwTextNode *m_pTextNode;
+        wwExtraneousParas* m_pOwner;
+    };
     /*
     A vector of SwTextNodes to erase from a document after import is complete
     */
-    std::set<SwTextNode*, SwWW8::ltnode> m_aTextNodes;
+    std::set<TextNodeListener> m_aTextNodes;
     SwDoc& m_rDoc;
 
     wwExtraneousParas(wwExtraneousParas const&) = delete;
     wwExtraneousParas& operator=(wwExtraneousParas const&) = delete;
-
 public:
     explicit wwExtraneousParas(SwDoc &rDoc) : m_rDoc(rDoc) {}
     ~wwExtraneousParas() { delete_all_from_doc(); }
-    void insert(SwTextNode *pTextNode) { m_aTextNodes.insert(pTextNode); }
-    void check_anchor_destination(SwTextNode *pTextNode)
-    {
-        auto it = m_aTextNodes.find(pTextNode);
-        if (it == m_aTextNodes.end())
-            return;
-        SAL_WARN("sw.ww8", "It is unexpected to anchor something in a para 
scheduled for removal");
-        m_aTextNodes.erase(it);
-    }
+    void insert(SwTextNode *pTextNode);
+    void remove_if_present(SwTextNode *pTextNode);
     void delete_all_from_doc();
 };
 
diff --git a/sw/source/filter/ww8/ww8par6.cxx b/sw/source/filter/ww8/ww8par6.cxx
index 66900d1a8cc6..c9fc7df8a8ef 100644
--- a/sw/source/filter/ww8/ww8par6.cxx
+++ b/sw/source/filter/ww8/ww8par6.cxx
@@ -2497,7 +2497,7 @@ bool SwWW8ImplReader::StartApo(const ApoTestResults 
&rApo, const WW8_TablePos *p
         {
             // ofz#34749 we shouldn't anchor anything into an 'extra' 
paragraph scheduled for
             // removal at end of import, but check if that scenario is 
happening
-            
m_aExtraneousParas.check_anchor_destination(m_pPaM->GetNode().GetTextNode());
+            
m_aExtraneousParas.remove_if_present(m_pPaM->GetNode().GetTextNode());
             
m_xSFlyPara->SetFlyFormat(m_rDoc.MakeFlySection(WW8SwFlyPara::eAnchor,
                                                             
m_pPaM->GetPoint(), &aFlySet));
             OSL_ENSURE(m_xSFlyPara->GetFlyFormat()->GetAnchor().GetAnchorId() 
==

Reply via email to