diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2018-08-16 13:56:07 +0300 |
---|---|---|
committer | Michael Stahl <Michael.Stahl@cib.de> | 2018-08-22 18:36:48 +0200 |
commit | b14bc12eee887b8a892f2bb114ffd50448a74d74 (patch) | |
tree | 03db595aeaf84fce21bc53f592f93125c0f08edf /sw | |
parent | 08d37362faeb9a242b3ca4c0df3615600391cb98 (diff) |
tdf#119294: reimplement fix for tdf#118859
When removing paragraphs with mail mere fields, both field type reference
and node reference could get invalid, because field type will be destroyed
when its last field is gone; and node will be destroyed if it is in a fly
with anchor in another node which gets destroyed.
To avoid use-after-delete, we will use an SwClient on field types, thus
detecting if a collected field type got destroyed; iterating over fields
using SwIterator is safe, because removing a node with fields would update
the iterator.
Change-Id: Id8b555ef7015b13ab70ebb41845d34c477ac6b31
Reviewed-on: https://gerrit.libreoffice.org/59164
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
(cherry picked from commit c883d5e073d2ac5b2d55126c929d7bf3e6d295e8)
Reviewed-on: https://gerrit.libreoffice.org/59175
Tested-by: Xisco Faulí <xiscofauli@libreoffice.org>
Reviewed-by: Michael Stahl <Michael.Stahl@cib.de>
Diffstat (limited to 'sw')
-rw-r--r-- | sw/source/core/doc/doc.cxx | 49 |
1 files changed, 32 insertions, 17 deletions
diff --git a/sw/source/core/doc/doc.cxx b/sw/source/core/doc/doc.cxx index 32b522e69767..450fc3aed05c 100644 --- a/sw/source/core/doc/doc.cxx +++ b/sw/source/core/doc/doc.cxx @@ -46,6 +46,7 @@ #include <comphelper/string.hxx> #include <comphelper/random.hxx> +#include <o3tl/make_unique.hxx> #include <tools/urlobj.hxx> #include <tools/poly.hxx> #include <tools/multisel.hxx> @@ -125,7 +126,6 @@ #include <vector> #include <map> -#include <set> #include <osl/diagnose.h> #include <osl/interlck.h> #include <vbahelper/vbaaccesshelper.hxx> @@ -1343,8 +1343,9 @@ void RemoveOrDeleteContents(SwTextNode* pTextNd, IDocumentContentOperations& xOp xOperations.DelFullPara(aPam); } } -// Returns the node pointer which needs to hide, or nullptr if this field does not hide a node -SwTextNode* HandleHidingField(SwFormatField& rFormatField, const SwNodes& rNodes) +// Returns if the data was actually modified +bool HandleHidingField(SwFormatField& rFormatField, const SwNodes& rNodes, + IDocumentContentOperations& xOperations) { SwTextNode* pTextNd; if (rFormatField.GetTextField() @@ -1352,9 +1353,10 @@ SwTextNode* HandleHidingField(SwFormatField& rFormatField, const SwNodes& rNodes && pTextNd->GetpSwpHints() && pTextNd->IsHiddenByParaField() && &pTextNd->GetNodes() == &rNodes) { - return pTextNd; + RemoveOrDeleteContents(pTextNd, xOperations); + return true; } - return nullptr; + return false; } } @@ -1393,25 +1395,38 @@ bool SwDoc::RemoveInvisibleContent() GetIDocumentUndoRedo().StartUndo( SwUndoId::UI_DELETE_INVISIBLECNTNT, nullptr ); { + class FieldTypeGuard : public SwClient + { + public: + explicit FieldTypeGuard(SwFieldType* pType) + : SwClient(pType) + { + } + const SwFieldType* get() const + { + return static_cast<const SwFieldType*>(GetRegisteredIn()); + } + }; // Removing some nodes for one SwFieldIds::Database type might remove the type from - // document's field types, or try to remove already removed nodes, invalidating iterators. - // So, we need to create own list of nodes prior to removing them. - std::set<SwTextNode*> aHiddenNodes; - for (const auto* pType : *getIDocumentFieldsAccess().GetFieldTypes()) + // document's field types, invalidating iterators. So, we need to create own list of + // matching types prior to processing them. + std::vector<std::unique_ptr<FieldTypeGuard>> aHidingFieldTypes; + for (SwFieldType* pType : *getIDocumentFieldsAccess().GetFieldTypes()) { if (FieldCanHidePara(pType->Which())) + aHidingFieldTypes.push_back(o3tl::make_unique<FieldTypeGuard>(pType)); + } + for (const auto& pTypeGuard : aHidingFieldTypes) + { + if (const SwFieldType* pType = pTypeGuard->get()) { SwIterator<SwFormatField, SwFieldType> aIter(*pType); - for (auto* pField = aIter.First(); pField; pField = aIter.Next()) - if (SwTextNode* pHiddenNode = HandleHidingField(*pField, GetNodes())) - aHiddenNodes.insert(pHiddenNode); + for (SwFormatField* pFormatField = aIter.First(); pFormatField; + pFormatField = aIter.Next()) + bRet |= HandleHidingField(*pFormatField, GetNodes(), + getIDocumentContentOperations()); } } - for (SwTextNode* pHiddenNode : aHiddenNodes) - { - bRet = true; - RemoveOrDeleteContents(pHiddenNode, getIDocumentContentOperations()); - } } // Remove any hidden paragraph (hidden text attribute) |