summaryrefslogtreecommitdiff
path: root/sw
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2021-11-26 12:40:37 +0000
committerCaolán McNamara <caolanm@redhat.com>2021-11-26 20:21:20 +0100
commit7d3aadce8d184f72e4785827ad706d27c31a2edb (patch)
tree1fc11957d8564f57e14c91dda590964c883ffbb3 /sw
parentb03e070420606d407df2ec5e9dfa7043ecc46177 (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.docbin0 -> 3291 bytes
-rw-r--r--sw/source/filter/ww8/ww8par.cxx39
-rw-r--r--sw/source/filter/ww8/ww8par.hxx32
-rw-r--r--sw/source/filter/ww8/ww8par6.cxx2
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
new file mode 100644
index 000000000000..34c6e357d82a
--- /dev/null
+++ b/sw/qa/core/data/ww6/pass/ofz41398-1.doc
Binary files 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() ==