diff options
author | Caolán McNamara <caolanm@redhat.com> | 2021-11-26 12:40:37 +0000 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2021-11-26 20:21:20 +0100 |
commit | 7d3aadce8d184f72e4785827ad706d27c31a2edb (patch) | |
tree | 1fc11957d8564f57e14c91dda590964c883ffbb3 /sw | |
parent | b03e070420606d407df2ec5e9dfa7043ecc46177 (diff) |
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 <caolanm@redhat.com>
Diffstat (limited to 'sw')
-rw-r--r-- | sw/qa/core/data/ww6/pass/ofz41398-1.doc | bin | 0 -> 3291 bytes | |||
-rw-r--r-- | sw/source/filter/ww8/ww8par.cxx | 39 | ||||
-rw-r--r-- | sw/source/filter/ww8/ww8par.hxx | 32 | ||||
-rw-r--r-- | sw/source/filter/ww8/ww8par6.cxx | 2 |
4 files changed, 59 insertions, 14 deletions
diff --git a/sw/qa/core/data/ww6/pass/ofz41398-1.doc b/sw/qa/core/data/ww6/pass/ofz41398-1.doc Binary files differnew file mode 100644 index 000000000000..34c6e357d82a --- /dev/null +++ b/sw/qa/core/data/ww6/pass/ofz41398-1.doc 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() == |