tor-browser

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

nsIMutationObserver.h (20922B)


      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 #ifndef nsIMutationObserver_h
      8 #define nsIMutationObserver_h
      9 
     10 #include <ostream>
     11 
     12 #include "mozilla/Assertions.h"
     13 #include "mozilla/DbgMacro.h"
     14 #include "mozilla/DoublyLinkedList.h"
     15 #include "nsISupports.h"
     16 
     17 class nsAttrValue;
     18 class nsAtom;
     19 class nsIContent;
     20 class nsINode;
     21 struct BatchRemovalState;
     22 
     23 namespace mozilla::dom {
     24 class Element;
     25 }  // namespace mozilla::dom
     26 
     27 #define NS_IMUTATION_OBSERVER_IID \
     28  {0x6d674c17, 0x0fbc, 0x4633, {0x8f, 0x46, 0x73, 0x4e, 0x87, 0xeb, 0xf0, 0xc7}}
     29 
     30 /**
     31 * Used for Trusted Types' Enforcement for scripts.
     32 * https://w3c.github.io/trusted-types/dist/spec/#enforcement-in-scripts
     33 */
     34 enum class MutationEffectOnScript : bool {
     35  KeepTrustWorthiness,
     36  DropTrustWorthiness,
     37 };
     38 
     39 inline std::ostream& operator<<(
     40    std::ostream& aStream, MutationEffectOnScript aMutationEffectOnScript) {
     41  return aStream << (static_cast<bool>(aMutationEffectOnScript)
     42                         ? "DropTrustWorthiness"
     43                         : "KeepTrustWorthiness");
     44 }
     45 
     46 // AttrModType is same as the legacy MutationEvent.attrChange value.
     47 enum class AttrModType : uint8_t {
     48  Modification = 1,
     49  Addition = 2,
     50  Removal = 3,
     51 };
     52 
     53 [[nodiscard]] inline bool IsAdditionOrModification(AttrModType aModType) {
     54  return aModType == AttrModType::Modification ||
     55         aModType == AttrModType::Addition;
     56 }
     57 [[nodiscard]] inline bool IsAdditionOrRemoval(AttrModType aModType) {
     58  return aModType == AttrModType::Addition || aModType == AttrModType::Removal;
     59 }
     60 
     61 /**
     62 * Information details about a characterdata change.  Basically, we
     63 * view all changes as replacements of a length of text at some offset
     64 * with some other text (of possibly some other length).
     65 */
     66 struct CharacterDataChangeInfo {
     67  /**
     68   * True if this character data change is just an append.
     69   */
     70  bool mAppend;
     71 
     72  /**
     73   * The offset in the text where the change occurred.
     74   */
     75  uint32_t mChangeStart;
     76 
     77  /**
     78   * The offset such that mChangeEnd - mChangeStart is equal to the length of
     79   * the text we removed. If this was a pure insert, append or a result of
     80   * `splitText()` this is equal to mChangeStart.
     81   */
     82  uint32_t mChangeEnd;
     83 
     84  uint32_t LengthOfRemovedText() const {
     85    MOZ_ASSERT(mChangeStart <= mChangeEnd);
     86 
     87    return mChangeEnd - mChangeStart;
     88  }
     89 
     90  /**
     91   * The length of the text that was inserted in place of the removed text.  If
     92   * this was a pure text removal, this is 0.
     93   */
     94  uint32_t mReplaceLength;
     95 
     96  /**
     97   * The net result is that mChangeStart characters at the beginning of the
     98   * text remained as they were.  The next mChangeEnd - mChangeStart characters
     99   * were removed, and mReplaceLength characters were inserted in their place.
    100   * The text that used to begin at mChangeEnd now begins at
    101   * mChangeStart + mReplaceLength.
    102   */
    103 
    104  MutationEffectOnScript mMutationEffectOnScript =
    105      MutationEffectOnScript::DropTrustWorthiness;
    106 
    107  struct MOZ_STACK_CLASS Details {
    108    enum {
    109      eMerge,  // two text nodes are merged as a result of normalize()
    110      eSplit   // a text node is split as a result of splitText()
    111    } mType;
    112    /**
    113     * For eMerge it's the text node that will be removed, for eSplit it's the
    114     * new text node.
    115     */
    116    nsIContent* MOZ_NON_OWNING_REF mNextSibling;
    117  };
    118 
    119  /**
    120   * Used for splitText() and normalize(), otherwise null.
    121   */
    122  Details* mDetails = nullptr;
    123 
    124  MOZ_DEFINE_DBG(CharacterDataChangeInfo, mAppend, mChangeStart, mChangeEnd,
    125                 mReplaceLength, mMutationEffectOnScript, mDetails);
    126 };
    127 
    128 /**
    129 * Information details about a content appending.
    130 */
    131 struct ContentAppendInfo {
    132  MutationEffectOnScript mMutationEffectOnScript =
    133      MutationEffectOnScript::DropTrustWorthiness;
    134  nsINode* mOldParent = nullptr;
    135 };
    136 
    137 /**
    138 * Information details about a content insertion.
    139 */
    140 using ContentInsertInfo = ContentAppendInfo;
    141 
    142 /**
    143 * Information details about a content removal.
    144 */
    145 struct ContentRemoveInfo {
    146  /* Whether we'll be removing all children of this
    147     container. This is useful to avoid wasteful work. */
    148  const BatchRemovalState* mBatchRemovalState = nullptr;
    149 
    150  MutationEffectOnScript mMutationEffectOnScript =
    151      MutationEffectOnScript::DropTrustWorthiness;
    152  nsINode* mNewParent = nullptr;
    153 };
    154 
    155 /**
    156 * Mutation observer interface
    157 *
    158 * See nsINode::AddMutationObserver, nsINode::RemoveMutationObserver for how to
    159 * attach or remove your observers. nsINode stores mutation observers using a
    160 * mozilla::SafeDoublyLinkedList, which is a specialization of the
    161 * DoublyLinkedList allowing for adding/removing elements while iterating.
    162 * If a mutation observer is intended to be added to multiple nsINode instances,
    163 * derive from nsMultiMutationObserver.
    164 *
    165 * WARNING: During these notifications, you are not allowed to perform
    166 * any mutations to the current or any other document, or start a
    167 * network load.  If you need to perform such operations do that
    168 * during the _last_ nsIDocumentObserver::EndUpdate notification.  The
    169 * exception for this is ParentChainChanged, where mutations should be
    170 * done from an async event, as the notification might not be
    171 * surrounded by BeginUpdate/EndUpdate calls.
    172 */
    173 class nsIMutationObserver
    174    : public nsISupports,
    175      mozilla::DoublyLinkedListElement<nsIMutationObserver> {
    176  friend struct mozilla::GetDoublyLinkedListElement<nsIMutationObserver>;
    177 
    178 public:
    179  NS_INLINE_DECL_STATIC_IID(NS_IMUTATION_OBSERVER_IID)
    180 
    181  /**
    182   * Notification that the node value of a data node (text, cdata, pi, comment)
    183   * will be changed.
    184   *
    185   * This notification is not sent when a piece of content is
    186   * added/removed from the document (the other notifications are used
    187   * for that).
    188   *
    189   * @param aContent  The piece of content that changed. Is never null.
    190   * @param aInfo     The structure with information details about the change.
    191   *
    192   * @note Callers of this method might not hold a strong reference to the
    193   *       observer.  The observer is responsible for making sure it stays
    194   *       alive for the duration of the call as needed.  The observer may
    195   *       assume that this call will happen when there are script blockers on
    196   *       the stack.
    197   */
    198  virtual void CharacterDataWillChange(nsIContent* aContent,
    199                                       const CharacterDataChangeInfo&) = 0;
    200 
    201  /**
    202   * Notification that the node value of a data node (text, cdata, pi, comment)
    203   * has changed.
    204   *
    205   * This notification is not sent when a piece of content is
    206   * added/removed from the document (the other notifications are used
    207   * for that).
    208   *
    209   * @param aContent  The piece of content that changed. Is never null.
    210   * @param aInfo     The structure with information details about the change.
    211   *
    212   * @note Callers of this method might not hold a strong reference to the
    213   *       observer.  The observer is responsible for making sure it stays
    214   *       alive for the duration of the call as needed.  The observer may
    215   *       assume that this call will happen when there are script blockers on
    216   *       the stack.
    217   */
    218  virtual void CharacterDataChanged(nsIContent* aContent,
    219                                    const CharacterDataChangeInfo&) = 0;
    220 
    221  /**
    222   * Notification that an attribute of an element will change.  This
    223   * can happen before the BeginUpdate for the change and may not
    224   * always be followed by an AttributeChanged (in particular, if the
    225   * attribute doesn't actually change there will be no corresponding
    226   * AttributeChanged).
    227   *
    228   * @param aContent     The element whose attribute will change
    229   * @param aNameSpaceID The namespace id of the changing attribute
    230   * @param aAttribute   The name of the changing attribute
    231   * @param aModType     Whether or not the attribute will be added, changed, or
    232   *                     removed.
    233   *
    234   * @note Callers of this method might not hold a strong reference to the
    235   *       observer.  The observer is responsible for making sure it stays
    236   *       alive for the duration of the call as needed.  The observer may
    237   *       assume that this call will happen when there are script blockers on
    238   *       the stack.
    239   */
    240  virtual void AttributeWillChange(mozilla::dom::Element* aElement,
    241                                   int32_t aNameSpaceID, nsAtom* aAttribute,
    242                                   AttrModType aModType) = 0;
    243 
    244  /**
    245   * Notification that an attribute of an element has changed.
    246   *
    247   * @param aElement     The element whose attribute changed
    248   * @param aNameSpaceID The namespace id of the changed attribute
    249   * @param aAttribute   The name of the changed attribute
    250   * @param aModType     Whether or not the attribute was added, changed, or
    251   *                     removed.
    252   * @param aOldValue    The old value, if either the old value or the new
    253   *                     value are StoresOwnData() (or absent); null otherwise.
    254   *
    255   * @note Callers of this method might not hold a strong reference to the
    256   *       observer.  The observer is responsible for making sure it stays
    257   *       alive for the duration of the call as needed.  The observer may
    258   *       assume that this call will happen when there are script blockers on
    259   *       the stack.
    260   */
    261  virtual void AttributeChanged(mozilla::dom::Element* aElement,
    262                                int32_t aNameSpaceID, nsAtom* aAttribute,
    263                                AttrModType aModType,
    264                                const nsAttrValue* aOldValue) = 0;
    265 
    266  /**
    267   * Notification that an attribute of an element has been
    268   * set to the value it already had.
    269   *
    270   * @param aElement     The element whose attribute changed
    271   * @param aNameSpaceID The namespace id of the changed attribute
    272   * @param aAttribute   The name of the changed attribute
    273   */
    274  virtual void AttributeSetToCurrentValue(mozilla::dom::Element* aElement,
    275                                          int32_t aNameSpaceID,
    276                                          nsAtom* aAttribute) {}
    277 
    278  /**
    279   * Notification that one or more content nodes have been appended to the
    280   * child list of another node in the tree.
    281   *
    282   * @param aFirstNewContent the first node appended.
    283   * @param aInfo The structure with information details about the change.
    284   *
    285   * @note Callers of this method might not hold a strong reference to the
    286   *       observer.  The observer is responsible for making sure it stays
    287   *       alive for the duration of the call as needed.  The observer may
    288   *       assume that this call will happen when there are script blockers on
    289   *       the stack.
    290   */
    291  virtual void ContentAppended(nsIContent* aFirstNewContent,
    292                               const ContentAppendInfo&) = 0;
    293 
    294  /**
    295   * Notification that a content node has been inserted as child to another
    296   * node in the tree.
    297   *
    298   * @param aChild The newly inserted child.
    299   * @param aInfo The structure with information details about the change.
    300   *
    301   * @note Callers of this method might not hold a strong reference to the
    302   *       observer.  The observer is responsible for making sure it stays
    303   *       alive for the duration of the call as needed.  The observer may
    304   *       assume that this call will happen when there are script blockers on
    305   *       the stack.
    306   */
    307  virtual void ContentInserted(nsIContent* aChild,
    308                               const ContentInsertInfo&) = 0;
    309 
    310  /**
    311   * Notification that a content node is about to be removed from the child list
    312   * of another node in the tree.
    313   *
    314   * @param aChild     The child that will be removed.
    315   * @param aState     The state of our batch removal of all children, or null.
    316   * @param aInfo      The structure with information details about the change.
    317   *
    318   * @note Callers of this method might not hold a strong reference to the
    319   *       observer.  The observer is responsible for making sure it stays
    320   *       alive for the duration of the call as needed.  The observer may
    321   *       assume that this call will happen when there are script blockers on
    322   *       the stack.
    323   */
    324  virtual void ContentWillBeRemoved(nsIContent* aChild,
    325                                    const ContentRemoveInfo&) = 0;
    326 
    327  /**
    328   * The node is in the process of being destroyed. Calling QI on the node is
    329   * not supported, however it is possible to get children and flags through
    330   * nsINode as well as calling IsContent and casting to nsIContent to get
    331   * attributes.
    332   *
    333   * NOTE: This notification is only called on observers registered directly
    334   * on the node. This is because when the node is destroyed it can not have
    335   * any ancestors. If you want to know when a descendant node is being
    336   * removed from the observed node, use the ContentWillBeRemoved notification.
    337   *
    338   * @param aNode The node being destroyed.
    339   *
    340   * @note Callers of this method might not hold a strong reference to
    341   *       the observer.  The observer is responsible for making sure it
    342   *       stays alive for the duration of the call as needed.
    343   */
    344  virtual void NodeWillBeDestroyed(nsINode* aNode) = 0;
    345 
    346  /**
    347   * Notification that the node's parent chain has changed. This
    348   * happens when either the node or one of its ancestors is inserted
    349   * or removed as a child of another node.
    350   *
    351   * Note that when a node is inserted this notification is sent to
    352   * all descendants of that node, since all such nodes have their
    353   * parent chain changed.
    354   *
    355   * @param aContent  The piece of content that had its parent changed.
    356   *
    357   * @note Callers of this method might not hold a strong reference to
    358   *       the observer.  The observer is responsible for making sure it
    359   *       stays alive for the duration of the call as needed.
    360   */
    361 
    362  virtual void ParentChainChanged(nsIContent* aContent) = 0;
    363 
    364  virtual void ARIAAttributeDefaultWillChange(mozilla::dom::Element* aElement,
    365                                              nsAtom* aAttribute,
    366                                              AttrModType aModType) = 0;
    367  virtual void ARIAAttributeDefaultChanged(mozilla::dom::Element* aElement,
    368                                           nsAtom* aAttribute,
    369                                           AttrModType aModType) = 0;
    370 
    371  enum : uint32_t {
    372    kNone = 0,
    373    kCharacterDataWillChange = 1 << 0,
    374    kCharacterDataChanged = 1 << 1,
    375    kAttributeWillChange = 1 << 2,
    376    kAttributeChanged = 1 << 3,
    377    kAttributeSetToCurrentValue = 1 << 4,
    378    kContentAppended = 1 << 5,
    379    kContentInserted = 1 << 6,
    380    kContentWillBeRemoved = 1 << 7,
    381    kNodeWillBeDestroyed = 1 << 8,
    382    kParentChainChanged = 1 << 9,
    383    kARIAAttributeDefaultWillChange = 1 << 10,
    384    kARIAAttributeDefaultChanged = 1 << 11,
    385 
    386    kBeginUpdate = 1 << 12,
    387    kEndUpdate = 1 << 13,
    388    kBeginLoad = 1 << 14,
    389    kEndLoad = 1 << 15,
    390    kElementStateChanged = 1 << 16,
    391 
    392    kAnimationAdded = 1 << 17,
    393    kAnimationChanged = 1 << 18,
    394    kAnimationRemoved = 1 << 19,
    395 
    396    kAll = 0xFFFFFFFF
    397  };
    398 
    399  void SetEnabledCallbacks(uint32_t aCallbacks) {
    400    mEnabledCallbacks = aCallbacks;
    401  }
    402 
    403  bool IsCallbackEnabled(uint32_t aCallback) const {
    404    return mEnabledCallbacks & aCallback;
    405  }
    406 
    407 private:
    408  uint32_t mEnabledCallbacks = kAll;
    409 };
    410 
    411 #define NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATAWILLCHANGE \
    412  virtual void CharacterDataWillChange(                     \
    413      nsIContent* aContent, const CharacterDataChangeInfo& aInfo) override;
    414 
    415 #define NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED \
    416  virtual void CharacterDataChanged(                     \
    417      nsIContent* aContent, const CharacterDataChangeInfo& aInfo) override;
    418 
    419 #define NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE                      \
    420  virtual void AttributeWillChange(mozilla::dom::Element* aElement,          \
    421                                   int32_t aNameSpaceID, nsAtom* aAttribute, \
    422                                   AttrModType aModType) override;
    423 
    424 #define NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED                      \
    425  virtual void AttributeChanged(mozilla::dom::Element* aElement,          \
    426                                int32_t aNameSpaceID, nsAtom* aAttribute, \
    427                                AttrModType aModType,                     \
    428                                const nsAttrValue* aOldValue) override;
    429 
    430 #define NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED          \
    431  virtual void ContentAppended(nsIContent* aFirstNewContent, \
    432                               const ContentAppendInfo&) override;
    433 
    434 #define NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED                          \
    435  virtual void ContentInserted(nsIContent* aChild, const ContentInsertInfo&) \
    436      override;
    437 
    438 #define NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED      \
    439  virtual void ContentWillBeRemoved(nsIContent* aChild, \
    440                                    const ContentRemoveInfo&) override;
    441 
    442 #define NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED \
    443  virtual void NodeWillBeDestroyed(nsINode* aNode) override;
    444 
    445 #define NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED \
    446  virtual void ParentChainChanged(nsIContent* aContent) override;
    447 
    448 #define NS_DECL_NSIMUTATIONOBSERVER_ARIAATTRIBUTEDEFAULTWILLCHANGE             \
    449  virtual void ARIAAttributeDefaultWillChange(mozilla::dom::Element* aElement, \
    450                                              nsAtom* aAttribute,              \
    451                                              AttrModType aModType) override;
    452 
    453 #define NS_DECL_NSIMUTATIONOBSERVER_ARIAATTRIBUTEDEFAULTCHANGED             \
    454  virtual void ARIAAttributeDefaultChanged(mozilla::dom::Element* aElement, \
    455                                           nsAtom* aAttribute,              \
    456                                           AttrModType aModType) override;
    457 
    458 #define NS_DECL_NSIMUTATIONOBSERVER                          \
    459  NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATAWILLCHANGE        \
    460  NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED           \
    461  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTEWILLCHANGE            \
    462  NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED               \
    463  NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED                \
    464  NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED                \
    465  NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED                 \
    466  NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED            \
    467  NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED             \
    468  NS_DECL_NSIMUTATIONOBSERVER_ARIAATTRIBUTEDEFAULTWILLCHANGE \
    469  NS_DECL_NSIMUTATIONOBSERVER_ARIAATTRIBUTEDEFAULTCHANGED
    470 
    471 #define NS_IMPL_NSIMUTATIONOBSERVER_CORE_STUB(_class) \
    472  void _class::NodeWillBeDestroyed(nsINode* aNode) {}
    473 
    474 #define NS_IMPL_NSIMUTATIONOBSERVER_CONTENT(_class)                            \
    475  void _class::CharacterDataWillChange(                                        \
    476      nsIContent* aContent, const CharacterDataChangeInfo& aInfo) {}           \
    477  void _class::CharacterDataChanged(nsIContent* aContent,                      \
    478                                    const CharacterDataChangeInfo& aInfo) {}   \
    479  void _class::AttributeWillChange(mozilla::dom::Element* aElement,            \
    480                                   int32_t aNameSpaceID, nsAtom* aAttribute,   \
    481                                   AttrModType aModType) {}                    \
    482  void _class::AttributeChanged(mozilla::dom::Element* aElement,               \
    483                                int32_t aNameSpaceID, nsAtom* aAttribute,      \
    484                                AttrModType aModType,                          \
    485                                const nsAttrValue* aOldValue) {}               \
    486  void _class::ContentAppended(nsIContent* aFirstNewContent,                   \
    487                               const ContentAppendInfo&) {}                    \
    488  void _class::ContentInserted(nsIContent* aChild, const ContentInsertInfo&) { \
    489  }                                                                            \
    490  void _class::ContentWillBeRemoved(nsIContent* aChild,                        \
    491                                    const ContentRemoveInfo&) {}               \
    492  void _class::ParentChainChanged(nsIContent* aContent) {}                     \
    493  void _class::ARIAAttributeDefaultWillChange(mozilla::dom::Element* aElement, \
    494                                              nsAtom* aAttribute,              \
    495                                              AttrModType aModType) {}         \
    496  void _class::ARIAAttributeDefaultChanged(mozilla::dom::Element* aElement,    \
    497                                           nsAtom* aAttribute,                 \
    498                                           AttrModType aModType) {}
    499 
    500 #endif /* nsIMutationObserver_h */