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  * Base class for all element classes; this provides an implementation
9  * of DOM Core's nsIDOMElement, implements nsIContent, provides
10  * utility methods for subclasses, and so forth.
11  */
12 
13 #ifndef mozilla_dom_Element_h__
14 #define mozilla_dom_Element_h__
15 
16 #include "mozilla/dom/FragmentOrElement.h"  // for base class
17 #include "nsChangeHint.h"                   // for enum
18 #include "mozilla/EventStates.h"            // for member
19 #include "mozilla/ServoTypes.h"
20 #include "mozilla/dom/DirectionalityUtils.h"
21 #include "nsIDOMElement.h"
22 #include "nsILinkHandler.h"
23 #include "nsINodeList.h"
24 #include "nsNodeUtils.h"
25 #include "nsAttrAndChildArray.h"
26 #include "mozilla/FlushType.h"
27 #include "nsDOMAttributeMap.h"
28 #include "nsPresContext.h"
29 #include "mozilla/CORSMode.h"
30 #include "mozilla/Attributes.h"
31 #include "nsIScrollableFrame.h"
32 #include "mozilla/dom/Attr.h"
33 #include "nsISMILAttr.h"
34 #include "mozilla/dom/DOMRect.h"
35 #include "nsAttrValue.h"
36 #include "nsAttrValueInlines.h"
37 #include "mozilla/EventForwards.h"
38 #include "mozilla/dom/BindingDeclarations.h"
39 #include "mozilla/dom/DOMTokenListSupportedTokens.h"
40 #include "mozilla/dom/WindowBinding.h"
41 #include "mozilla/dom/ElementBinding.h"
42 #include "mozilla/dom/Nullable.h"
43 #include "mozilla/dom/PointerEventHandler.h"
44 #include "mozilla/UniquePtr.h"
45 #include "Units.h"
46 #include "DOMIntersectionObserver.h"
47 
48 class mozAutoDocUpdate;
49 class nsIFrame;
50 class nsIMozBrowserFrame;
51 class nsIURI;
52 class nsIScrollableFrame;
53 class nsAttrValueOrString;
54 class nsContentList;
55 class nsDOMTokenList;
56 struct nsRect;
57 class nsFocusManager;
58 class nsGlobalWindowInner;
59 class nsGlobalWindowOuter;
60 class nsDOMCSSAttributeDeclaration;
61 class nsISMILAttr;
62 class nsDocument;
63 class nsDOMStringMap;
64 
65 namespace mozilla {
66 class DeclarationBlock;
67 class TextEditor;
68 namespace dom {
69 struct AnimationFilter;
70 struct ScrollIntoViewOptions;
71 struct ScrollToOptions;
72 class DOMIntersectionObserver;
73 class DOMMatrixReadOnly;
74 class ElementOrCSSPseudoElement;
75 class UnrestrictedDoubleOrKeyframeAnimationOptions;
76 enum class CallerType : uint32_t;
77 typedef nsDataHashtable<nsRefPtrHashKey<DOMIntersectionObserver>, int32_t>
78     IntersectionObserverList;
79 }  // namespace dom
80 }  // namespace mozilla
81 
82 already_AddRefed<nsContentList> NS_GetContentList(nsINode* aRootNode,
83                                                   int32_t aMatchNameSpaceId,
84                                                   const nsAString& aTagname);
85 
86 #define ELEMENT_FLAG_BIT(n_) \
87   NODE_FLAG_BIT(NODE_TYPE_SPECIFIC_BITS_OFFSET + (n_))
88 
89 // Element-specific flags
90 enum {
91   // These four bits are shared by Gecko's and Servo's restyle systems for
92   // different purposes. They should not be accessed directly, and access to
93   // them should be properly guarded by asserts.
94   ELEMENT_SHARED_RESTYLE_BIT_1 = ELEMENT_FLAG_BIT(0),
95   ELEMENT_SHARED_RESTYLE_BIT_2 = ELEMENT_FLAG_BIT(1),
96   ELEMENT_SHARED_RESTYLE_BIT_3 = ELEMENT_FLAG_BIT(2),
97   ELEMENT_SHARED_RESTYLE_BIT_4 = ELEMENT_FLAG_BIT(3),
98 
99   ELEMENT_SHARED_RESTYLE_BITS =
100       ELEMENT_SHARED_RESTYLE_BIT_1 | ELEMENT_SHARED_RESTYLE_BIT_2 |
101       ELEMENT_SHARED_RESTYLE_BIT_3 | ELEMENT_SHARED_RESTYLE_BIT_4,
102 
103   // Whether this node has dirty descendants for Servo's style system.
104   ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO = ELEMENT_SHARED_RESTYLE_BIT_1,
105 
106   // Whether this node has dirty descendants for animation-only restyle for
107   // Servo's style system.
108   ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO =
109       ELEMENT_SHARED_RESTYLE_BIT_2,
110 
111   // Whether the element has been snapshotted due to attribute or state changes
112   // by the Servo restyle manager.
113   ELEMENT_HAS_SNAPSHOT = ELEMENT_SHARED_RESTYLE_BIT_3,
114 
115   // Whether the element has already handled its relevant snapshot.
116   //
117   // Used by the servo restyle process in order to accurately track whether the
118   // style of an element is up-to-date, even during the same restyle process.
119   ELEMENT_HANDLED_SNAPSHOT = ELEMENT_SHARED_RESTYLE_BIT_4,
120 
121   // Set if the element has a pending style change.
122   ELEMENT_HAS_PENDING_RESTYLE = ELEMENT_SHARED_RESTYLE_BIT_1,
123 
124   // Set if the element is a potential restyle root (that is, has a style
125   // change pending _and_ that style change will attempt to restyle
126   // descendants).
127   ELEMENT_IS_POTENTIAL_RESTYLE_ROOT = ELEMENT_SHARED_RESTYLE_BIT_2,
128 
129   // Set if the element has a pending animation-only style change as
130   // part of an animation-only style update (where we update styles from
131   // animation to the current refresh tick, but leave everything else as
132   // it was).
133   ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE = ELEMENT_SHARED_RESTYLE_BIT_3,
134 
135   // Set if the element is a potential animation-only restyle root (that
136   // is, has an animation-only style change pending _and_ that style
137   // change will attempt to restyle descendants).
138   ELEMENT_IS_POTENTIAL_ANIMATION_ONLY_RESTYLE_ROOT =
139       ELEMENT_SHARED_RESTYLE_BIT_4,
140 
141   // Set if this element has a pending restyle with an eRestyle_SomeDescendants
142   // restyle hint.
143   ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR = ELEMENT_FLAG_BIT(4),
144 
145   // Set if a child element has later-sibling restyle hint. This is needed for
146   // nsComputedDOMStyle to decide when should we need to flush style (only used
147   // in Gecko).
148   ELEMENT_HAS_CHILD_WITH_LATER_SIBLINGS_HINT = ELEMENT_FLAG_BIT(5),
149 
150   // Just the HAS_PENDING bits, for convenience
151   ELEMENT_PENDING_RESTYLE_FLAGS =
152       ELEMENT_HAS_PENDING_RESTYLE | ELEMENT_HAS_PENDING_ANIMATION_ONLY_RESTYLE,
153 
154   // Just the IS_POTENTIAL bits, for convenience
155   ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS =
156       ELEMENT_IS_POTENTIAL_RESTYLE_ROOT |
157       ELEMENT_IS_POTENTIAL_ANIMATION_ONLY_RESTYLE_ROOT,
158 
159   // All of the restyle bits together, for convenience.
160   ELEMENT_ALL_RESTYLE_FLAGS = ELEMENT_PENDING_RESTYLE_FLAGS |
161                               ELEMENT_POTENTIAL_RESTYLE_ROOT_FLAGS |
162                               ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR,
163 
164   // Remaining bits are for subclasses
165   ELEMENT_TYPE_SPECIFIC_BITS_OFFSET = NODE_TYPE_SPECIFIC_BITS_OFFSET + 6
166 };
167 
168 #undef ELEMENT_FLAG_BIT
169 
170 // Make sure we have space for our bits
171 ASSERT_NODE_FLAGS_SPACE(ELEMENT_TYPE_SPECIFIC_BITS_OFFSET);
172 
173 namespace mozilla {
174 enum class CSSPseudoElementType : uint8_t;
175 class EventChainPostVisitor;
176 class EventChainPreVisitor;
177 class EventChainVisitor;
178 class EventListenerManager;
179 class EventStateManager;
180 
181 namespace dom {
182 
183 struct CustomElementDefinition;
184 class Animation;
185 class CustomElementRegistry;
186 class Link;
187 class DOMRect;
188 class DOMRectList;
189 class Flex;
190 class Grid;
191 
192 // IID for the dom::Element interface
193 #define NS_ELEMENT_IID                               \
194   {                                                  \
195     0xc67ed254, 0xfd3b, 0x4b10, {                    \
196       0x96, 0xa2, 0xc5, 0x8b, 0x7b, 0x64, 0x97, 0xd1 \
197     }                                                \
198   }
199 
200 class Element : public FragmentOrElement {
201  public:
202 #ifdef MOZILLA_INTERNAL_API
Element(already_AddRefed<mozilla::dom::NodeInfo> & aNodeInfo)203   explicit Element(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
204       : FragmentOrElement(aNodeInfo), mState(NS_EVENT_STATE_MOZ_READONLY) {
205     MOZ_ASSERT(mNodeInfo->NodeType() == ELEMENT_NODE,
206                "Bad NodeType in aNodeInfo");
207     SetIsElement();
208   }
209 
~Element()210   ~Element() {
211     NS_ASSERTION(!HasServoData(), "expected ServoData to be cleared earlier");
212   }
213 
214 #endif  // MOZILLA_INTERNAL_API
215 
216   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ELEMENT_IID)
217 
218   NS_DECL_ADDSIZEOFEXCLUDINGTHIS
219 
220   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) override;
221 
222   /**
223    * Method to get the full state of this element.  See mozilla/EventStates.h
224    * for the possible bits that could be set here.
225    */
State()226   EventStates State() const {
227     // mState is maintained by having whoever might have changed it
228     // call UpdateState() or one of the other mState mutators.
229     return mState;
230   }
231 
232   /**
233    * Ask this element to update its state.  If aNotify is false, then
234    * state change notifications will not be dispatched; in that
235    * situation it is the caller's responsibility to dispatch them.
236    *
237    * In general, aNotify should only be false if we're guaranteed that
238    * the element can't have a frame no matter what its style is
239    * (e.g. if we're in the middle of adding it to the document or
240    * removing it from the document).
241    */
242   void UpdateState(bool aNotify);
243 
244   /**
245    * Method to update mState with link state information.  This does not notify.
246    */
247   void UpdateLinkState(EventStates aState);
248 
TabIndexDefault()249   virtual int32_t TabIndexDefault() { return -1; }
250 
251   /**
252    * Get tabIndex of this element. If not found, return TabIndexDefault.
253    */
254   int32_t TabIndex();
255 
256   /**
257    * Set tabIndex value to this element.
258    */
259   void SetTabIndex(int32_t aTabIndex, mozilla::ErrorResult& aError);
260 
261   /**
262    * Sets or unsets an XBL binding for this element. Setting a
263    * binding on an element that already has a binding will remove the
264    * old binding.
265    *
266    * @param aBinding The binding to bind to this content. If nullptr is
267    *        provided as the argument, then existing binding will be
268    *        removed.
269    *
270    * @param aOldBindingManager The old binding manager that contains
271    *                           this content if this content was adopted
272    *                           to another document.
273    */
274   void SetXBLBinding(nsXBLBinding* aBinding,
275                      nsBindingManager* aOldBindingManager = nullptr);
276 
277   /**
278    * Sets the ShadowRoot binding for this element. The contents of the
279    * binding is rendered in place of this node's children.
280    *
281    * @param aShadowRoot The ShadowRoot to be bound to this element.
282    */
283   void SetShadowRoot(ShadowRoot* aShadowRoot);
284 
285   /**
286    * Make focus on this element.
287    */
288   virtual void Focus(mozilla::ErrorResult& aError);
289 
290   /**
291    * Show blur and clear focus.
292    */
293   virtual void Blur(mozilla::ErrorResult& aError);
294 
295   /**
296    * The style state of this element. This is the real state of the element
297    * with any style locks applied for pseudo-class inspecting.
298    */
StyleState()299   EventStates StyleState() const {
300     if (!HasLockedStyleStates()) {
301       return mState;
302     }
303     return StyleStateFromLocks();
304   }
305 
306   /**
307    * StyleStateLocks is used to specify which event states should be locked,
308    * and whether they should be locked to on or off.
309    */
310   struct StyleStateLocks {
311     // mLocks tracks which event states should be locked.
312     EventStates mLocks;
313     // mValues tracks if the locked state should be on or off.
314     EventStates mValues;
315   };
316 
317   /**
318    * The style state locks applied to this element.
319    */
320   StyleStateLocks LockedStyleStates() const;
321 
322   /**
323    * Add a style state lock on this element.
324    * aEnabled is the value to lock the given state bits to.
325    */
326   void LockStyleStates(EventStates aStates, bool aEnabled);
327 
328   /**
329    * Remove a style state lock on this element.
330    */
331   void UnlockStyleStates(EventStates aStates);
332 
333   /**
334    * Clear all style state locks on this element.
335    */
336   void ClearStyleStateLocks();
337 
338   /**
339    * Accessors for the state of our dir attribute.
340    */
HasDirAuto()341   bool HasDirAuto() const {
342     return State().HasState(NS_EVENT_STATE_DIR_ATTR_LIKE_AUTO);
343   }
344 
345   /**
346    * Elements with dir="rtl" or dir="ltr".
347    */
HasFixedDir()348   bool HasFixedDir() const {
349     return State().HasAtLeastOneOfStates(NS_EVENT_STATE_DIR_ATTR_LTR |
350                                          NS_EVENT_STATE_DIR_ATTR_RTL);
351   }
352 
353   /**
354    * Get the inline style declaration, if any, for this element.
355    */
356   DeclarationBlock* GetInlineStyleDeclaration() const;
357 
358   /**
359    * Get the mapped attributes, if any, for this element.
360    */
361   const nsMappedAttributes* GetMappedAttributes() const;
362 
ClearMappedServoStyle()363   void ClearMappedServoStyle() { mAttrsAndChildren.ClearMappedServoStyle(); }
364 
365   /**
366    * Set the inline style declaration for this element. This will send
367    * an appropriate AttributeChanged notification if aNotify is true.
368    */
369   virtual nsresult SetInlineStyleDeclaration(DeclarationBlock* aDeclaration,
370                                              const nsAString* aSerialized,
371                                              bool aNotify);
372 
373   /**
374    * Get the SMIL override style declaration for this element. If the
375    * rule hasn't been created, this method simply returns null.
376    */
377   DeclarationBlock* GetSMILOverrideStyleDeclaration();
378 
379   /**
380    * Set the SMIL override style declaration for this element. If
381    * aNotify is true, this method will notify the document's pres
382    * context, so that the style changes will be noticed.
383    */
384   nsresult SetSMILOverrideStyleDeclaration(DeclarationBlock* aDeclaration,
385                                            bool aNotify);
386 
387   /**
388    * Returns a new nsISMILAttr that allows the caller to animate the given
389    * attribute on this element.
390    */
GetAnimatedAttr(int32_t aNamespaceID,nsAtom * aName)391   virtual UniquePtr<nsISMILAttr> GetAnimatedAttr(int32_t aNamespaceID,
392                                                  nsAtom* aName) {
393     return nullptr;
394   }
395 
396   /**
397    * Get the SMIL override style for this element. This is a style declaration
398    * that is applied *after* the inline style, and it can be used e.g. to store
399    * animated style values.
400    *
401    * Note: This method is analogous to the 'GetStyle' method in
402    * nsGenericHTMLElement and nsStyledElement.
403    */
404   nsDOMCSSAttributeDeclaration* GetSMILOverrideStyle();
405 
406   /**
407    * Returns if the element is labelable as per HTML specification.
408    */
409   virtual bool IsLabelable() const;
410 
411   /**
412    * Returns if the element is interactive content as per HTML specification.
413    */
414   virtual bool IsInteractiveHTMLContent(bool aIgnoreTabindex) const;
415 
416   /**
417    * Returns |this| as an nsIMozBrowserFrame* if the element is a frame or
418    * iframe element.
419    *
420    * We have this method, rather than using QI, so that we can use it during
421    * the servo traversal, where we can't QI DOM nodes because of non-thread-safe
422    * refcounts.
423    */
GetAsMozBrowserFrame()424   virtual nsIMozBrowserFrame* GetAsMozBrowserFrame() { return nullptr; }
425 
426   /**
427    * Is the attribute named stored in the mapped attributes?
428    *
429    * // XXXbz we use this method in HasAttributeDependentStyle, so svg
430    *    returns true here even though it stores nothing in the mapped
431    *    attributes.
432    */
433   NS_IMETHOD_(bool) IsAttributeMapped(const nsAtom* aAttribute) const;
434 
435   /**
436    * Get a hint that tells the style system what to do when
437    * an attribute on this node changes, if something needs to happen
438    * in response to the change *other* than the result of what is
439    * mapped into style data via any type of style rule.
440    */
441   virtual nsChangeHint GetAttributeChangeHint(const nsAtom* aAttribute,
442                                               int32_t aModType) const;
443 
444 #ifdef MOZ_OLD_STYLE
WalkContentStyleRules(nsRuleWalker * aRuleWalker)445   NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) { return NS_OK; }
446 #endif
447 
GetDirectionality()448   inline Directionality GetDirectionality() const {
449     if (HasFlag(NODE_HAS_DIRECTION_RTL)) {
450       return eDir_RTL;
451     }
452 
453     if (HasFlag(NODE_HAS_DIRECTION_LTR)) {
454       return eDir_LTR;
455     }
456 
457     return eDir_NotSet;
458   }
459 
SetDirectionality(Directionality aDir,bool aNotify)460   inline void SetDirectionality(Directionality aDir, bool aNotify) {
461     UnsetFlags(NODE_ALL_DIRECTION_FLAGS);
462     if (!aNotify) {
463       RemoveStatesSilently(DIRECTION_STATES);
464     }
465 
466     switch (aDir) {
467       case (eDir_RTL):
468         SetFlags(NODE_HAS_DIRECTION_RTL);
469         if (!aNotify) {
470           AddStatesSilently(NS_EVENT_STATE_RTL);
471         }
472         break;
473 
474       case (eDir_LTR):
475         SetFlags(NODE_HAS_DIRECTION_LTR);
476         if (!aNotify) {
477           AddStatesSilently(NS_EVENT_STATE_LTR);
478         }
479         break;
480 
481       default:
482         break;
483     }
484 
485     /*
486      * Only call UpdateState if we need to notify, because we call
487      * SetDirectionality for every element, and UpdateState is very very slow
488      * for some elements.
489      */
490     if (aNotify) {
491       UpdateState(true);
492     }
493   }
494 
495   bool GetBindingURL(nsIDocument* aDocument, css::URLValue** aResult);
496 
497   Directionality GetComputedDirectionality() const;
498 
499   static const uint32_t kAllServoDescendantBits =
500       ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO |
501       ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO |
502       NODE_DESCENDANTS_NEED_FRAMES;
503 
504   /**
505    * Notes that something in the given subtree of this element needs dirtying,
506    * and that all the relevant dirty bits have already been propagated up to the
507    * element.
508    *
509    * This is important because `NoteDirtyForServo` uses the dirty bits to reason
510    * about the shape of the tree, so we can't just call into there.
511    */
512   void NoteDirtySubtreeForServo();
513 
514   void NoteDirtyForServo();
515   void NoteAnimationOnlyDirtyForServo();
516   void NoteDescendantsNeedFramesForServo();
517 
HasDirtyDescendantsForServo()518   bool HasDirtyDescendantsForServo() const {
519     MOZ_ASSERT(IsStyledByServo());
520     return HasFlag(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
521   }
522 
SetHasDirtyDescendantsForServo()523   void SetHasDirtyDescendantsForServo() {
524     MOZ_ASSERT(IsStyledByServo());
525     SetFlags(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
526   }
527 
UnsetHasDirtyDescendantsForServo()528   void UnsetHasDirtyDescendantsForServo() {
529     MOZ_ASSERT(IsStyledByServo());
530     UnsetFlags(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO);
531   }
532 
HasAnimationOnlyDirtyDescendantsForServo()533   bool HasAnimationOnlyDirtyDescendantsForServo() const {
534     MOZ_ASSERT(IsStyledByServo());
535     return HasFlag(ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO);
536   }
537 
SetHasAnimationOnlyDirtyDescendantsForServo()538   void SetHasAnimationOnlyDirtyDescendantsForServo() {
539     MOZ_ASSERT(IsStyledByServo());
540     SetFlags(ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO);
541   }
542 
UnsetHasAnimationOnlyDirtyDescendantsForServo()543   void UnsetHasAnimationOnlyDirtyDescendantsForServo() {
544     MOZ_ASSERT(IsStyledByServo());
545     UnsetFlags(ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO);
546   }
547 
HasServoData()548   bool HasServoData() const { return !!mServoData.Get(); }
549 
ClearServoData()550   void ClearServoData() { ClearServoData(GetComposedDoc()); }
551   void ClearServoData(nsIDocument* aDocument);
552 
553   /**
554    * Gets the custom element data used by web components custom element.
555    * Custom element data is created at the first attempt to enqueue a callback.
556    *
557    * @return The custom element data or null if none.
558    */
GetCustomElementData()559   inline CustomElementData* GetCustomElementData() const {
560     const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
561     return slots ? slots->mCustomElementData.get() : nullptr;
562   }
563 
564   /**
565    * Sets the custom element data, ownership of the
566    * callback data is taken by this element.
567    *
568    * @param aData The custom element data.
569    */
570   void SetCustomElementData(CustomElementData* aData);
571 
572   /**
573    * Gets the custom element definition used by web components custom element.
574    *
575    * @return The custom element definition or null if element is not a custom
576    *         element or custom element is not defined yet.
577    */
578   CustomElementDefinition* GetCustomElementDefinition() const;
579 
580   /**
581    * Sets the custom element definition, called when custom element is created
582    * or upgraded.
583    *
584    * @param aDefinition The custom element definition.
585    */
586   void SetCustomElementDefinition(CustomElementDefinition* aDefinition);
587 
588  protected:
589   /**
590    * Method to get the _intrinsic_ content state of this element.  This is the
591    * state that is independent of the element's presentation.  To get the full
592    * content state, use State().  See mozilla/EventStates.h for
593    * the possible bits that could be set here.
594    */
595   virtual EventStates IntrinsicState() const;
596 
597   /**
598    * Method to add state bits.  This should be called from subclass
599    * constructors to set up our event state correctly at construction
600    * time and other places where we don't want to notify a state
601    * change.
602    */
AddStatesSilently(EventStates aStates)603   void AddStatesSilently(EventStates aStates) { mState |= aStates; }
604 
605   /**
606    * Method to remove state bits.  This should be called from subclass
607    * constructors to set up our event state correctly at construction
608    * time and other places where we don't want to notify a state
609    * change.
610    */
RemoveStatesSilently(EventStates aStates)611   void RemoveStatesSilently(EventStates aStates) { mState &= ~aStates; }
612 
613   already_AddRefed<ShadowRoot> AttachShadowInternal(ShadowRootMode,
614                                                     ErrorResult& aError);
615 
616  private:
617   // Need to allow the ESM, nsGlobalWindow, and the focus manager to
618   // set our state
619   friend class mozilla::EventStateManager;
620   friend class ::nsGlobalWindowInner;
621   friend class ::nsGlobalWindowOuter;
622   friend class ::nsFocusManager;
623 
624   // Allow CusomtElementRegistry to call AddStates.
625   friend class CustomElementRegistry;
626 
627   // Also need to allow Link to call UpdateLinkState.
628   friend class Link;
629 
630   void NotifyStateChange(EventStates aStates);
631 
632   void NotifyStyleStateChange(EventStates aStates);
633 
634   // Style state computed from element's state and style locks.
635   EventStates StyleStateFromLocks() const;
636 
637  protected:
638   // Methods for the ESM, nsGlobalWindow and focus manager to manage state bits.
639   // These will handle setting up script blockers when they notify, so no need
640   // to do it in the callers unless desired.  States passed here must only be
641   // those in EXTERNALLY_MANAGED_STATES.
AddStates(EventStates aStates)642   virtual void AddStates(EventStates aStates) {
643     NS_PRECONDITION(!aStates.HasAtLeastOneOfStates(INTRINSIC_STATES),
644                     "Should only be adding externally-managed states here");
645     AddStatesSilently(aStates);
646     NotifyStateChange(aStates);
647   }
RemoveStates(EventStates aStates)648   virtual void RemoveStates(EventStates aStates) {
649     NS_PRECONDITION(!aStates.HasAtLeastOneOfStates(INTRINSIC_STATES),
650                     "Should only be removing externally-managed states here");
651     RemoveStatesSilently(aStates);
652     NotifyStateChange(aStates);
653   }
ToggleStates(EventStates aStates,bool aNotify)654   virtual void ToggleStates(EventStates aStates, bool aNotify) {
655     NS_PRECONDITION(!aStates.HasAtLeastOneOfStates(INTRINSIC_STATES),
656                     "Should only be removing externally-managed states here");
657     mState ^= aStates;
658     if (aNotify) {
659       NotifyStateChange(aStates);
660     }
661   }
662 
663  public:
664   // Public methods to manage state bits in MANUALLY_MANAGED_STATES.
AddManuallyManagedStates(EventStates aStates)665   void AddManuallyManagedStates(EventStates aStates) {
666     MOZ_ASSERT(MANUALLY_MANAGED_STATES.HasAllStates(aStates),
667                "Should only be adding manually-managed states here");
668     AddStates(aStates);
669   }
RemoveManuallyManagedStates(EventStates aStates)670   void RemoveManuallyManagedStates(EventStates aStates) {
671     MOZ_ASSERT(MANUALLY_MANAGED_STATES.HasAllStates(aStates),
672                "Should only be removing manually-managed states here");
673     RemoveStates(aStates);
674   }
675 
676   virtual void UpdateEditableState(bool aNotify) override;
677 
678   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
679                               nsIContent* aBindingParent,
680                               bool aCompileEventHandlers) override;
681   virtual void UnbindFromTree(bool aDeep = true,
682                               bool aNullParent = true) override;
683 
684   /**
685    * Normalizes an attribute name and returns it as a nodeinfo if an attribute
686    * with that name exists. This method is intended for character case
687    * conversion if the content object is case insensitive (e.g. HTML). Returns
688    * the nodeinfo of the attribute with the specified name if one exists or
689    * null otherwise.
690    *
691    * @param aStr the unparsed attribute string
692    * @return the node info. May be nullptr.
693    */
694   already_AddRefed<mozilla::dom::NodeInfo> GetExistingAttrNameFromQName(
695       const nsAString& aStr) const;
696 
697   /**
698    * Helper for SetAttr/SetParsedAttr. This method will return true if aNotify
699    * is true or there are mutation listeners that must be triggered, the
700    * attribute is currently set, and the new value that is about to be set is
701    * different to the current value. As a perf optimization the new and old
702    * values will not actually be compared if we aren't notifying and we don't
703    * have mutation listeners (in which case it's cheap to just return false
704    * and let the caller go ahead and set the value).
705    * @param aOldValue [out] Set to the old value of the attribute, but only if
706    *   there are event listeners. If set, the type of aOldValue will be either
707    *   nsAttrValue::eString or nsAttrValue::eAtom.
708    * @param aModType [out] Set to MutationEventBinding::MODIFICATION or to
709    *   MutationEventBinding::ADDITION, but only if this helper returns true
710    * @param aHasListeners [out] Set to true if there are mutation event
711    *   listeners listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
712    * @param aOldValueSet [out] Indicates whether an old attribute value has been
713    *   stored in aOldValue. The bool will be set to true if a value was stored.
714    */
715   bool MaybeCheckSameAttrVal(int32_t aNamespaceID, nsAtom* aName,
716                              nsAtom* aPrefix, const nsAttrValueOrString& aValue,
717                              bool aNotify, nsAttrValue& aOldValue,
718                              uint8_t* aModType, bool* aHasListeners,
719                              bool* aOldValueSet);
720 
721   /**
722    * Notifies mutation listeners if aNotify is true, there are mutation
723    * listeners, and the attribute value is changing.
724    *
725    * @param aNamespaceID The namespace of the attribute
726    * @param aName The local name of the attribute
727    * @param aPrefix The prefix of the attribute
728    * @param aValue The value that the attribute is being changed to
729    * @param aNotify If true, mutation listeners will be notified if they exist
730    *   and the attribute value is changing
731    * @param aOldValue [out] Set to the old value of the attribute, but only if
732    *   there are event listeners. If set, the type of aOldValue will be either
733    *   nsAttrValue::eString or nsAttrValue::eAtom.
734    * @param aModType [out] Set to MutationEventBinding::MODIFICATION or to
735    *   MutationEventBinding::ADDITION, but only if this helper returns true
736    * @param aHasListeners [out] Set to true if there are mutation event
737    *   listeners listening for NS_EVENT_BITS_MUTATION_ATTRMODIFIED
738    * @param aOldValueSet [out] Indicates whether an old attribute value has been
739    *   stored in aOldValue. The bool will be set to true if a value was stored.
740    */
741   bool OnlyNotifySameValueSet(int32_t aNamespaceID, nsAtom* aName,
742                               nsAtom* aPrefix,
743                               const nsAttrValueOrString& aValue, bool aNotify,
744                               nsAttrValue& aOldValue, uint8_t* aModType,
745                               bool* aHasListeners, bool* aOldValueSet);
746 
747   /**
748    * Sets the class attribute to a value that contains no whitespace.
749    * Assumes that we are not notifying and that the attribute hasn't been
750    * set previously.
751    */
752   nsresult SetSingleClassFromParser(nsAtom* aSingleClassName);
753 
754   // aParsedValue receives the old value of the attribute. That's useful if
755   // either the input or output value of aParsedValue is StoresOwnData.
756   nsresult SetParsedAttr(int32_t aNameSpaceID, nsAtom* aName, nsAtom* aPrefix,
757                          nsAttrValue& aParsedValue, bool aNotify);
758   /**
759    * Get the current value of the attribute. This returns a form that is
760    * suitable for passing back into SetAttr.
761    *
762    * @param aNameSpaceID the namespace of the attr
763    * @param aName the name of the attr
764    * @param aResult the value (may legitimately be the empty string) [OUT]
765    * @returns true if the attribute was set (even when set to empty string)
766    *          false when not set.
767    * GetAttr is not inlined on purpose, to keep down codesize from all the
768    * inlined nsAttrValue bits for C++ callers.
769    */
770   bool GetAttr(int32_t aNameSpaceID, nsAtom* aName, nsAString& aResult) const;
771 
772   /**
773    * Determine if an attribute has been set (empty string or otherwise).
774    *
775    * @param aNameSpaceId the namespace id of the attribute
776    * @param aAttr the attribute name
777    * @return whether an attribute exists
778    */
779   inline bool HasAttr(int32_t aNameSpaceID, nsAtom* aName) const;
780   /**
781    * Test whether this Element's given attribute has the given value.  If the
782    * attribute is not set at all, this will return false.
783    *
784    * @param aNameSpaceID The namespace ID of the attribute.  Must not
785    *                     be kNameSpaceID_Unknown.
786    * @param aName The name atom of the attribute.  Must not be null.
787    * @param aValue The value to compare to.
788    * @param aCaseSensitive Whether to do a case-sensitive compare on the value.
789    */
790   inline bool AttrValueIs(int32_t aNameSpaceID, nsAtom* aName,
791                           const nsAString& aValue,
792                           nsCaseTreatment aCaseSensitive) const;
793 
794   /**
795    * Test whether this Element's given attribute has the given value.  If the
796    * attribute is not set at all, this will return false.
797    *
798    * @param aNameSpaceID The namespace ID of the attribute.  Must not
799    *                     be kNameSpaceID_Unknown.
800    * @param aName The name atom of the attribute.  Must not be null.
801    * @param aValue The value to compare to.  Must not be null.
802    * @param aCaseSensitive Whether to do a case-sensitive compare on the value.
803    */
804   bool AttrValueIs(int32_t aNameSpaceID, nsAtom* aName, nsAtom* aValue,
805                    nsCaseTreatment aCaseSensitive) const;
806 
807   enum { ATTR_MISSING = -1, ATTR_VALUE_NO_MATCH = -2 };
808   /**
809    * Check whether this Element's given attribute has one of a given list of
810    * values. If there is a match, we return the index in the list of the first
811    * matching value. If there was no attribute at all, then we return
812    * ATTR_MISSING. If there was an attribute but it didn't match, we return
813    * ATTR_VALUE_NO_MATCH. A non-negative result always indicates a match.
814    *
815    * @param aNameSpaceID The namespace ID of the attribute.  Must not
816    *                     be kNameSpaceID_Unknown.
817    * @param aName The name atom of the attribute.  Must not be null.
818    * @param aValues a nullptr-terminated array of pointers to atom values to
819    * test against.
820    * @param aCaseSensitive Whether to do a case-sensitive compare on the values.
821    * @return ATTR_MISSING, ATTR_VALUE_NO_MATCH or the non-negative index
822    * indicating the first value of aValues that matched
823    */
824   typedef nsStaticAtom* const* const AttrValuesArray;
825   int32_t FindAttrValueIn(int32_t aNameSpaceID, nsAtom* aName,
826                           AttrValuesArray* aValues,
827                           nsCaseTreatment aCaseSensitive) const;
828 
829   /**
830    * Set attribute values. All attribute values are assumed to have a
831    * canonical string representation that can be used for these
832    * methods. The SetAttr method is assumed to perform a translation
833    * of the canonical form into the underlying content specific
834    * form.
835    *
836    * @param aNameSpaceID the namespace of the attribute
837    * @param aName the name of the attribute
838    * @param aValue the value to set
839    * @param aNotify specifies how whether or not the document should be
840    *        notified of the attribute change.
841    */
SetAttr(int32_t aNameSpaceID,nsAtom * aName,const nsAString & aValue,bool aNotify)842   nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName, const nsAString& aValue,
843                    bool aNotify) {
844     return SetAttr(aNameSpaceID, aName, nullptr, aValue, aNotify);
845   }
SetAttr(int32_t aNameSpaceID,nsAtom * aName,nsAtom * aPrefix,const nsAString & aValue,bool aNotify)846   nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName, nsAtom* aPrefix,
847                    const nsAString& aValue, bool aNotify) {
848     return SetAttr(aNameSpaceID, aName, aPrefix, aValue, nullptr, aNotify);
849   }
SetAttr(int32_t aNameSpaceID,nsAtom * aName,const nsAString & aValue,nsIPrincipal * aTriggeringPrincipal,bool aNotify)850   nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName, const nsAString& aValue,
851                    nsIPrincipal* aTriggeringPrincipal, bool aNotify) {
852     return SetAttr(aNameSpaceID, aName, nullptr, aValue, aTriggeringPrincipal,
853                    aNotify);
854   }
855 
856   /**
857    * Set attribute values. All attribute values are assumed to have a
858    * canonical String representation that can be used for these
859    * methods. The SetAttr method is assumed to perform a translation
860    * of the canonical form into the underlying content specific
861    * form.
862    *
863    * @param aNameSpaceID the namespace of the attribute
864    * @param aName the name of the attribute
865    * @param aPrefix the prefix of the attribute
866    * @param aValue the value to set
867    * @param aMaybeScriptedPrincipal the principal of the scripted caller
868    * responsible for setting the attribute, or null if no scripted caller can be
869    *        determined. A null value here does not guarantee that there is no
870    *        scripted caller, but a non-null value does guarantee that a scripted
871    *        caller with the given principal is directly responsible for the
872    *        attribute change.
873    * @param aNotify specifies how whether or not the document should be
874    *        notified of the attribute change.
875    */
876   nsresult SetAttr(int32_t aNameSpaceID, nsAtom* aName, nsAtom* aPrefix,
877                    const nsAString& aValue,
878                    nsIPrincipal* aMaybeScriptedPrincipal, bool aNotify);
879 
880   /**
881    * Remove an attribute so that it is no longer explicitly specified.
882    *
883    * @param aNameSpaceID the namespace id of the attribute
884    * @param aAttr the name of the attribute to unset
885    * @param aNotify specifies whether or not the document should be
886    * notified of the attribute change
887    */
888   nsresult UnsetAttr(int32_t aNameSpaceID, nsAtom* aAttribute, bool aNotify);
889 
890   /**
891    * Get the namespace / name / prefix of a given attribute.
892    *
893    * @param   aIndex the index of the attribute name
894    * @returns The name at the given index, or null if the index is
895    *          out-of-bounds.
896    * @note    The document returned by NodeInfo()->GetDocument() (if one is
897    *          present) is *not* necessarily the owner document of the element.
898    * @note    The pointer returned by this function is only valid until the
899    *          next call of either GetAttrNameAt or SetAttr on the element.
900    */
GetAttrNameAt(uint32_t aIndex)901   const nsAttrName* GetAttrNameAt(uint32_t aIndex) const {
902     return mAttrsAndChildren.GetSafeAttrNameAt(aIndex);
903   }
904 
905   /**
906    * Gets the attribute info (name and value) for this element at a given index.
907    */
GetAttrInfoAt(uint32_t aIndex)908   BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const {
909     if (aIndex >= mAttrsAndChildren.AttrCount()) {
910       return BorrowedAttrInfo(nullptr, nullptr);
911     }
912 
913     return mAttrsAndChildren.AttrInfoAt(aIndex);
914   }
915 
916   /**
917    * Get the number of all specified attributes.
918    *
919    * @return the number of attributes
920    */
GetAttrCount()921   uint32_t GetAttrCount() const { return mAttrsAndChildren.AttrCount(); }
922 
923   virtual bool IsNodeOfType(uint32_t aFlags) const override;
924 
925   /**
926    * Get the class list of this element (this corresponds to the value of the
927    * class attribute).  This may be null if there are no classes, but that's not
928    * guaranteed (e.g. we could have class="").
929    */
GetClasses()930   const nsAttrValue* GetClasses() const {
931     if (MayHaveClass()) {
932       return DoGetClasses();
933     }
934     return nullptr;
935   }
936 
937   /**
938    * Hook for implementing GetClasses. This should only be called if the
939    * ElementMayHaveClass flag is set.
940    *
941    * Public only because Servo needs to call it too, and it ensures the
942    * precondition before calling this.
943    */
DoGetClasses()944   const nsAttrValue* DoGetClasses() const {
945     MOZ_ASSERT(MayHaveClass(), "Unexpected call");
946     if (IsSVGElement()) {
947       if (const nsAttrValue* value = GetSVGAnimatedClass()) {
948         return value;
949       }
950     }
951 
952     return GetParsedAttr(nsGkAtoms::_class);
953   }
954 
955 #ifdef DEBUG
956   virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override {
957     List(out, aIndent, EmptyCString());
958   }
959   virtual void DumpContent(FILE* out, int32_t aIndent,
960                            bool aDumpAll) const override;
961   void List(FILE* out, int32_t aIndent, const nsCString& aPrefix) const;
962   void ListAttributes(FILE* out) const;
963 #endif
964 
965   void Describe(nsAString& aOutDescription) const override;
966 
967   /*
968    * Attribute Mapping Helpers
969    */
970   struct MappedAttributeEntry {
971     nsStaticAtom** attribute;
972   };
973 
974   /**
975    * A common method where you can just pass in a list of maps to check
976    * for attribute dependence. Most implementations of
977    * IsAttributeMapped should use this function as a default
978    * handler.
979    */
980   template <size_t N>
FindAttributeDependence(const nsAtom * aAttribute,const MappedAttributeEntry * const (& aMaps)[N])981   static bool FindAttributeDependence(
982       const nsAtom* aAttribute, const MappedAttributeEntry* const (&aMaps)[N]) {
983     return FindAttributeDependence(aAttribute, aMaps, N);
984   }
985 
986   static nsStaticAtom*** HTMLSVGPropertiesToTraverseAndUnlink();
987 
988  private:
989   void DescribeAttribute(uint32_t index, nsAString& aOutDescription) const;
990 
991   static bool FindAttributeDependence(const nsAtom* aAttribute,
992                                       const MappedAttributeEntry* const aMaps[],
993                                       uint32_t aMapCount);
994 
995  protected:
GetAttr(int32_t aNameSpaceID,nsAtom * aName,DOMString & aResult)996   inline bool GetAttr(int32_t aNameSpaceID, nsAtom* aName,
997                       DOMString& aResult) const {
998     NS_ASSERTION(nullptr != aName, "must have attribute name");
999     NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown,
1000                  "must have a real namespace ID!");
1001     MOZ_ASSERT(aResult.IsEmpty(), "Should have empty string coming in");
1002     const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
1003     if (val) {
1004       val->ToString(aResult);
1005       return true;
1006     }
1007     // else DOMString comes pre-emptied.
1008     return false;
1009   }
1010 
1011  public:
HasAttrs()1012   bool HasAttrs() const { return mAttrsAndChildren.HasAttrs(); }
1013 
GetAttr(const nsAString & aName,DOMString & aResult)1014   inline bool GetAttr(const nsAString& aName, DOMString& aResult) const {
1015     MOZ_ASSERT(aResult.IsEmpty(), "Should have empty string coming in");
1016     const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName);
1017     if (val) {
1018       val->ToString(aResult);
1019       return true;
1020     }
1021     // else DOMString comes pre-emptied.
1022     return false;
1023   }
1024 
GetTagName(nsAString & aTagName)1025   void GetTagName(nsAString& aTagName) const { aTagName = NodeName(); }
GetId(nsAString & aId)1026   void GetId(nsAString& aId) const {
1027     GetAttr(kNameSpaceID_None, nsGkAtoms::id, aId);
1028   }
GetId(DOMString & aId)1029   void GetId(DOMString& aId) const {
1030     GetAttr(kNameSpaceID_None, nsGkAtoms::id, aId);
1031   }
SetId(const nsAString & aId)1032   void SetId(const nsAString& aId) {
1033     SetAttr(kNameSpaceID_None, nsGkAtoms::id, aId, true);
1034   }
GetClassName(nsAString & aClassName)1035   void GetClassName(nsAString& aClassName) {
1036     GetAttr(kNameSpaceID_None, nsGkAtoms::_class, aClassName);
1037   }
GetClassName(DOMString & aClassName)1038   void GetClassName(DOMString& aClassName) {
1039     GetAttr(kNameSpaceID_None, nsGkAtoms::_class, aClassName);
1040   }
SetClassName(const nsAString & aClassName)1041   void SetClassName(const nsAString& aClassName) {
1042     SetAttr(kNameSpaceID_None, nsGkAtoms::_class, aClassName, true);
1043   }
1044 
1045   nsDOMTokenList* ClassList();
Attributes()1046   nsDOMAttributeMap* Attributes() {
1047     nsDOMSlots* slots = DOMSlots();
1048     if (!slots->mAttributeMap) {
1049       slots->mAttributeMap = new nsDOMAttributeMap(this);
1050     }
1051 
1052     return slots->mAttributeMap;
1053   }
1054 
1055   void GetAttributeNames(nsTArray<nsString>& aResult);
1056 
GetAttribute(const nsAString & aName,nsAString & aReturn)1057   void GetAttribute(const nsAString& aName, nsAString& aReturn) {
1058     DOMString str;
1059     GetAttribute(aName, str);
1060     str.ToString(aReturn);
1061   }
1062 
1063   void GetAttribute(const nsAString& aName, DOMString& aReturn);
1064   void GetAttributeNS(const nsAString& aNamespaceURI,
1065                       const nsAString& aLocalName, nsAString& aReturn);
1066   void SetAttribute(const nsAString& aName, const nsAString& aValue,
1067                     nsIPrincipal* aTriggeringPrincipal, ErrorResult& aError);
1068   void SetAttributeNS(const nsAString& aNamespaceURI,
1069                       const nsAString& aLocalName, const nsAString& aValue,
1070                       nsIPrincipal* aTriggeringPrincipal, ErrorResult& aError);
SetAttribute(const nsAString & aName,const nsAString & aValue,ErrorResult & aError)1071   void SetAttribute(const nsAString& aName, const nsAString& aValue,
1072                     ErrorResult& aError) {
1073     SetAttribute(aName, aValue, nullptr, aError);
1074   }
1075 
1076   void RemoveAttribute(const nsAString& aName, ErrorResult& aError);
1077   void RemoveAttributeNS(const nsAString& aNamespaceURI,
1078                          const nsAString& aLocalName, ErrorResult& aError);
HasAttribute(const nsAString & aName)1079   bool HasAttribute(const nsAString& aName) const {
1080     return InternalGetAttrNameFromQName(aName) != nullptr;
1081   }
1082   bool HasAttributeNS(const nsAString& aNamespaceURI,
1083                       const nsAString& aLocalName) const;
HasAttributes()1084   bool HasAttributes() const { return HasAttrs(); }
1085   Element* Closest(const nsAString& aSelector, ErrorResult& aResult);
1086   bool Matches(const nsAString& aSelector, ErrorResult& aError);
1087   already_AddRefed<nsIHTMLCollection> GetElementsByTagName(
1088       const nsAString& aQualifiedName);
1089   already_AddRefed<nsIHTMLCollection> GetElementsByTagNameNS(
1090       const nsAString& aNamespaceURI, const nsAString& aLocalName,
1091       ErrorResult& aError);
1092   already_AddRefed<nsIHTMLCollection> GetElementsByClassName(
1093       const nsAString& aClassNames);
1094 
GetPseudoElementType()1095   CSSPseudoElementType GetPseudoElementType() const {
1096     nsresult rv = NS_OK;
1097     auto raw = GetProperty(nsGkAtoms::pseudoProperty, &rv);
1098     if (rv == NS_PROPTABLE_PROP_NOT_THERE) {
1099       return CSSPseudoElementType::NotPseudo;
1100     }
1101     return CSSPseudoElementType(reinterpret_cast<uintptr_t>(raw));
1102   }
1103 
SetPseudoElementType(CSSPseudoElementType aPseudo)1104   void SetPseudoElementType(CSSPseudoElementType aPseudo) {
1105     static_assert(sizeof(CSSPseudoElementType) <= sizeof(uintptr_t),
1106                   "Need to be able to store this in a void*");
1107     MOZ_ASSERT(aPseudo != CSSPseudoElementType::NotPseudo);
1108     SetProperty(nsGkAtoms::pseudoProperty, reinterpret_cast<void*>(aPseudo));
1109   }
1110 
1111   /**
1112    * Return an array of all elements in the subtree rooted at this
1113    * element that are styled as grid containers. This includes
1114    * elements that don't actually generate any frames (by virtue of
1115    * being in a 'display:none' subtree), but this does not include
1116    * pseudo-elements.
1117    */
1118   void GetElementsWithGrid(nsTArray<RefPtr<Element>>& aElements);
1119 
1120  private:
1121   /**
1122    * Define a general matching function that can be passed to
1123    * GetElementsByMatching(). Each Element being considered is
1124    * passed in.
1125    */
1126   typedef bool (*nsElementMatchFunc)(Element* aElement);
1127 
1128   void GetElementsByMatching(nsElementMatchFunc aFunc,
1129                              nsTArray<RefPtr<Element>>& aElements);
1130 
1131   /**
1132    * Implement the algorithm specified at
1133    * https://dom.spec.whatwg.org/#insert-adjacent for both
1134    * |insertAdjacentElement()| and |insertAdjacentText()| APIs.
1135    */
1136   nsINode* InsertAdjacent(const nsAString& aWhere, nsINode* aNode,
1137                           ErrorResult& aError);
1138 
1139  public:
1140   Element* InsertAdjacentElement(const nsAString& aWhere, Element& aElement,
1141                                  ErrorResult& aError);
1142 
1143   void InsertAdjacentText(const nsAString& aWhere, const nsAString& aData,
1144                           ErrorResult& aError);
1145 
SetPointerCapture(int32_t aPointerId,ErrorResult & aError)1146   void SetPointerCapture(int32_t aPointerId, ErrorResult& aError) {
1147     bool activeState = false;
1148     if (!PointerEventHandler::GetPointerInfo(aPointerId, activeState)) {
1149       aError.Throw(NS_ERROR_DOM_INVALID_POINTER_ERR);
1150       return;
1151     }
1152     if (!IsInUncomposedDoc()) {
1153       aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1154       return;
1155     }
1156     if (OwnerDoc()->GetPointerLockElement()) {
1157       // Throw an exception 'InvalidStateError' while the page has a locked
1158       // element.
1159       aError.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
1160       return;
1161     }
1162     if (!activeState) {
1163       return;
1164     }
1165     PointerEventHandler::SetPointerCaptureById(aPointerId, this);
1166   }
ReleasePointerCapture(int32_t aPointerId,ErrorResult & aError)1167   void ReleasePointerCapture(int32_t aPointerId, ErrorResult& aError) {
1168     bool activeState = false;
1169     if (!PointerEventHandler::GetPointerInfo(aPointerId, activeState)) {
1170       aError.Throw(NS_ERROR_DOM_INVALID_POINTER_ERR);
1171       return;
1172     }
1173     if (HasPointerCapture(aPointerId)) {
1174       PointerEventHandler::ReleasePointerCaptureById(aPointerId);
1175     }
1176   }
HasPointerCapture(long aPointerId)1177   bool HasPointerCapture(long aPointerId) {
1178     PointerCaptureInfo* pointerCaptureInfo =
1179         PointerEventHandler::GetPointerCaptureInfo(aPointerId);
1180     if (pointerCaptureInfo && pointerCaptureInfo->mPendingContent == this) {
1181       return true;
1182     }
1183     return false;
1184   }
SetCapture(bool aRetargetToElement)1185   void SetCapture(bool aRetargetToElement) {
1186     // If there is already an active capture, ignore this request. This would
1187     // occur if a splitter, frame resizer, etc had already captured and we don't
1188     // want to override those.
1189     if (!nsIPresShell::GetCapturingContent()) {
1190       nsIPresShell::SetCapturingContent(
1191           this, CAPTURE_PREVENTDRAG |
1192                     (aRetargetToElement ? CAPTURE_RETARGETTOELEMENT : 0));
1193     }
1194   }
1195 
SetCaptureAlways(bool aRetargetToElement)1196   void SetCaptureAlways(bool aRetargetToElement) {
1197     nsIPresShell::SetCapturingContent(
1198         this, CAPTURE_PREVENTDRAG | CAPTURE_IGNOREALLOWED |
1199                   (aRetargetToElement ? CAPTURE_RETARGETTOELEMENT : 0));
1200   }
1201 
ReleaseCapture()1202   void ReleaseCapture() {
1203     if (nsIPresShell::GetCapturingContent() == this) {
1204       nsIPresShell::SetCapturingContent(nullptr, 0);
1205     }
1206   }
1207 
1208   void RequestFullscreen(CallerType aCallerType, ErrorResult& aError);
1209   void RequestPointerLock(CallerType aCallerType);
1210   Attr* GetAttributeNode(const nsAString& aName);
1211   already_AddRefed<Attr> SetAttributeNode(Attr& aNewAttr, ErrorResult& aError);
1212   already_AddRefed<Attr> RemoveAttributeNode(Attr& aOldAttr,
1213                                              ErrorResult& aError);
1214   Attr* GetAttributeNodeNS(const nsAString& aNamespaceURI,
1215                            const nsAString& aLocalName);
1216   already_AddRefed<Attr> SetAttributeNodeNS(Attr& aNewAttr,
1217                                             ErrorResult& aError);
1218 
1219   MOZ_CAN_RUN_SCRIPT already_AddRefed<DOMRectList> GetClientRects();
1220   MOZ_CAN_RUN_SCRIPT already_AddRefed<DOMRect> GetBoundingClientRect();
1221 
1222   // Shadow DOM v1
1223   already_AddRefed<ShadowRoot> AttachShadow(const ShadowRootInit& aInit,
1224                                             ErrorResult& aError);
1225   ShadowRoot* GetShadowRootByMode() const;
1226   void SetSlot(const nsAString& aName, ErrorResult& aError);
1227   void GetSlot(nsAString& aName);
1228 
1229   // [deprecated] Shadow DOM v0
1230   already_AddRefed<ShadowRoot> CreateShadowRoot(ErrorResult& aError);
1231 
GetShadowRoot()1232   ShadowRoot* GetShadowRoot() const {
1233     const nsExtendedDOMSlots* slots = GetExistingExtendedDOMSlots();
1234     return slots ? slots->mShadowRoot.get() : nullptr;
1235   }
1236 
1237  private:
1238   void ScrollIntoView(const ScrollIntoViewOptions& aOptions);
1239 
1240  public:
1241   void ScrollIntoView(const BooleanOrScrollIntoViewOptions& aObject);
1242   MOZ_CAN_RUN_SCRIPT void Scroll(double aXScroll, double aYScroll);
1243   MOZ_CAN_RUN_SCRIPT void Scroll(const ScrollToOptions& aOptions);
1244   MOZ_CAN_RUN_SCRIPT void ScrollTo(double aXScroll, double aYScroll);
1245   MOZ_CAN_RUN_SCRIPT void ScrollTo(const ScrollToOptions& aOptions);
1246   MOZ_CAN_RUN_SCRIPT void ScrollBy(double aXScrollDif, double aYScrollDif);
1247   MOZ_CAN_RUN_SCRIPT void ScrollBy(const ScrollToOptions& aOptions);
1248   /* Scrolls without flushing the layout.
1249    * aDx is the x offset, aDy the y offset in CSS pixels.
1250    * Returns true if we actually scrolled.
1251    */
1252   MOZ_CAN_RUN_SCRIPT bool ScrollByNoFlush(int32_t aDx, int32_t aDy);
1253   MOZ_CAN_RUN_SCRIPT int32_t ScrollTop();
1254   MOZ_CAN_RUN_SCRIPT void SetScrollTop(int32_t aScrollTop);
1255   MOZ_CAN_RUN_SCRIPT int32_t ScrollLeft();
1256   MOZ_CAN_RUN_SCRIPT void SetScrollLeft(int32_t aScrollLeft);
1257   MOZ_CAN_RUN_SCRIPT int32_t ScrollWidth();
1258   MOZ_CAN_RUN_SCRIPT int32_t ScrollHeight();
1259   MOZ_CAN_RUN_SCRIPT void MozScrollSnap();
ClientTop()1260   MOZ_CAN_RUN_SCRIPT int32_t ClientTop() {
1261     return nsPresContext::AppUnitsToIntCSSPixels(GetClientAreaRect().y);
1262   }
ClientLeft()1263   MOZ_CAN_RUN_SCRIPT int32_t ClientLeft() {
1264     return nsPresContext::AppUnitsToIntCSSPixels(GetClientAreaRect().x);
1265   }
ClientWidth()1266   MOZ_CAN_RUN_SCRIPT int32_t ClientWidth() {
1267     return nsPresContext::AppUnitsToIntCSSPixels(GetClientAreaRect().Width());
1268   }
ClientHeight()1269   MOZ_CAN_RUN_SCRIPT int32_t ClientHeight() {
1270     return nsPresContext::AppUnitsToIntCSSPixels(GetClientAreaRect().Height());
1271   }
ScrollTopMin()1272   MOZ_CAN_RUN_SCRIPT int32_t ScrollTopMin() {
1273     nsIScrollableFrame* sf = GetScrollFrame();
1274     return sf ? nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollRange().y)
1275               : 0;
1276   }
ScrollTopMax()1277   MOZ_CAN_RUN_SCRIPT int32_t ScrollTopMax() {
1278     nsIScrollableFrame* sf = GetScrollFrame();
1279     return sf ? nsPresContext::AppUnitsToIntCSSPixels(
1280                     sf->GetScrollRange().YMost())
1281               : 0;
1282   }
ScrollLeftMin()1283   MOZ_CAN_RUN_SCRIPT int32_t ScrollLeftMin() {
1284     nsIScrollableFrame* sf = GetScrollFrame();
1285     return sf ? nsPresContext::AppUnitsToIntCSSPixels(sf->GetScrollRange().x)
1286               : 0;
1287   }
ScrollLeftMax()1288   MOZ_CAN_RUN_SCRIPT int32_t ScrollLeftMax() {
1289     nsIScrollableFrame* sf = GetScrollFrame();
1290     return sf ? nsPresContext::AppUnitsToIntCSSPixels(
1291                     sf->GetScrollRange().XMost())
1292               : 0;
1293   }
1294 
1295   already_AddRefed<Flex> GetAsFlexContainer();
1296   void GetGridFragments(nsTArray<RefPtr<Grid>>& aResult);
1297 
1298   already_AddRefed<DOMMatrixReadOnly> GetTransformToAncestor(
1299       Element& aAncestor);
1300   already_AddRefed<DOMMatrixReadOnly> GetTransformToParent();
1301   already_AddRefed<DOMMatrixReadOnly> GetTransformToViewport();
1302 
1303   already_AddRefed<Animation> Animate(
1304       JSContext* aContext, JS::Handle<JSObject*> aKeyframes,
1305       const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
1306       ErrorResult& aError);
1307 
1308   // A helper method that factors out the common functionality needed by
1309   // Element::Animate and CSSPseudoElement::Animate
1310   static already_AddRefed<Animation> Animate(
1311       const Nullable<ElementOrCSSPseudoElement>& aTarget, JSContext* aContext,
1312       JS::Handle<JSObject*> aKeyframes,
1313       const UnrestrictedDoubleOrKeyframeAnimationOptions& aOptions,
1314       ErrorResult& aError);
1315 
1316   // Note: GetAnimations will flush style while GetAnimationsUnsorted won't.
1317   // Callers must keep this element alive because flushing style may destroy
1318   // this element.
1319   void GetAnimations(const AnimationFilter& filter,
1320                      nsTArray<RefPtr<Animation>>& aAnimations);
1321   static void GetAnimationsUnsorted(Element* aElement,
1322                                     CSSPseudoElementType aPseudoType,
1323                                     nsTArray<RefPtr<Animation>>& aAnimations);
1324 
1325   NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML);
1326   virtual void SetInnerHTML(const nsAString& aInnerHTML,
1327                             nsIPrincipal* aSubjectPrincipal,
1328                             ErrorResult& aError);
1329   void UnsafeSetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError);
1330   void GetOuterHTML(nsAString& aOuterHTML);
1331   void SetOuterHTML(const nsAString& aOuterHTML, ErrorResult& aError);
1332   void InsertAdjacentHTML(const nsAString& aPosition, const nsAString& aText,
1333                           ErrorResult& aError);
1334 
1335   //----------------------------------------
1336 
1337   /**
1338    * Add a script event listener with the given event handler name
1339    * (like onclick) and with the value as JS
1340    * @param aEventName the event listener name
1341    * @param aValue the JS to attach
1342    * @param aDefer indicates if deferred execution is allowed
1343    */
1344   nsresult SetEventHandler(nsAtom* aEventName, const nsAString& aValue,
1345                            bool aDefer = true);
1346 
1347   /**
1348    * Do whatever needs to be done when the mouse leaves a link
1349    */
1350   nsresult LeaveLink(nsPresContext* aPresContext);
1351 
1352   static bool ShouldBlur(nsIContent* aContent);
1353 
1354   /**
1355    * Method to create and dispatch a left-click event loosely based on
1356    * aSourceEvent. If aFullDispatch is true, the event will be dispatched
1357    * through the full dispatching of the presshell of the aPresContext; if it's
1358    * false the event will be dispatched only as a DOM event.
1359    * If aPresContext is nullptr, this does nothing.
1360    *
1361    * @param aFlags      Extra flags for the dispatching event.  The true flags
1362    *                    will be respected.
1363    */
1364   static nsresult DispatchClickEvent(nsPresContext* aPresContext,
1365                                      WidgetInputEvent* aSourceEvent,
1366                                      nsIContent* aTarget, bool aFullDispatch,
1367                                      const EventFlags* aFlags,
1368                                      nsEventStatus* aStatus);
1369 
1370   /**
1371    * Method to dispatch aEvent to aTarget. If aFullDispatch is true, the event
1372    * will be dispatched through the full dispatching of the presshell of the
1373    * aPresContext; if it's false the event will be dispatched only as a DOM
1374    * event.
1375    * If aPresContext is nullptr, this does nothing.
1376    */
1377   using nsIContent::DispatchEvent;
1378   static nsresult DispatchEvent(nsPresContext* aPresContext,
1379                                 WidgetEvent* aEvent, nsIContent* aTarget,
1380                                 bool aFullDispatch, nsEventStatus* aStatus);
1381 
1382   /**
1383    * Get the primary frame for this content with flushing
1384    *
1385    * @param aType the kind of flush to do, typically FlushType::Frames or
1386    *              FlushType::Layout
1387    * @return the primary frame
1388    */
1389   nsIFrame* GetPrimaryFrame(FlushType aType);
1390   // Work around silly C++ name hiding stuff
GetPrimaryFrame()1391   nsIFrame* GetPrimaryFrame() const { return nsIContent::GetPrimaryFrame(); }
1392 
GetParsedAttr(nsAtom * aAttr)1393   const nsAttrValue* GetParsedAttr(nsAtom* aAttr) const {
1394     return mAttrsAndChildren.GetAttr(aAttr);
1395   }
1396 
GetParsedAttr(nsAtom * aAttr,int32_t aNameSpaceID)1397   const nsAttrValue* GetParsedAttr(nsAtom* aAttr, int32_t aNameSpaceID) const {
1398     return mAttrsAndChildren.GetAttr(aAttr, aNameSpaceID);
1399   }
1400 
1401   /**
1402    * Returns the attribute map, if there is one.
1403    *
1404    * @return existing attribute map or nullptr.
1405    */
GetAttributeMap()1406   nsDOMAttributeMap* GetAttributeMap() {
1407     nsDOMSlots* slots = GetExistingDOMSlots();
1408 
1409     return slots ? slots->mAttributeMap.get() : nullptr;
1410   }
1411 
RecompileScriptEventListeners()1412   virtual void RecompileScriptEventListeners() {}
1413 
1414   /**
1415    * Get the attr info for the given namespace ID and attribute name.  The
1416    * namespace ID must not be kNameSpaceID_Unknown and the name must not be
1417    * null.  Note that this can only return info on attributes that actually
1418    * live on this element (and is only virtual to handle XUL prototypes).  That
1419    * is, this should only be called from methods that only care about attrs
1420    * that effectively live in mAttrsAndChildren.
1421    */
GetAttrInfo(int32_t aNamespaceID,nsAtom * aName)1422   BorrowedAttrInfo GetAttrInfo(int32_t aNamespaceID, nsAtom* aName) const {
1423     NS_ASSERTION(aName, "must have attribute name");
1424     NS_ASSERTION(aNamespaceID != kNameSpaceID_Unknown,
1425                  "must have a real namespace ID!");
1426 
1427     int32_t index = mAttrsAndChildren.IndexOfAttr(aName, aNamespaceID);
1428     if (index < 0) {
1429       return BorrowedAttrInfo(nullptr, nullptr);
1430     }
1431 
1432     return mAttrsAndChildren.AttrInfoAt(index);
1433   }
1434 
1435   /**
1436    * Called when we have been adopted, and the information of the
1437    * node has been changed.
1438    *
1439    * The new document can be reached via OwnerDoc().
1440    *
1441    * If you override this method,
1442    * please call up to the parent NodeInfoChanged.
1443    *
1444    * If you change this, change also the similar method in Link.
1445    */
NodeInfoChanged(nsIDocument * aOldDoc)1446   virtual void NodeInfoChanged(nsIDocument* aOldDoc) {}
1447 
1448   /**
1449    * Parse a string into an nsAttrValue for a CORS attribute.  This
1450    * never fails.  The resulting value is an enumerated value whose
1451    * GetEnumValue() returns one of the above constants.
1452    */
1453   static void ParseCORSValue(const nsAString& aValue, nsAttrValue& aResult);
1454 
1455   /**
1456    * Return the CORS mode for a given string
1457    */
1458   static CORSMode StringToCORSMode(const nsAString& aValue);
1459 
1460   /**
1461    * Return the CORS mode for a given nsAttrValue (which may be null,
1462    * but if not should have been parsed via ParseCORSValue).
1463    */
1464   static CORSMode AttrValueToCORSMode(const nsAttrValue* aValue);
1465 
1466   JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) final;
1467 
1468   nsINode* GetScopeChainParent() const override;
1469 
1470   /**
1471    * Locate a TextEditor rooted at this content node, if there is one.
1472    */
1473   mozilla::TextEditor* GetTextEditorInternal();
1474 
1475   /**
1476    * Gets value of boolean attribute. Only works for attributes in null
1477    * namespace.
1478    *
1479    * @param aAttr    name of attribute.
1480    * @param aValue   Boolean value of attribute.
1481    */
GetBoolAttr(nsAtom * aAttr)1482   bool GetBoolAttr(nsAtom* aAttr) const {
1483     return HasAttr(kNameSpaceID_None, aAttr);
1484   }
1485 
1486   /**
1487    * Sets value of boolean attribute by removing attribute or setting it to
1488    * the empty string. Only works for attributes in null namespace.
1489    *
1490    * @param aAttr    name of attribute.
1491    * @param aValue   Boolean value of attribute.
1492    */
1493   nsresult SetBoolAttr(nsAtom* aAttr, bool aValue);
1494 
1495   /**
1496    * Gets the enum value string of an attribute and using a default value if
1497    * the attribute is missing or the string is an invalid enum value.
1498    *
1499    * @param aType     the name of the attribute.
1500    * @param aDefault  the default value if the attribute is missing or invalid.
1501    * @param aResult   string corresponding to the value [out].
1502    */
1503   void GetEnumAttr(nsAtom* aAttr, const char* aDefault,
1504                    nsAString& aResult) const;
1505 
1506   /**
1507    * Gets the enum value string of an attribute and using the default missing
1508    * value if the attribute is missing or the default invalid value if the
1509    * string is an invalid enum value.
1510    *
1511    * @param aType            the name of the attribute.
1512    * @param aDefaultMissing  the default value if the attribute is missing.  If
1513                              null and the attribute is missing, aResult will be
1514                              set to the null DOMString; this only matters for
1515                              cases in which we're reflecting a nullable string.
1516    * @param aDefaultInvalid  the default value if the attribute is invalid.
1517    * @param aResult          string corresponding to the value [out].
1518    */
1519   void GetEnumAttr(nsAtom* aAttr, const char* aDefaultMissing,
1520                    const char* aDefaultInvalid, nsAString& aResult) const;
1521 
1522   /**
1523    * Unset an attribute.
1524    */
UnsetAttr(nsAtom * aAttr,ErrorResult & aError)1525   void UnsetAttr(nsAtom* aAttr, ErrorResult& aError) {
1526     aError = UnsetAttr(kNameSpaceID_None, aAttr, true);
1527   }
1528 
1529   /**
1530    * Set an attribute in the simplest way possible.
1531    */
SetAttr(nsAtom * aAttr,const nsAString & aValue,ErrorResult & aError)1532   void SetAttr(nsAtom* aAttr, const nsAString& aValue, ErrorResult& aError) {
1533     aError = SetAttr(kNameSpaceID_None, aAttr, aValue, true);
1534   }
1535 
SetAttr(nsAtom * aAttr,const nsAString & aValue,nsIPrincipal * aTriggeringPrincipal,ErrorResult & aError)1536   void SetAttr(nsAtom* aAttr, const nsAString& aValue,
1537                nsIPrincipal* aTriggeringPrincipal, ErrorResult& aError) {
1538     aError =
1539         SetAttr(kNameSpaceID_None, aAttr, aValue, aTriggeringPrincipal, true);
1540   }
1541 
1542   /**
1543    * Set a content attribute via a reflecting nullable string IDL
1544    * attribute (e.g. a CORS attribute).  If DOMStringIsNull(aValue),
1545    * this will actually remove the content attribute.
1546    */
1547   void SetOrRemoveNullableStringAttr(nsAtom* aName, const nsAString& aValue,
1548                                      ErrorResult& aError);
1549 
1550   /**
1551    * Retrieve the ratio of font-size-inflated text font size to computed font
1552    * size for this element. This will query the element for its primary frame,
1553    * and then use this to get font size inflation information about the frame.
1554    *
1555    * @returns The font size inflation ratio (inflated font size to uninflated
1556    *          font size) for the primary frame of this element. Returns 1.0
1557    *          by default if font size inflation is not enabled. Returns -1
1558    *          if the element does not have a primary frame.
1559    *
1560    * @note The font size inflation ratio that is returned is actually the
1561    *       font size inflation data for the element's _primary frame_, not the
1562    *       element itself, but for most purposes, this should be sufficient.
1563    */
1564   float FontSizeInflation();
1565 
1566   net::ReferrerPolicy GetReferrerPolicyAsEnum();
1567   net::ReferrerPolicy ReferrerPolicyFromAttr(const nsAttrValue* aValue);
1568 
1569   /*
1570    * Helpers for .dataset.  This is implemented on Element, though only some
1571    * sorts of elements expose it to JS as a .dataset property
1572    */
1573   // Getter, to be called from bindings.
1574   already_AddRefed<nsDOMStringMap> Dataset();
1575   // Callback for destructor of dataset to ensure to null out our weak pointer
1576   // to it.
1577   void ClearDataset();
1578 
1579   void RegisterIntersectionObserver(DOMIntersectionObserver* aObserver);
1580   void UnregisterIntersectionObserver(DOMIntersectionObserver* aObserver);
1581   void UnlinkIntersectionObservers();
1582   bool UpdateIntersectionObservation(DOMIntersectionObserver* aObserver,
1583                                      int32_t threshold);
1584 
1585  protected:
1586   /*
1587    * Named-bools for use with SetAttrAndNotify to make call sites easier to
1588    * read.
1589    */
1590   static const bool kFireMutationEvent = true;
1591   static const bool kDontFireMutationEvent = false;
1592   static const bool kNotifyDocumentObservers = true;
1593   static const bool kDontNotifyDocumentObservers = false;
1594   static const bool kCallAfterSetAttr = true;
1595   static const bool kDontCallAfterSetAttr = false;
1596 
1597   /**
1598    * Set attribute and (if needed) notify documentobservers and fire off
1599    * mutation events.  This will send the AttributeChanged notification.
1600    * Callers of this method are responsible for calling AttributeWillChange,
1601    * since that needs to happen before the new attr value has been set, and
1602    * in particular before it has been parsed.
1603    *
1604    * For the boolean parameters, consider using the named bools above to aid
1605    * code readability.
1606    *
1607    * @param aNamespaceID  namespace of attribute
1608    * @param aAttribute    local-name of attribute
1609    * @param aPrefix       aPrefix of attribute
1610    * @param aOldValue     The old value of the attribute to use as a fallback
1611    *                      in the cases where the actual old value (i.e.
1612    *                      its current value) is !StoresOwnData() --- in which
1613    *                      case the current value is probably already useless.
1614    *                      If the current value is StoresOwnData() (or absent),
1615    *                      aOldValue will not be used. aOldValue will only be set
1616    *                      in certain circumstances (there are mutation
1617    *                      listeners, element is a custom element, attribute was
1618    *                      not previously unset). Otherwise it will be null.
1619    * @param aParsedValue  parsed new value of attribute. Replaced by the
1620    *                      old value of the attribute. This old value is only
1621    *                      useful if either it or the new value is StoresOwnData.
1622    * @param aMaybeScriptedPrincipal
1623    *                      the principal of the scripted caller responsible for
1624    *                      setting the attribute, or null if no scripted caller
1625    *                      can be determined. A null value here does not
1626    *                      guarantee that there is no scripted caller, but a
1627    *                      non-null value does guarantee that a scripted caller
1628    *                      with the given principal is directly responsible for
1629    *                      the attribute change.
1630    * @param aModType      MutationEventBinding::MODIFICATION or ADDITION.  Only
1631    *                      needed if aFireMutation or aNotify is true.
1632    * @param aFireMutation should mutation-events be fired?
1633    * @param aNotify       should we notify document-observers?
1634    * @param aCallAfterSetAttr should we call AfterSetAttr?
1635    * @param aComposedDocument The current composed document of the element.
1636    */
1637   nsresult SetAttrAndNotify(int32_t aNamespaceID, nsAtom* aName,
1638                             nsAtom* aPrefix, const nsAttrValue* aOldValue,
1639                             nsAttrValue& aParsedValue,
1640                             nsIPrincipal* aMaybeScriptedPrincipal,
1641                             uint8_t aModType, bool aFireMutation, bool aNotify,
1642                             bool aCallAfterSetAttr,
1643                             nsIDocument* aComposedDocument,
1644                             const mozAutoDocUpdate& aGuard);
1645 
1646   /**
1647    * Scroll to a new position using behavior evaluated from CSS and
1648    * a CSSOM-View DOM method ScrollOptions dictionary.  The scrolling may
1649    * be performed asynchronously or synchronously depending on the resolved
1650    * scroll-behavior.
1651    *
1652    * @param aScroll       Destination of scroll, in CSS pixels
1653    * @param aOptions      Dictionary of options to be evaluated
1654    */
1655   MOZ_CAN_RUN_SCRIPT
1656   void Scroll(const CSSIntPoint& aScroll, const ScrollOptions& aOptions);
1657 
1658   /**
1659    * Convert an attribute string value to attribute type based on the type of
1660    * attribute.  Called by SetAttr().  Note that at the moment we only do this
1661    * for attributes in the null namespace (kNameSpaceID_None).
1662    *
1663    * @param aNamespaceID the namespace of the attribute to convert
1664    * @param aAttribute the attribute to convert
1665    * @param aValue the string value to convert
1666    * @param aMaybeScriptedPrincipal the principal of the script setting the
1667    *        attribute, if one can be determined, or null otherwise. As in
1668    *        AfterSetAttr, a null value does not guarantee that the attribute was
1669    *        not set by a scripted caller, but a non-null value guarantees that
1670    *        the attribute was set by a scripted caller with the given principal.
1671    * @param aResult the nsAttrValue [OUT]
1672    * @return true if the parsing was successful, false otherwise
1673    */
1674   virtual bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
1675                               const nsAString& aValue,
1676                               nsIPrincipal* aMaybeScriptedPrincipal,
1677                               nsAttrValue& aResult);
1678 
1679   /**
1680    * Try to set the attribute as a mapped attribute, if applicable.  This will
1681    * only be called for attributes that are in the null namespace and only on
1682    * attributes that returned true when passed to IsAttributeMapped.  The
1683    * caller will not try to set the attr in any other way if this method
1684    * returns true (the value of aRetval does not matter for that purpose).
1685    *
1686    * @param aName the name of the attribute
1687    * @param aValue the nsAttrValue to set. Will be swapped with the existing
1688    *               value of the attribute if the attribute already exists.
1689    * @param [out] aValueWasSet If the attribute was not set previously,
1690    *                           aValue will be swapped with an empty attribute
1691    *                           and aValueWasSet will be set to false. Otherwise,
1692    *                           aValueWasSet will be set to true and aValue will
1693    *                           contain the previous value set.
1694    * @param [out] aRetval the nsresult status of the operation, if any.
1695    * @return true if the setting was attempted, false otherwise.
1696    */
1697   virtual bool SetAndSwapMappedAttribute(nsAtom* aName, nsAttrValue& aValue,
1698                                          bool* aValueWasSet, nsresult* aRetval);
1699 
1700   /**
1701    * Hook that is called by Element::SetAttr to allow subclasses to
1702    * deal with attribute sets.  This will only be called after we verify that
1703    * we're actually doing an attr set and will be called before
1704    * AttributeWillChange and before ParseAttribute and hence before we've set
1705    * the new value.
1706    *
1707    * @param aNamespaceID the namespace of the attr being set
1708    * @param aName the localname of the attribute being set
1709    * @param aValue the value it's being set to represented as either a string or
1710    *        a parsed nsAttrValue. Alternatively, if the attr is being removed it
1711    *        will be null.
1712    * @param aNotify Whether we plan to notify document observers.
1713    */
1714   virtual nsresult BeforeSetAttr(int32_t aNamespaceID, nsAtom* aName,
1715                                  const nsAttrValueOrString* aValue,
1716                                  bool aNotify);
1717 
1718   /**
1719    * Hook that is called by Element::SetAttr to allow subclasses to
1720    * deal with attribute sets.  This will only be called after we have called
1721    * SetAndSwapAttr (that is, after we have actually set the attr).  It will
1722    * always be called under a scriptblocker.
1723    *
1724    * @param aNamespaceID the namespace of the attr being set
1725    * @param aName the localname of the attribute being set
1726    * @param aValue the value it's being set to.  If null, the attr is being
1727    *        removed.
1728    * @param aOldValue the value that the attribute had previously. If null,
1729    *        the attr was not previously set. This argument may not have the
1730    *        correct value for SVG elements, or other cases in which the
1731    *        attribute value doesn't store its own data
1732    * @param aMaybeScriptedPrincipal the principal of the scripted caller
1733    *        responsible for setting the attribute, or null if no scripted caller
1734    *        can be determined, or the attribute is being unset. A null value
1735    *        here does not guarantee that there is no scripted caller, but a
1736    *        non-null value does guarantee that a scripted caller with the given
1737    *        principal is directly responsible for the attribute change.
1738    * @param aNotify Whether we plan to notify document observers.
1739    */
1740   // Note that this is inlined so that when subclasses call it it gets
1741   // inlined.  Those calls don't go through a vtable.
AfterSetAttr(int32_t aNamespaceID,nsAtom * aName,const nsAttrValue * aValue,const nsAttrValue * aOldValue,nsIPrincipal * aMaybeScriptedPrincipal,bool aNotify)1742   virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
1743                                 const nsAttrValue* aValue,
1744                                 const nsAttrValue* aOldValue,
1745                                 nsIPrincipal* aMaybeScriptedPrincipal,
1746                                 bool aNotify) {
1747     return NS_OK;
1748   }
1749 
1750   /**
1751    * This function shall be called just before the id attribute changes. It will
1752    * be called after BeforeSetAttr. If the attribute being changed is not the id
1753    * attribute, this function does nothing. Otherwise, it will remove the old id
1754    * from the document's id cache.
1755    *
1756    * This must happen after BeforeSetAttr (rather than during) because the
1757    * the subclasses' calls to BeforeSetAttr may notify on state changes. If they
1758    * incorrectly determine whether the element had an id, the element may not be
1759    * restyled properly.
1760    *
1761    * @param aNamespaceID the namespace of the attr being set
1762    * @param aName the localname of the attribute being set
1763    * @param aValue the new id value. Will be null if the id is being unset.
1764    */
1765   void PreIdMaybeChange(int32_t aNamespaceID, nsAtom* aName,
1766                         const nsAttrValueOrString* aValue);
1767 
1768   /**
1769    * This function shall be called just after the id attribute changes. It will
1770    * be called before AfterSetAttr. If the attribute being changed is not the id
1771    * attribute, this function does nothing. Otherwise, it will add the new id to
1772    * the document's id cache and properly set the ElementHasID flag.
1773    *
1774    * This must happen before AfterSetAttr (rather than during) because the
1775    * the subclasses' calls to AfterSetAttr may notify on state changes. If they
1776    * incorrectly determine whether the element now has an id, the element may
1777    * not be restyled properly.
1778    *
1779    * @param aNamespaceID the namespace of the attr being set
1780    * @param aName the localname of the attribute being set
1781    * @param aValue the new id value. Will be null if the id is being unset.
1782    */
1783   void PostIdMaybeChange(int32_t aNamespaceID, nsAtom* aName,
1784                          const nsAttrValue* aValue);
1785 
1786   /**
1787    * Usually, setting an attribute to the value that it already has results in
1788    * no action. However, in some cases, setting an attribute to its current
1789    * value should have the effect of, for example, forcing a reload of
1790    * network data. To address that, this function will be called in this
1791    * situation to allow the handling of such a case.
1792    *
1793    * @param aNamespaceID the namespace of the attr being set
1794    * @param aName the localname of the attribute being set
1795    * @param aValue the value it's being set to represented as either a string or
1796    *        a parsed nsAttrValue.
1797    * @param aNotify Whether we plan to notify document observers.
1798    */
1799   // Note that this is inlined so that when subclasses call it it gets
1800   // inlined.  Those calls don't go through a vtable.
1801   virtual nsresult OnAttrSetButNotChanged(int32_t aNamespaceID, nsAtom* aName,
1802                                           const nsAttrValueOrString& aValue,
1803                                           bool aNotify);
1804 
1805   /**
1806    * Hook to allow subclasses to produce a different EventListenerManager if
1807    * needed for attachment of attribute-defined handlers
1808    */
1809   virtual EventListenerManager* GetEventListenerManagerForAttr(
1810       nsAtom* aAttrName, bool* aDefer);
1811 
1812   /**
1813    * Internal hook for converting an attribute name-string to nsAttrName in
1814    * case there is such existing attribute. aNameToUse can be passed to get
1815    * name which was used for looking for the attribute (lowercase in HTML).
1816    */
1817   const nsAttrName* InternalGetAttrNameFromQName(
1818       const nsAString& aStr, nsAutoString* aNameToUse = nullptr) const;
1819 
1820   nsIFrame* GetStyledFrame();
1821 
GetNameSpaceElement()1822   virtual Element* GetNameSpaceElement() override { return this; }
1823 
1824   Attr* GetAttributeNodeNSInternal(const nsAString& aNamespaceURI,
1825                                    const nsAString& aLocalName);
1826 
1827   inline void RegisterActivityObserver();
1828   inline void UnregisterActivityObserver();
1829 
1830   /**
1831    * Add/remove this element to the documents id cache
1832    */
1833   void AddToIdTable(nsAtom* aId);
1834   void RemoveFromIdTable();
1835 
1836   /**
1837    * Functions to carry out event default actions for links of all types
1838    * (HTML links, XLinks, SVG "XLinks", etc.)
1839    */
1840 
1841   /**
1842    * Check that we meet the conditions to handle a link event
1843    * and that we are actually on a link.
1844    *
1845    * @param aVisitor event visitor
1846    * @param aURI the uri of the link, set only if the return value is true [OUT]
1847    * @return true if we can handle the link event, false otherwise
1848    */
1849   bool CheckHandleEventForLinksPrecondition(EventChainVisitor& aVisitor,
1850                                             nsIURI** aURI) const;
1851 
1852   /**
1853    * Handle status bar updates before they can be cancelled.
1854    */
1855   nsresult GetEventTargetParentForLinks(EventChainPreVisitor& aVisitor);
1856 
1857   /**
1858    * Handle default actions for link event if the event isn't consumed yet.
1859    */
1860   nsresult PostHandleEventForLinks(EventChainPostVisitor& aVisitor);
1861 
1862   /**
1863    * Get the target of this link element. Consumers should established that
1864    * this element is a link (probably using IsLink) before calling this
1865    * function (or else why call it?)
1866    *
1867    * Note: for HTML this gets the value of the 'target' attribute; for XLink
1868    * this gets the value of the xlink:_moz_target attribute, or failing that,
1869    * the value of xlink:show, converted to a suitably equivalent named target
1870    * (e.g. _blank).
1871    */
1872   virtual void GetLinkTarget(nsAString& aTarget);
1873 
1874   nsDOMTokenList* GetTokenList(
1875       nsAtom* aAtom,
1876       const DOMTokenListSupportedTokenArray aSupportedTokens = nullptr);
1877 
1878  private:
1879   /**
1880    * Slow path for DoGetClasses, this should only be called for SVG elements.
1881    */
1882   const nsAttrValue* GetSVGAnimatedClass() const;
1883 
1884   /**
1885    * Get this element's client area rect in app units.
1886    * @return the frame's client area
1887    */
1888   MOZ_CAN_RUN_SCRIPT nsRect GetClientAreaRect();
1889 
1890   MOZ_CAN_RUN_SCRIPT
1891   nsIScrollableFrame* GetScrollFrame(nsIFrame** aStyledFrame = nullptr,
1892                                      FlushType aFlushType = FlushType::Layout);
1893 
1894   // Data members
1895   EventStates mState;
1896   // Per-node data managed by Servo.
1897   //
1898   // There should not be data on nodes that are in the flattened tree, or
1899   // descendants of display: none elements.
1900   mozilla::ServoCell<ServoNodeData*> mServoData;
1901 };
1902 
1903 class RemoveFromBindingManagerRunnable : public mozilla::Runnable {
1904  public:
1905   RemoveFromBindingManagerRunnable(nsBindingManager* aManager,
1906                                    nsIContent* aContent, nsIDocument* aDoc);
1907 
1908   NS_IMETHOD Run() override;
1909 
1910  private:
1911   virtual ~RemoveFromBindingManagerRunnable();
1912   RefPtr<nsBindingManager> mManager;
1913   RefPtr<nsIContent> mContent;
1914   nsCOMPtr<nsIDocument> mDoc;
1915 };
1916 
NS_DEFINE_STATIC_IID_ACCESSOR(Element,NS_ELEMENT_IID)1917 NS_DEFINE_STATIC_IID_ACCESSOR(Element, NS_ELEMENT_IID)
1918 
1919 inline bool Element::HasAttr(int32_t aNameSpaceID, nsAtom* aName) const {
1920   NS_ASSERTION(nullptr != aName, "must have attribute name");
1921   NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown,
1922                "must have a real namespace ID!");
1923 
1924   return mAttrsAndChildren.IndexOfAttr(aName, aNameSpaceID) >= 0;
1925 }
1926 
AttrValueIs(int32_t aNameSpaceID,nsAtom * aName,const nsAString & aValue,nsCaseTreatment aCaseSensitive)1927 inline bool Element::AttrValueIs(int32_t aNameSpaceID, nsAtom* aName,
1928                                  const nsAString& aValue,
1929                                  nsCaseTreatment aCaseSensitive) const {
1930   NS_ASSERTION(aName, "Must have attr name");
1931   NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
1932 
1933   const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
1934   return val && val->Equals(aValue, aCaseSensitive);
1935 }
1936 
AttrValueIs(int32_t aNameSpaceID,nsAtom * aName,nsAtom * aValue,nsCaseTreatment aCaseSensitive)1937 inline bool Element::AttrValueIs(int32_t aNameSpaceID, nsAtom* aName,
1938                                  nsAtom* aValue,
1939                                  nsCaseTreatment aCaseSensitive) const {
1940   NS_ASSERTION(aName, "Must have attr name");
1941   NS_ASSERTION(aNameSpaceID != kNameSpaceID_Unknown, "Must have namespace");
1942   NS_ASSERTION(aValue, "Null value atom");
1943 
1944   const nsAttrValue* val = mAttrsAndChildren.GetAttr(aName, aNameSpaceID);
1945   return val && val->Equals(aValue, aCaseSensitive);
1946 }
1947 
1948 }  // namespace dom
1949 }  // namespace mozilla
1950 
AsElement()1951 inline mozilla::dom::Element* nsINode::AsElement() {
1952   MOZ_ASSERT(IsElement());
1953   return static_cast<mozilla::dom::Element*>(this);
1954 }
1955 
AsElement()1956 inline const mozilla::dom::Element* nsINode::AsElement() const {
1957   MOZ_ASSERT(IsElement());
1958   return static_cast<const mozilla::dom::Element*>(this);
1959 }
1960 
UnsetRestyleFlagsIfGecko()1961 inline void nsINode::UnsetRestyleFlagsIfGecko() {
1962   if (IsElement() && !AsElement()->IsStyledByServo()) {
1963     UnsetFlags(ELEMENT_ALL_RESTYLE_FLAGS |
1964                ELEMENT_HAS_CHILD_WITH_LATER_SIBLINGS_HINT);
1965   }
1966 }
1967 
1968 /**
1969  * Macros to implement Clone(). _elementName is the class for which to implement
1970  * Clone.
1971  */
1972 #define NS_IMPL_ELEMENT_CLONE(_elementName)                                  \
1973   nsresult _elementName::Clone(mozilla::dom::NodeInfo* aNodeInfo,            \
1974                                nsINode** aResult, bool aPreallocateChildren) \
1975       const {                                                                \
1976     *aResult = nullptr;                                                      \
1977     already_AddRefed<mozilla::dom::NodeInfo> ni =                            \
1978         RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();                  \
1979     _elementName* it = new _elementName(ni);                                 \
1980     if (!it) {                                                               \
1981       return NS_ERROR_OUT_OF_MEMORY;                                         \
1982     }                                                                        \
1983                                                                              \
1984     nsCOMPtr<nsINode> kungFuDeathGrip = it;                                  \
1985     nsresult rv = const_cast<_elementName*>(this)->CopyInnerTo(              \
1986         it, aPreallocateChildren);                                           \
1987     if (NS_SUCCEEDED(rv)) {                                                  \
1988       kungFuDeathGrip.swap(*aResult);                                        \
1989     }                                                                        \
1990                                                                              \
1991     return rv;                                                               \
1992   }
1993 
1994 #define EXPAND(...) __VA_ARGS__
1995 #define NS_IMPL_ELEMENT_CLONE_WITH_INIT_HELPER(_elementName, extra_args_)    \
1996   nsresult _elementName::Clone(mozilla::dom::NodeInfo* aNodeInfo,            \
1997                                nsINode** aResult, bool aPreallocateChildren) \
1998       const {                                                                \
1999     *aResult = nullptr;                                                      \
2000     already_AddRefed<mozilla::dom::NodeInfo> ni =                            \
2001         RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();                  \
2002     _elementName* it = new _elementName(ni EXPAND extra_args_);              \
2003     if (!it) {                                                               \
2004       return NS_ERROR_OUT_OF_MEMORY;                                         \
2005     }                                                                        \
2006                                                                              \
2007     nsCOMPtr<nsINode> kungFuDeathGrip = it;                                  \
2008     nsresult rv = it->Init();                                                \
2009     nsresult rv2 = const_cast<_elementName*>(this)->CopyInnerTo(             \
2010         it, aPreallocateChildren);                                           \
2011     if (NS_FAILED(rv2)) {                                                    \
2012       rv = rv2;                                                              \
2013     }                                                                        \
2014     if (NS_SUCCEEDED(rv)) {                                                  \
2015       kungFuDeathGrip.swap(*aResult);                                        \
2016     }                                                                        \
2017                                                                              \
2018     return rv;                                                               \
2019   }
2020 
2021 #define NS_IMPL_ELEMENT_CLONE_WITH_INIT(_elementName) \
2022   NS_IMPL_ELEMENT_CLONE_WITH_INIT_HELPER(_elementName, ())
2023 #define NS_IMPL_ELEMENT_CLONE_WITH_INIT_AND_PARSER(_elementName) \
2024   NS_IMPL_ELEMENT_CLONE_WITH_INIT_HELPER(_elementName, (, NOT_FROM_PARSER))
2025 
2026 #endif  // mozilla_dom_Element_h__
2027