Backed out changeset 4191b252db9b (bug 1886734) for causing build bustages @netwerk...
[gecko.git] / editor / libeditor / ManualNAC.h
blob17d0e4d273f094715a6c3760a69713d63190e031
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef mozilla_ManualNAC_h
7 #define mozilla_ManualNAC_h
9 #include "mozilla/dom/Element.h"
10 #include "mozilla/RefPtr.h"
12 namespace mozilla {
14 // 16 seems to be the maximum number of manual Native Anonymous Content (NAC)
15 // nodes that editor creates for a given element.
17 // These need to be manually removed by the machinery that sets the NAC,
18 // otherwise we'll leak.
19 using ManualNACArray = AutoTArray<RefPtr<dom::Element>, 16>;
21 /**
22 * Smart pointer class to own "manual" Native Anonymous Content, and perform
23 * the necessary registration and deregistration on the parent element.
25 class ManualNACPtr final {
26 public:
27 ManualNACPtr() = default;
28 MOZ_IMPLICIT ManualNACPtr(decltype(nullptr)) {}
29 explicit ManualNACPtr(already_AddRefed<dom::Element> aNewNAC)
30 : mPtr(aNewNAC) {
31 if (!mPtr) {
32 return;
35 // Record the NAC on the element, so that AllChildrenIterator can find it.
36 nsIContent* parentContent = mPtr->GetParent();
37 auto nac = static_cast<ManualNACArray*>(
38 parentContent->GetProperty(nsGkAtoms::manualNACProperty));
39 if (!nac) {
40 nac = new ManualNACArray();
41 parentContent->SetProperty(nsGkAtoms::manualNACProperty, nac,
42 nsINode::DeleteProperty<ManualNACArray>);
44 nac->AppendElement(mPtr);
47 // We use move semantics, and delete the copy-constructor and operator=.
48 ManualNACPtr(ManualNACPtr&& aOther) : mPtr(std::move(aOther.mPtr)) {}
49 ManualNACPtr(ManualNACPtr& aOther) = delete;
50 ManualNACPtr& operator=(ManualNACPtr&& aOther) {
51 mPtr = std::move(aOther.mPtr);
52 return *this;
54 ManualNACPtr& operator=(ManualNACPtr& aOther) = delete;
56 ~ManualNACPtr() { Reset(); }
58 void Reset() {
59 if (!mPtr) {
60 return;
63 RefPtr<dom::Element> ptr = std::move(mPtr);
64 RemoveContentFromNACArray(ptr);
67 static bool IsManualNAC(nsIContent* aAnonContent) {
68 MOZ_ASSERT(aAnonContent->IsRootOfNativeAnonymousSubtree());
69 MOZ_ASSERT(aAnonContent->IsInComposedDoc());
71 auto* nac = static_cast<ManualNACArray*>(
72 aAnonContent->GetParent()->GetProperty(nsGkAtoms::manualNACProperty));
73 return nac && nac->Contains(aAnonContent);
76 static void RemoveContentFromNACArray(nsIContent* aAnonymousContent) {
77 nsIContent* parentContent = aAnonymousContent->GetParent();
78 if (!parentContent) {
79 NS_WARNING("Potentially leaking manual NAC");
80 return;
83 // Remove reference from the parent element.
84 auto* nac = static_cast<ManualNACArray*>(
85 parentContent->GetProperty(nsGkAtoms::manualNACProperty));
86 // Document::AdoptNode might remove all properties before destroying editor.
87 // So we have to consider that NAC could be already removed.
88 if (nac) {
89 nac->RemoveElement(aAnonymousContent);
90 if (nac->IsEmpty()) {
91 parentContent->RemoveProperty(nsGkAtoms::manualNACProperty);
95 aAnonymousContent->UnbindFromTree();
98 dom::Element* get() const { return mPtr.get(); }
99 dom::Element* operator->() const { return get(); }
100 operator dom::Element*() const& { return get(); }
102 private:
103 RefPtr<dom::Element> mPtr;
106 } // namespace mozilla
108 inline void ImplCycleCollectionUnlink(mozilla::ManualNACPtr& field) {
109 field.Reset();
112 inline void ImplCycleCollectionTraverse(
113 nsCycleCollectionTraversalCallback& callback,
114 const mozilla::ManualNACPtr& field, const char* name, uint32_t flags = 0) {
115 CycleCollectionNoteChild(callback, field.get(), name, flags);
118 #endif // #ifndef mozilla_ManualNAC_h