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"
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>;
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
{
27 ManualNACPtr() = default;
28 MOZ_IMPLICIT
ManualNACPtr(decltype(nullptr)) {}
29 explicit ManualNACPtr(already_AddRefed
<dom::Element
> aNewNAC
)
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
));
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
);
54 ManualNACPtr
& operator=(ManualNACPtr
& aOther
) = delete;
56 ~ManualNACPtr() { Reset(); }
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();
79 NS_WARNING("Potentially leaking manual NAC");
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.
89 nac
->RemoveElement(aAnonymousContent
);
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(); }
103 RefPtr
<dom::Element
> mPtr
;
106 } // namespace mozilla
108 inline void ImplCycleCollectionUnlink(mozilla::ManualNACPtr
& field
) {
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