tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ManualNAC.h (3826B)


      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/. */
      5 
      6 #ifndef mozilla_ManualNAC_h
      7 #define mozilla_ManualNAC_h
      8 
      9 #include "mozilla/dom/Element.h"
     10 #include "mozilla/RefPtr.h"
     11 
     12 namespace mozilla {
     13 
     14 // 16 seems to be the maximum number of manual Native Anonymous Content (NAC)
     15 // nodes that editor creates for a given element.
     16 //
     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>;
     20 
     21 /**
     22 * Smart pointer class to own "manual" Native Anonymous Content, and perform
     23 * the necessary registration and deregistration on the parent element.
     24 */
     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;
     33    }
     34 
     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>);
     43    }
     44    nac->AppendElement(mPtr);
     45  }
     46 
     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;
     53  }
     54  ManualNACPtr& operator=(ManualNACPtr& aOther) = delete;
     55 
     56  ~ManualNACPtr() { Reset(); }
     57 
     58  void Reset() {
     59    if (!mPtr) {
     60      return;
     61    }
     62 
     63    RefPtr<dom::Element> ptr = std::move(mPtr);
     64    RemoveContentFromNACArray(ptr);
     65  }
     66 
     67  static bool IsManualNAC(nsIContent* aAnonContent) {
     68    MOZ_ASSERT(aAnonContent->IsRootOfNativeAnonymousSubtree());
     69    MOZ_ASSERT(aAnonContent->IsInComposedDoc());
     70 
     71    auto* nac = static_cast<ManualNACArray*>(
     72        aAnonContent->GetParent()->GetProperty(nsGkAtoms::manualNACProperty));
     73    return nac && nac->Contains(aAnonContent);
     74  }
     75 
     76  static void RemoveContentFromNACArray(nsIContent* aAnonymousContent) {
     77    nsIContent* parentContent = aAnonymousContent->GetParent();
     78    if (!parentContent) {
     79      NS_WARNING("Potentially leaking manual NAC");
     80      return;
     81    }
     82 
     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);
     92      }
     93    }
     94 
     95    aAnonymousContent->UnbindFromTree();
     96  }
     97 
     98  dom::Element* get() const { return mPtr.get(); }
     99  dom::Element* operator->() const { return get(); }
    100  operator dom::Element*() const& { return get(); }
    101 
    102 private:
    103  RefPtr<dom::Element> mPtr;
    104 };
    105 
    106 }  // namespace mozilla
    107 
    108 inline void ImplCycleCollectionUnlink(mozilla::ManualNACPtr& field) {
    109  field.Reset();
    110 }
    111 
    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);
    116 }
    117 
    118 #endif  // #ifndef mozilla_ManualNAC_h