tor-browser

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

IdentifierMapEntry.h (8018B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 /*
      8 * Entry for the Document or ShadowRoot's identifier map.
      9 */
     10 
     11 #ifndef mozilla_IdentifierMapEntry_h
     12 #define mozilla_IdentifierMapEntry_h
     13 
     14 #include <utility>
     15 
     16 #include "PLDHashTable.h"
     17 #include "mozilla/MemoryReporting.h"
     18 #include "mozilla/UniquePtr.h"
     19 #include "mozilla/dom/TreeOrderedArray.h"
     20 #include "nsAtom.h"
     21 #include "nsCOMPtr.h"
     22 #include "nsContentList.h"
     23 #include "nsHashKeys.h"
     24 #include "nsTArray.h"
     25 #include "nsTHashtable.h"
     26 
     27 class nsIContent;
     28 class nsINode;
     29 
     30 namespace mozilla {
     31 namespace dom {
     32 class Document;
     33 class Element;
     34 }  // namespace dom
     35 
     36 /**
     37 * Right now our identifier map entries contain information for 'name'
     38 * and 'id' mappings of a given string. This is so that
     39 * nsHTMLDocument::ResolveName only has to do one hash lookup instead
     40 * of two. It's not clear whether this still matters for performance.
     41 *
     42 * We also store the document.all result list here. This is mainly so that
     43 * when all elements with the given ID are removed and we remove
     44 * the ID's IdentifierMapEntry, the document.all result is released too.
     45 * Perhaps the document.all results should have their own hashtable
     46 * in nsHTMLDocument.
     47 */
     48 class IdentifierMapEntry : public PLDHashEntryHdr {
     49  typedef dom::Document Document;
     50  typedef dom::Element Element;
     51 
     52  /**
     53   * @see Document::IDTargetObserver, this is just here to avoid include hell.
     54   */
     55  typedef bool (*IDTargetObserver)(Element* aOldElement, Element* aNewelement,
     56                                   void* aData);
     57 
     58 public:
     59  // We use DependentAtomOrString as our external key interface.  This allows
     60  // consumers to use an nsAString, for example, without forcing a copy.
     61  struct DependentAtomOrString final {
     62    MOZ_IMPLICIT DependentAtomOrString(nsAtom* aAtom)
     63        : mAtom(aAtom), mString(nullptr) {}
     64    MOZ_IMPLICIT DependentAtomOrString(const nsAString& aString)
     65        : mAtom(nullptr), mString(&aString) {}
     66    DependentAtomOrString(const DependentAtomOrString& aOther) = default;
     67 
     68    nsAtom* mAtom;
     69    const nsAString* mString;
     70  };
     71 
     72  typedef const DependentAtomOrString& KeyType;
     73  typedef const DependentAtomOrString* KeyTypePointer;
     74 
     75  explicit IdentifierMapEntry(const DependentAtomOrString* aKey);
     76  IdentifierMapEntry(IdentifierMapEntry&& aOther) = default;
     77  ~IdentifierMapEntry() = default;
     78 
     79  nsString GetKeyAsString() const {
     80    if (mKey.mAtom) {
     81      return nsAtomString(mKey.mAtom);
     82    }
     83 
     84    return mKey.mString;
     85  }
     86 
     87  bool KeyEquals(const KeyTypePointer aOtherKey) const {
     88    if (mKey.mAtom) {
     89      if (aOtherKey->mAtom) {
     90        return mKey.mAtom == aOtherKey->mAtom;
     91      }
     92 
     93      return mKey.mAtom->Equals(*aOtherKey->mString);
     94    }
     95 
     96    if (aOtherKey->mAtom) {
     97      return aOtherKey->mAtom->Equals(mKey.mString);
     98    }
     99 
    100    return mKey.mString.Equals(*aOtherKey->mString);
    101  }
    102 
    103  static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; }
    104 
    105  static PLDHashNumber HashKey(const KeyTypePointer aKey) {
    106    return aKey->mAtom ? aKey->mAtom->hash() : HashString(*aKey->mString);
    107  }
    108 
    109  enum { ALLOW_MEMMOVE = false };
    110 
    111  bool IsEmpty();
    112 
    113  void AddNameElement(nsINode* aDocument, Element* aElement);
    114  void RemoveNameElement(Element* aElement);
    115  nsBaseContentList* GetNameContentList() { return mNameContentList; }
    116  bool HasNameElement() const;
    117 
    118  void AddDocumentNameElement(Document* aDocument,
    119                              nsGenericHTMLElement* aElement);
    120  void RemoveDocumentNameElement(nsGenericHTMLElement* aElement);
    121  bool HasDocumentNameElement() const;
    122  nsBaseContentList* GetDocumentNameContentList() {
    123    return mDocumentNameContentList;
    124  }
    125 
    126  /**
    127   * Returns the element if we know the element associated with this
    128   * id. Otherwise returns null.
    129   */
    130  Element* GetIdElement() const {
    131    auto span = mIdContentList.AsSpan();
    132    return span.IsEmpty() ? nullptr : span[0];
    133  }
    134 
    135  /**
    136   * Returns the list of all elements associated with this id.
    137   */
    138  Span<Element* const> GetIdElements() const { return mIdContentList.AsSpan(); }
    139 
    140  /**
    141   * If this entry has a non-null image element set (using SetImageElement),
    142   * the image element will be returned, otherwise the same as GetIdElement().
    143   */
    144  Element* GetImageIdElement() {
    145    return mImageElement ? mImageElement.get() : GetIdElement();
    146  }
    147 
    148  /**
    149   * This can fire ID change callbacks.
    150   */
    151  void AddIdElement(Element* aElement);
    152  /**
    153   * This can fire ID change callbacks.
    154   */
    155  void RemoveIdElement(Element* aElement);
    156  /**
    157   * Set the image element override for this ID. This will be returned by
    158   * GetIdElement(true) if non-null.
    159   */
    160  void SetImageElement(Element* aElement);
    161  bool HasIdElementExposedAsHTMLDocumentProperty() const;
    162 
    163  bool HasContentChangeCallback() { return mChangeCallbacks != nullptr; }
    164  void AddContentChangeCallback(IDTargetObserver aCallback, void* aData,
    165                                bool aForImage);
    166  void RemoveContentChangeCallback(IDTargetObserver aCallback, void* aData,
    167                                   bool aForImage);
    168 
    169  /**
    170   * Remove all elements and notify change listeners.
    171   */
    172  void ClearAndNotify();
    173 
    174  void Traverse(nsCycleCollectionTraversalCallback* aCallback);
    175 
    176  struct ChangeCallback {
    177    IDTargetObserver mCallback;
    178    void* mData;
    179    bool mForImage;
    180  };
    181 
    182  struct ChangeCallbackEntry : public PLDHashEntryHdr {
    183    typedef const ChangeCallback KeyType;
    184    typedef const ChangeCallback* KeyTypePointer;
    185 
    186    explicit ChangeCallbackEntry(const ChangeCallback* aKey) : mKey(*aKey) {}
    187    ChangeCallbackEntry(ChangeCallbackEntry&& aOther)
    188        : PLDHashEntryHdr(std::move(aOther)), mKey(std::move(aOther.mKey)) {}
    189 
    190    KeyType GetKey() const { return mKey; }
    191    bool KeyEquals(KeyTypePointer aKey) const {
    192      return aKey->mCallback == mKey.mCallback && aKey->mData == mKey.mData &&
    193             aKey->mForImage == mKey.mForImage;
    194    }
    195 
    196    static KeyTypePointer KeyToPointer(KeyType& aKey) { return &aKey; }
    197    static PLDHashNumber HashKey(KeyTypePointer aKey) {
    198      return HashGeneric(aKey->mCallback, aKey->mData);
    199    }
    200    enum { ALLOW_MEMMOVE = true };
    201 
    202    ChangeCallback mKey;
    203  };
    204 
    205  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
    206 
    207 private:
    208  // We use an OwningAtomOrString as our internal key storage.  It needs to own
    209  // the key string, whether in atom or string form.
    210  struct OwningAtomOrString final {
    211    OwningAtomOrString(const OwningAtomOrString& aOther) = delete;
    212    OwningAtomOrString(OwningAtomOrString&& aOther) = default;
    213 
    214    explicit OwningAtomOrString(const DependentAtomOrString& aOther)
    215        // aOther may have a null mString, so jump through a bit of a hoop in
    216        // that case.  I wish there were a way to just default-initialize
    217        // mString in that situation...  We could also make mString not const
    218        // and only assign to it if aOther.mString is not null, but having it be
    219        // const is nice.
    220        : mAtom(aOther.mAtom),
    221          mString(aOther.mString ? *aOther.mString : u""_ns) {}
    222 
    223    RefPtr<nsAtom> mAtom;
    224    nsString mString;
    225  };
    226 
    227  IdentifierMapEntry(const IdentifierMapEntry& aOther) = delete;
    228  IdentifierMapEntry& operator=(const IdentifierMapEntry& aOther) = delete;
    229 
    230  void FireChangeCallbacks(Element* aOldElement, Element* aNewElement,
    231                           bool aImageOnly = false);
    232 
    233  OwningAtomOrString mKey;
    234  dom::TreeOrderedArray<Element*> mIdContentList;
    235  RefPtr<nsBaseContentList> mNameContentList;
    236  // The content list for the document named getter.
    237  RefPtr<nsBaseContentList> mDocumentNameContentList;
    238  UniquePtr<nsTHashtable<ChangeCallbackEntry> > mChangeCallbacks;
    239  RefPtr<Element> mImageElement;
    240 };
    241 
    242 }  // namespace mozilla
    243 
    244 #endif  // #ifndef mozilla_IdentifierMapEntry_h