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