blob: cc135847c8381fe8b920547dbef2ba8d5991202a [file] [log] [blame]
* Copyright (C) 1999 Lars Knoll (
* (C) 1999 Antti Koivisto (
* (C) 2001 Peter Kelly (
* (C) 2001 Dirk Mueller (
* Copyright (C) 2003-2011, 2013, 2014 Apple Inc. All rights reserved.
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* Library General Public License for more details.
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
#include "third_party/blink/public/platform/pointer_id.h"
#include "third_party/blink/public/platform/web_focus_type.h"
#include "third_party/blink/renderer/core/animation/animatable.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/css/css_primitive_value.h"
#include "third_party/blink/renderer/core/css/css_selector.h"
#include "third_party/blink/renderer/core/css/style_recalc.h"
#include "third_party/blink/renderer/core/dom/container_node.h"
#include "third_party/blink/renderer/core/dom/dom_high_res_time_stamp.h"
#include "third_party/blink/renderer/core/dom/element_data.h"
#include "third_party/blink/renderer/core/dom/names_map.h"
#include "third_party/blink/renderer/core/dom/whitespace_attacher.h"
#include "third_party/blink/renderer/core/html/focus_options.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/trustedtypes/trusted_types_util.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
namespace blink {
class AccessibleNode;
class Attr;
class Attribute;
class CSSPropertyValueSet;
class CSSStyleDeclaration;
class CustomElementDefinition;
class DOMRect;
class DOMRectList;
class DOMStringMap;
class DOMTokenList;
class DisplayLockContext;
class Document;
class ElementAnimations;
class ElementInternals;
class ElementIntersectionObserverData;
class ElementRareData;
class ExceptionState;
class FloatQuad;
class FloatSize;
class FocusOptions;
class Image;
class InputDeviceCapabilities;
class Locale;
class MutableCSSPropertyValueSet;
class NamedNodeMap;
class PaintLayerScrollableArea;
class PointerLockOptions;
class PseudoElement;
class PseudoElementStyleRequest;
class ResizeObservation;
class ResizeObserver;
class ScriptPromise;
class ScrollIntoViewOptions;
class ScrollIntoViewOptionsOrBoolean;
class ScrollToOptions;
class ShadowRoot;
class ShadowRootInit;
class SpaceSplitString;
class StringOrTrustedHTML;
class StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURL;
class StringOrTrustedScript;
class StringOrTrustedScriptURL;
class StylePropertyMap;
class StylePropertyMapReadOnly;
class V0CustomElementDefinition;
enum class CSSPropertyID;
enum class CSSValueID;
enum class DisplayLockActivationReason;
enum class DisplayLockLifecycleTarget;
enum class DisplayLockContextCreateMethod;
using ScrollOffset = FloatSize;
enum SpellcheckAttributeState {
enum class ElementFlags {
kTabIndexWasSetExplicitly = 1 << 0,
kStyleAffectedByEmpty = 1 << 1,
kIsInCanvasSubtree = 1 << 2,
kContainsFullScreenElement = 1 << 3,
kIsInTopLayer = 1 << 4,
kContainsPersistentVideo = 1 << 5,
kNumberOfElementFlags = 6, // Size of bitfield used to store the flags.
enum class ShadowRootType;
enum class SelectionBehaviorOnFocus {
enum class NamedItemType {
enum class InvisibleState {
struct FocusParams {
FocusParams() : options(FocusOptions::Create()) {}
FocusParams(SelectionBehaviorOnFocus selection,
WebFocusType focus_type,
InputDeviceCapabilities* capabilities,
const FocusOptions* focus_options = FocusOptions::Create())
: selection_behavior(selection),
options(focus_options) {}
SelectionBehaviorOnFocus selection_behavior =
WebFocusType type = kWebFocusTypeNone;
Member<InputDeviceCapabilities> source_capabilities = nullptr;
Member<const FocusOptions> options;
typedef HeapVector<Member<Attr>> AttrNodeList;
typedef HashMap<AtomicString, SpecificTrustedType> AttrNameToTrustedType;
class CORE_EXPORT Element : public ContainerNode, public Animatable {
Element(const QualifiedName& tag_name,
ConstructionType = kCreateElement);
// Animatable implementation.
Element* GetAnimationTarget() override;
DEFINE_ATTRIBUTE_EVENT_LISTENER(beforepaste, kBeforepaste)
bool hasAttribute(const QualifiedName&) const;
const AtomicString& getAttribute(const QualifiedName&) const;
// Passing g_null_atom as the second parameter removes the attribute when
// calling either of these set methods.
void setAttribute(const QualifiedName&, const AtomicString& value);
void setAttribute(const QualifiedName&,
const AtomicString& value,
void SetSynchronizedLazyAttribute(const QualifiedName&,
const AtomicString& value);
void removeAttribute(const QualifiedName&);
// Typed getters and setters for language bindings.
int GetIntegralAttribute(const QualifiedName& attribute_name) const;
int GetIntegralAttribute(const QualifiedName& attribute_name,
int default_value) const;
void SetIntegralAttribute(const QualifiedName& attribute_name, int value);
void SetUnsignedIntegralAttribute(const QualifiedName& attribute_name,
unsigned value,
unsigned default_value = 0);
double GetFloatingPointAttribute(
const QualifiedName& attribute_name,
double fallback_value = std::numeric_limits<double>::quiet_NaN()) const;
void SetFloatingPointAttribute(const QualifiedName& attribute_name,
double value);
Element* GetElementAttribute(const QualifiedName& name);
void SetElementAttribute(const QualifiedName&, Element*);
HeapVector<Member<Element>> GetElementArrayAttribute(
const QualifiedName& name,
bool& is_null);
void SetElementArrayAttribute(const QualifiedName&,
bool is_null);
// Call this to get the value of an attribute that is known not to be the
// style attribute or one of the SVG animatable attributes.
bool FastHasAttribute(const QualifiedName&) const;
const AtomicString& FastGetAttribute(const QualifiedName&) const;
bool FastAttributeLookupAllowed(const QualifiedName&) const;
bool HasNamedNodeMap() const;
bool hasAttributes() const;
bool hasAttribute(const AtomicString& name) const;
bool hasAttributeNS(const AtomicString& namespace_uri,
const AtomicString& local_name) const;
// Ignores namespace.
bool HasAttributeIgnoringNamespace(const AtomicString& local_name) const;
const AtomicString& getAttribute(const AtomicString& name) const;
const AtomicString& getAttributeNS(const AtomicString& namespace_uri,
const AtomicString& local_name) const;
void setAttribute(const AtomicString& name,
const AtomicString& value,
void setAttribute(const AtomicString& name, const AtomicString& value);
// Trusted Types variant for explicit setAttribute() use.
void setAttribute(const AtomicString&,
const StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURL&,
// Returns attributes that should be checked against Trusted Types
virtual const AttrNameToTrustedType& GetCheckedAttributeTypes() const;
// Trusted Type HTML variant
void setAttribute(const QualifiedName&,
const StringOrTrustedHTML&,
// Trusted Type Script variant
void setAttribute(const QualifiedName&,
const StringOrTrustedScript&,
// Trusted Type ScriptURL variant
void setAttribute(const QualifiedName&,
const StringOrTrustedScriptURL&,
static bool ParseAttributeName(QualifiedName&,
const AtomicString& namespace_uri,
const AtomicString& qualified_name,
void setAttributeNS(
const AtomicString& namespace_uri,
const AtomicString& qualified_name,
const StringOrTrustedHTMLOrTrustedScriptOrTrustedScriptURL&,
bool toggleAttribute(const AtomicString&, ExceptionState&);
bool toggleAttribute(const AtomicString&, bool force, ExceptionState&);
const AtomicString& GetIdAttribute() const;
void SetIdAttribute(const AtomicString&);
const AtomicString& GetNameAttribute() const;
const AtomicString& GetClassAttribute() const;
// This is an operation defined in the DOM standard like:
// If element is in the HTML namespace and its node document is an HTML
// document, then set qualifiedName to qualifiedName in ASCII lowercase.
AtomicString LowercaseIfNecessary(const AtomicString&) const;
// NoncedElement implementation: this is only used by HTMLElement and
// SVGElement, but putting the implementation here allows us to use
// ElementRareData to hold the data.
const AtomicString& nonce() const;
void setNonce(const AtomicString&);
// Call this to get the value of the id attribute for style resolution
// purposes. The value will already be lowercased if the document is in
// compatibility mode, so this function is not suitable for non-style uses.
const AtomicString& IdForStyleResolution() const;
// This getter takes care of synchronizing all attributes before returning the
// AttributeCollection. If the Element has no attributes, an empty
// AttributeCollection will be returned. This is not a trivial getter and its
// return value should be cached for performance.
AttributeCollection Attributes() const;
// This variant will not update the potentially invalid attributes. To be used
// when not interested in style attribute or one of the SVG animation
// attributes.
AttributeCollection AttributesWithoutUpdate() const;
void scrollIntoView(ScrollIntoViewOptionsOrBoolean);
void scrollIntoView(bool align_to_top = true);
void scrollIntoViewWithOptions(const ScrollIntoViewOptions*);
void ScrollIntoViewNoVisualUpdate(const ScrollIntoViewOptions*);
void scrollIntoViewIfNeeded(bool center_if_needed = true);
int OffsetLeft();
int OffsetTop();
int OffsetWidth();
int OffsetHeight();
Element* OffsetParent();
int clientLeft();
int clientTop();
int clientWidth();
int clientHeight();
double scrollLeft();
double scrollTop();
void setScrollLeft(double);
void setScrollTop(double);
int scrollWidth();
int scrollHeight();
void scrollBy(double x, double y);
void scrollBy(const ScrollToOptions*);
void scrollTo(double x, double y);
void scrollTo(const ScrollToOptions*);
// This will return the |GetScrollableArea| of correspond LayoutBox. For
// LayoutTextControlSingleLine, it will return its |InnerEditorElement|'s.
virtual PaintLayerScrollableArea* GetScrollableArea() const;
IntRect BoundsInViewport() const;
// Returns an intersection rectangle of the bounds rectangle and the visual
// viewport's rectangle in the visual viewport's coordinate space.
// Applies ancestors' frames' clipping, but does not (yet) apply (overflow)
// element clipping (
IntRect VisibleBoundsInVisualViewport() const;
DOMRectList* getClientRects();
DOMRect* getBoundingClientRect();
const AtomicString& computedRole();
String computedName();
AccessibleNode* ExistingAccessibleNode() const;
AccessibleNode* accessibleNode();
InvisibleState Invisible() const;
bool HasInvisibleAttribute() const;
void DispatchActivateInvisibleEventIfNeeded();
bool IsInsideInvisibleSubtree() const;
bool IsInsideInvisibleStaticSubtree() const;
void DefaultEventHandler(Event&) override;
void DidMoveToNewDocument(Document&) override;
void removeAttribute(const AtomicString& name);
void removeAttributeNS(const AtomicString& namespace_uri,
const AtomicString& local_name);
Attr* DetachAttribute(wtf_size_t index);
Attr* getAttributeNode(const AtomicString& name);
Attr* getAttributeNodeNS(const AtomicString& namespace_uri,
const AtomicString& local_name);
Attr* setAttributeNode(Attr*, ExceptionState&);
Attr* setAttributeNodeNS(Attr*, ExceptionState&);
Attr* removeAttributeNode(Attr*, ExceptionState&);
Attr* AttrIfExists(const QualifiedName&);
Attr* EnsureAttr(const QualifiedName&);
AttrNodeList* GetAttrNodeList();
CSSStyleDeclaration* style();
StylePropertyMap* attributeStyleMap();
StylePropertyMapReadOnly* ComputedStyleMap();
const QualifiedName& TagQName() const { return tag_name_; }
String tagName() const { return nodeName(); }
bool HasTagName(const QualifiedName& tag_name) const {
return tag_name_.Matches(tag_name);
bool HasTagName(const HTMLQualifiedName& tag_name) const {
return ContainerNode::HasTagName(tag_name);
bool HasTagName(const SVGQualifiedName& tag_name) const {
return ContainerNode::HasTagName(tag_name);
// Should be called only by Document::createElementNS to fix up tag_name_
// immediately after construction.
void SetTagNameForCreateElementNS(const QualifiedName&);
// A fast function for checking the local name against another atomic string.
bool HasLocalName(const AtomicString& other) const {
return tag_name_.LocalName() == other;
const AtomicString& localName() const { return tag_name_.LocalName(); }
AtomicString LocalNameForSelectorMatching() const;
const AtomicString& prefix() const { return tag_name_.Prefix(); }
const AtomicString& namespaceURI() const { return tag_name_.NamespaceURI(); }
const AtomicString& LocateNamespacePrefix(
const AtomicString& namespace_uri) const;
String nodeName() const override;
Element& CloneWithChildren(Document* = nullptr) const;
Element& CloneWithoutChildren(Document* = nullptr) const;
void SetBooleanAttribute(const QualifiedName&, bool);
virtual const CSSPropertyValueSet* AdditionalPresentationAttributeStyle() {
return nullptr;
void InvalidateStyleAttribute();
const CSSPropertyValueSet* InlineStyle() const {
return GetElementData() ? GetElementData()->inline_style_.Get() : nullptr;
void SetInlineStyleProperty(CSSPropertyID,
CSSValueID identifier,
bool important = false);
void SetInlineStyleProperty(CSSPropertyID,
double value,
bool important = false);
void SetInlineStyleProperty(CSSPropertyID,
const CSSValue&,
bool important = false);
bool SetInlineStyleProperty(CSSPropertyID,
const String& value,
bool important = false);
bool RemoveInlineStyleProperty(CSSPropertyID);
bool RemoveInlineStyleProperty(const AtomicString&);
void RemoveAllInlineStyleProperties();
void SynchronizeStyleAttributeInternal() const;
const CSSPropertyValueSet* PresentationAttributeStyle();
virtual bool IsPresentationAttribute(const QualifiedName& attr) const {
return false;
virtual void CollectStyleForPresentationAttribute(
const QualifiedName&,
const AtomicString&,
MutableCSSPropertyValueSet*) {}
// For exposing to DOM only.
NamedNodeMap* attributesForBindings() const;
Vector<AtomicString> getAttributeNames() const;
enum class AttributeModificationReason { kDirectly, kByParser, kByCloning };
struct AttributeModificationParams {
AttributeModificationParams(const QualifiedName& qname,
const AtomicString& old_value,
const AtomicString& new_value,
AttributeModificationReason reason)
: name(qname),
reason(reason) {}
const QualifiedName& name;
const AtomicString& old_value;
const AtomicString& new_value;
const AttributeModificationReason reason;
// |attributeChanged| is called whenever an attribute is added, changed or
// removed. It handles very common attributes such as id, class, name, style,
// and slot.
// While the owner document is parsed, this function is called after all
// attributes in a start tag were added to the element.
virtual void AttributeChanged(const AttributeModificationParams&);
// |parseAttribute| is called by |attributeChanged|. If an element
// implementation needs to check an attribute update, override this function.
// While the owner document is parsed, this function is called after all
// attributes in a start tag were added to the element.
virtual void ParseAttribute(const AttributeModificationParams&);
virtual bool HasLegalLinkAttribute(const QualifiedName&) const;
virtual const QualifiedName& SubResourceAttributeName() const;
// Only called by the parser immediately after element construction.
void ParserSetAttributes(const Vector<Attribute>&);
// Remove attributes that might introduce scripting from the vector leaving
// the element unchanged.
void StripScriptingAttributes(Vector<Attribute>&) const;
bool SharesSameElementData(const Element& other) const {
return GetElementData() == other.GetElementData();
// Clones attributes only.
void CloneAttributesFrom(const Element&);
bool HasEquivalentAttributes(const Element& other) const;
// Step 5 of
virtual void CloneNonAttributePropertiesFrom(const Element&,
CloneChildrenFlag) {}
void AttachLayoutTree(AttachContext&) override;
void DetachLayoutTree(bool performing_reattach = false) override;
virtual LayoutObject* CreateLayoutObject(const ComputedStyle&, LegacyLayout);
virtual bool LayoutObjectIsNeeded(const ComputedStyle&) const;
void RecalcStyle(const StyleRecalcChange);
void RecalcStyleForTraversalRootAncestor();
void RebuildLayoutTreeForTraversalRootAncestor() {
bool NeedsRebuildLayoutTree(
const WhitespaceAttacher& whitespace_attacher) const {
// TODO( !CanParticipateInFlatTree() can be removed
// when Shadow DOM V0 support is removed.
return NeedsReattachLayoutTree() || ChildNeedsReattachLayoutTree() ||
!CanParticipateInFlatTree() ||
(whitespace_attacher.TraverseIntoDisplayContents() &&
void RebuildLayoutTree(WhitespaceAttacher&);
void PseudoStateChanged(CSSSelector::PseudoType);
void SetAnimationStyleChange(bool);
void SetNeedsAnimationStyleRecalc();
void SetNeedsCompositingUpdate();
// If type of ShadowRoot (either closed or open) is explicitly specified,
// creation of multiple shadow roots is prohibited in any combination and
// throws an exception. Multiple shadow roots are allowed only when
// createShadowRoot() is used without any parameters from JavaScript.
ShadowRoot* createShadowRoot(ExceptionState&);
ShadowRoot* attachShadow(const ShadowRootInit*, ExceptionState&);
ShadowRoot& CreateV0ShadowRootForTesting() {
return CreateShadowRootInternal();
ShadowRoot& CreateUserAgentShadowRoot();
ShadowRoot& AttachShadowRootInternal(ShadowRootType,
bool delegates_focus = false,
bool manual_slotting = false);
// Returns the shadow root attached to this element if it is a shadow host.
ShadowRoot* GetShadowRoot() const;
ShadowRoot* OpenShadowRoot() const;
ShadowRoot* ClosedShadowRoot() const;
ShadowRoot* AuthorShadowRoot() const;
ShadowRoot* UserAgentShadowRoot() const;
ShadowRoot* ShadowRootIfV1() const;
ShadowRoot& EnsureUserAgentShadowRoot();
bool IsInDescendantTreeOf(const Element* shadow_host) const;
// Returns the Element’s ComputedStyle. If the ComputedStyle is not already
// stored on the Element, computes the ComputedStyle and stores it on the
// Element’s ElementRareData. Used for getComputedStyle when Element is
// display none.
const ComputedStyle* EnsureComputedStyle(PseudoId = kPseudoIdNone);
bool HasDisplayContentsStyle() const;
bool ShouldStoreComputedStyle(const ComputedStyle&) const;
// Methods for indicating the style is affected by dynamic updates (e.g.,
// children changing, our position changing in our sibling list, etc.)
bool StyleAffectedByEmpty() const {
return HasElementFlag(ElementFlags::kStyleAffectedByEmpty);
void SetStyleAffectedByEmpty() {
void SetIsInCanvasSubtree(bool value) {
SetElementFlag(ElementFlags::kIsInCanvasSubtree, value);
bool IsInCanvasSubtree() const {
return HasElementFlag(ElementFlags::kIsInCanvasSubtree);
bool IsDefined() const {
return !(static_cast<int>(GetCustomElementState()) &
bool IsUpgradedV0CustomElement() {
return GetV0CustomElementState() == kV0Upgraded;
bool IsUnresolvedV0CustomElement() {
return GetV0CustomElementState() == kV0WaitingForUpgrade;
AtomicString ComputeInheritedLanguage() const;
Locale& GetLocale() const;
virtual void AccessKeyAction(bool /*sendToAnyEvent*/) {}
virtual bool IsURLAttribute(const Attribute&) const { return false; }
virtual bool IsHTMLContentAttribute(const Attribute&) const { return false; }
bool IsJavaScriptURLAttribute(const Attribute&) const;
virtual bool IsSVGAnimationAttributeSettingJavaScriptURL(
const Attribute&) const {
return false;
bool IsScriptingAttribute(const Attribute&) const;
virtual bool IsLiveLink() const { return false; }
KURL HrefURL() const;
KURL GetURLAttribute(const QualifiedName&) const;
void GetURLAttribute(const QualifiedName&, StringOrTrustedScriptURL&) const;
void FastGetAttribute(const QualifiedName&, StringOrTrustedHTML&) const;
KURL GetNonEmptyURLAttribute(const QualifiedName&) const;
virtual const AtomicString ImageSourceURL() const;
virtual Image* ImageContents() { return nullptr; }
// Returns true if this is a shadow host, and its ShadowRoot has
// delegatesFocus flag.
bool DelegatesFocus() const;
Element* GetFocusableArea() const;
virtual void focus(const FocusParams& = FocusParams());
void focus(const FocusOptions*);
void UpdateFocusAppearance(SelectionBehaviorOnFocus);
virtual void UpdateFocusAppearanceWithOptions(SelectionBehaviorOnFocus,
const FocusOptions*);
virtual void blur();
// Whether this element can receive focus at all. Most elements are not
// focusable but some elements, such as form controls and links, are. Unlike
// layoutObjectIsFocusable(), this method may be called when layout is not up
// to date, so it must not use the layoutObject to determine focusability.
virtual bool SupportsFocus() const;
// IsFocusable(), IsKeyboardFocusable(), and IsMouseFocusable() check
// whether the element can actually be focused. Callers should ensure
// ComputedStyle is up to date;
// e.g. by calling Document::UpdateStyleAndLayoutTree().
bool IsFocusable() const;
virtual bool IsKeyboardFocusable() const;
virtual bool IsMouseFocusable() const;
bool IsFocusedElementInDocument() const;
Element* AdjustedFocusedElementInTreeScope() const;
bool IsAutofocusable() const;
virtual void DispatchFocusEvent(
Element* old_focused_element,
InputDeviceCapabilities* source_capabilities = nullptr);
virtual void DispatchBlurEvent(
Element* new_focused_element,
InputDeviceCapabilities* source_capabilities = nullptr);
virtual void DispatchFocusInEvent(
const AtomicString& event_type,
Element* old_focused_element,
InputDeviceCapabilities* source_capabilities = nullptr);
void DispatchFocusOutEvent(
const AtomicString& event_type,
Element* new_focused_element,
InputDeviceCapabilities* source_capabilities = nullptr);
// The implementation of |innerText()| is found in "".
String innerText();
String outerText();
String InnerHTMLAsString() const;
String OuterHTMLAsString() const;
void SetInnerHTMLFromString(const String& html, ExceptionState&);
void SetInnerHTMLFromString(const String& html);
void SetOuterHTMLFromString(const String& html, ExceptionState&);
Element* insertAdjacentElement(const String& where,
Element* new_child,
void insertAdjacentText(const String& where,
const String& text,
void insertAdjacentHTML(const String& where,
const String& html,
// TrustedTypes variants of the above.
// TODO(mkwst): Write a spec for these bits.
void innerHTML(StringOrTrustedHTML&) const;
void outerHTML(StringOrTrustedHTML&) const;
void setInnerHTML(const StringOrTrustedHTML&, ExceptionState&);
void setInnerHTML(const StringOrTrustedHTML&);
void setOuterHTML(const StringOrTrustedHTML&, ExceptionState&);
void insertAdjacentHTML(const String& where,
const StringOrTrustedHTML&,
void setPointerCapture(PointerId poinetr_id, ExceptionState&);
void releasePointerCapture(PointerId pointer_id, ExceptionState&);
// Returns true iff the element would capture the next pointer event. This
// is true between a setPointerCapture call and a releasePointerCapture (or
// implicit release) call:
bool hasPointerCapture(PointerId pointer_id) const;
String TextFromChildren();
virtual String title() const { return String(); }
virtual String DefaultToolTip() const { return String(); }
virtual const AtomicString& ShadowPseudoId() const;
// The specified string must start with "-webkit-" or "-internal-". The
// former can be used as a selector in any places, and the latter can be
// used only in UA stylesheet.
void SetShadowPseudoId(const AtomicString&);
// Called by the parser when this element's close tag is reached, signaling
// that all child tags have been parsed and added. This is needed for
// <applet> and <object> elements, which can't lay themselves out until they
// know all of their nested <param>s. [Radar 3603191, 4040848]. Also used for
// script elements and some SVG elements for similar purposes, but making
// parsing a special case in this respect should be avoided if possible.
virtual void FinishParsingChildren();
void BeginParsingChildren() { SetIsFinishedParsingChildren(false); }
PseudoElement* GetPseudoElement(PseudoId) const;
LayoutObject* PseudoElementLayoutObject(PseudoId) const;
const ComputedStyle* CachedStyleForPseudoElement(
const PseudoElementStyleRequest&);
scoped_refptr<ComputedStyle> StyleForPseudoElement(
const PseudoElementStyleRequest&,
const ComputedStyle* parent_style = nullptr);
bool CanGeneratePseudoElement(PseudoId) const;
virtual bool MatchesDefaultPseudoClass() const { return false; }
virtual bool MatchesEnabledPseudoClass() const { return false; }
virtual bool MatchesReadOnlyPseudoClass() const { return false; }
virtual bool MatchesReadWritePseudoClass() const { return false; }
virtual bool MatchesValidityPseudoClasses() const { return false; }
virtual bool MayTriggerVirtualKeyboard() const;
bool matches(const AtomicString& selectors, ExceptionState&);
bool matches(const AtomicString& selectors);
Element* closest(const AtomicString& selectors, ExceptionState&);
Element* closest(const AtomicString& selectors);
virtual bool ShouldAppearIndeterminate() const { return false; }
DOMTokenList& classList();
DOMStringMap& dataset();
virtual bool IsDateTimeEditElement() const { return false; }
virtual bool IsDateTimeFieldElement() const { return false; }
virtual bool IsPickerIndicatorElement() const { return false; }
virtual bool IsFormControlElement() const { return false; }
virtual bool IsSpinButtonElement() const { return false; }
// This returns true for <textarea> and some types of <input>.
virtual bool IsTextControl() const { return false; }
virtual bool IsOptionalFormControl() const { return false; }
virtual bool IsRequiredFormControl() const { return false; }
virtual bool willValidate() const { return false; }
virtual bool IsValidElement() { return false; }
virtual bool IsInRange() const { return false; }
virtual bool IsOutOfRange() const { return false; }
virtual bool IsClearButtonElement() const { return false; }
virtual bool IsScriptElement() const { return false; }
virtual bool IsVTTCueBackgroundBox() const { return false; }
// Elements that may have an insertion mode other than "in body" should
// override this and return true.
virtual bool HasNonInBodyInsertionMode() const { return false; }
bool CanContainRangeEndPoint() const override { return true; }
// Used for disabled form elements; if true, prevents mouse events from being
// dispatched to event listeners, and prevents DOMActivate events from being
// sent at all.
virtual bool IsDisabledFormControl() const { return false; }
// Return true if we should force legacy layout on this element and all
// descendants. Note that even if this element returns true, it's not implied
// that all descendants will return the same. Once an element needs to force
// legacy layout, though, the layout engine knows that it will have to perform
// legacy layout on the entire subtree.
bool ShouldForceLegacyLayout() const {
if (TypeShouldForceLegacyLayout())
return true;
if (!HasRareData())
return false;
return StyleShouldForceLegacyLayout() || ShouldForceLegacyLayoutForChild();
virtual void BuildPendingResource() {}
void V0SetCustomElementDefinition(V0CustomElementDefinition*);
V0CustomElementDefinition* GetV0CustomElementDefinition() const;
void SetCustomElementDefinition(CustomElementDefinition*);
CustomElementDefinition* GetCustomElementDefinition() const;
void SetIsValue(const AtomicString&);
const AtomicString& IsValue() const;
void SetDidAttachInternals();
bool DidAttachInternals() const;
ElementInternals& EnsureElementInternals();
bool ContainsFullScreenElement() const {
return HasElementFlag(ElementFlags::kContainsFullScreenElement);
void SetContainsFullScreenElement(bool);
void SetContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool);
bool ContainsPersistentVideo() const {
return HasElementFlag(ElementFlags::kContainsPersistentVideo);
void SetContainsPersistentVideo(bool);
bool IsInTopLayer() const {
return HasElementFlag(ElementFlags::kIsInTopLayer);
void SetIsInTopLayer(bool);
void requestPointerLock(const PointerLockOptions*);
bool IsSpellCheckingEnabled() const;
// FIXME: public for LayoutTreeBuilder, we shouldn't expose this though.
scoped_refptr<ComputedStyle> StyleForLayoutObject(
bool calc_invisible = false);
bool HasID() const;
bool HasClass() const;
const SpaceSplitString& ClassNames() const;
bool HasClassName(const AtomicString& class_name) const;
// Returns true if the element has 1 or more part names.
bool HasPart() const;
// Returns the list of part names if it has ever been created.
DOMTokenList* GetPart() const;
// IDL method.
// Returns the list of part names, creating it if it doesn't exist.
DOMTokenList& part();
bool HasPartNamesMap() const;
const NamesMap* PartNamesMap() const;
ScrollOffset SavedLayerScrollOffset() const;
void SetSavedLayerScrollOffset(const ScrollOffset&);
ElementAnimations* GetElementAnimations() const;
ElementAnimations& EnsureElementAnimations();
bool HasAnimations() const;
void SynchronizeAttribute(const AtomicString& local_name) const;
MutableCSSPropertyValueSet& EnsureMutableInlineStyle();
void ClearMutableInlineStyleIfEmpty();
void setTabIndex(int);
int tabIndex() const;
// Helpers for V8DOMActivityLogger::logEvent. They call logEvent only if
// the element is isConnected() and the context is an isolated world.
void LogAddElementIfIsolatedWorldAndInDocument(const char element[],
const QualifiedName& attr1);
void LogAddElementIfIsolatedWorldAndInDocument(const char element[],
const QualifiedName& attr1,
const QualifiedName& attr2);
void LogAddElementIfIsolatedWorldAndInDocument(const char element[],
const QualifiedName& attr1,
const QualifiedName& attr2,
const QualifiedName& attr3);
void LogUpdateAttributeIfIsolatedWorldAndInDocument(
const char element[],
const AttributeModificationParams&);
void Trace(Visitor*) override;
SpellcheckAttributeState GetSpellcheckAttributeState() const;
ElementIntersectionObserverData* IntersectionObserverData() const;
ElementIntersectionObserverData& EnsureIntersectionObserverData();
bool ComputeIntersectionsForLifecycleUpdate(unsigned flags);
// Returns true if the Element is being observed by an IntersectionObserver
// for which trackVisibility() is true.
bool NeedsOcclusionTracking() const;
HeapHashMap<Member<ResizeObserver>, Member<ResizeObservation>>*
ResizeObserverData() const;
HeapHashMap<Member<ResizeObserver>, Member<ResizeObservation>>&
void SetNeedsResizeObserverUpdate();
DisplayLockContext* GetDisplayLockContext() const;
DisplayLockContext& EnsureDisplayLockContext(DisplayLockContextCreateMethod);
// Display locking IDL implementation
ScriptPromise updateRendering(ScriptState*);
void resetSubtreeRendered();
bool StyleRecalcBlockedByDisplayLock(DisplayLockLifecycleTarget) const;
// Activates all activatable (for a given reason) locked ancestors for this
// element. Return true if we activated at least one previously locked
// element.
bool ActivateDisplayLockIfNeeded(DisplayLockActivationReason reason);
virtual void SetActive(bool active);
virtual void SetHovered(bool hovered);
const ElementData* GetElementData() const { return element_data_.Get(); }
UniqueElementData& EnsureUniqueElementData();
void AddPropertyToPresentationAttributeStyle(MutableCSSPropertyValueSet*,
CSSValueID identifier);
void AddPropertyToPresentationAttributeStyle(MutableCSSPropertyValueSet*,
double value,
void AddPropertyToPresentationAttributeStyle(MutableCSSPropertyValueSet*,
const String& value);
void AddPropertyToPresentationAttributeStyle(MutableCSSPropertyValueSet*,
const CSSValue&);
InsertionNotificationRequest InsertedInto(ContainerNode&) override;
void RemovedFrom(ContainerNode&) override;
void ChildrenChanged(const ChildrenChange&) override;
virtual void WillRecalcStyle(const StyleRecalcChange);
virtual void DidRecalcStyle(const StyleRecalcChange);
virtual scoped_refptr<ComputedStyle> CustomStyleForLayoutObject();
virtual NamedItemType GetNamedItemType() const {
return NamedItemType::kNone;
bool SupportsSpatialNavigationFocus() const;
void ClearTabIndexExplicitlyIfNeeded();
void SetTabIndexExplicitly();
// Subclasses may override this method to affect focusability. This method
// must be called on an up-to-date ComputedStyle, so it may use existence of
// layoutObject and the LayoutObject::style() to reason about focusability.
// However, it must not retrieve layout information like position and size.
// This method cannot be moved to LayoutObject because some focusable nodes
// don't have layoutObjects. e.g., HTMLOptionElement.
virtual bool IsFocusableStyle() const;
// classAttributeChanged() exists to share code between
// parseAttribute (called via setAttribute()) and
// svgAttributeChanged (called when element.className.baseValue is set)
void ClassAttributeChanged(const AtomicString& new_class_string);
static bool AttributeValueIsJavaScriptURL(const Attribute&);
scoped_refptr<ComputedStyle> OriginalStyleForLayoutObject();
// Step 4 of
Node* InsertAdjacent(const String& where, Node* new_child, ExceptionState&);
virtual void ParserDidSetAttributes() {}
void ScrollLayoutBoxBy(const ScrollToOptions*);
void ScrollLayoutBoxTo(const ScrollToOptions*);
void ScrollFrameBy(const ScrollToOptions*);
void ScrollFrameTo(const ScrollToOptions*);
bool HasElementFlag(ElementFlags mask) const {
return HasRareData() && HasElementFlagInternal(mask);
void SetElementFlag(ElementFlags, bool value = true);
void ClearElementFlag(ElementFlags);
bool HasElementFlagInternal(ElementFlags) const;
bool IsElementNode() const =
delete; // This will catch anyone doing an unnecessary check.
bool IsDocumentFragment() const =
delete; // This will catch anyone doing an unnecessary check.
bool IsDocumentNode() const =
delete; // This will catch anyone doing an unnecessary check.
bool CanAttachShadowRoot() const;
ShadowRoot& CreateShadowRootInternal();
void StyleAttributeChanged(const AtomicString& new_style_string,
void UpdatePresentationAttributeStyle();
void InlineStyleChanged();
void SetInlineStyleFromString(const AtomicString&);
void InvisibleAttributeChanged(const AtomicString& old_value,
const AtomicString& new_value);
// If the only inherited changes in the parent element are independent,
// these changes can be directly propagated to this element (the child).
// If these conditions are met, propagates the changes to the current style
// and returns the new style. Otherwise, returns null.
scoped_refptr<ComputedStyle> PropagateInheritedProperties();
// Recalculate the ComputedStyle for this element and return a
// StyleRecalcChange for propagation/traversal into child nodes.
StyleRecalcChange RecalcOwnStyle(const StyleRecalcChange);
void RebuildPseudoElementLayoutTree(PseudoId, WhitespaceAttacher&);
void RebuildFirstLetterLayoutTree();
void RebuildShadowRootLayoutTree(WhitespaceAttacher&);
inline void CheckForEmptyStyleChange(const Node* node_before_change,
const Node* node_after_change);
void UpdatePseudoElement(PseudoId, const StyleRecalcChange);
enum class StyleUpdatePhase {
void UpdateFirstLetterPseudoElement(StyleUpdatePhase);
inline PseudoElement* CreatePseudoElementIfNeeded(PseudoId);
void AttachPseudoElement(PseudoId, AttachContext&);
void DetachPseudoElement(PseudoId, bool performing_reattach);
ShadowRoot& CreateAndAttachShadowRoot(ShadowRootType);
// FIXME: Everyone should allow author shadows.
virtual bool AreAuthorShadowsAllowed() const { return true; }
virtual void DidAddUserAgentShadowRoot(ShadowRoot&) {}
virtual bool AlwaysCreateUserAgentShadowRoot() const { return false; }
enum SynchronizationOfLazyAttribute {
kNotInSynchronizationOfLazyAttribute = 0,
void DidAddAttribute(const QualifiedName&, const AtomicString&);
void WillModifyAttribute(const QualifiedName&,
const AtomicString& old_value,
const AtomicString& new_value);
void DidModifyAttribute(const QualifiedName&,
const AtomicString& old_value,
const AtomicString& new_value);
void DidRemoveAttribute(const QualifiedName&, const AtomicString& old_value);
void SynchronizeAllAttributes() const;
void SynchronizeAttribute(const QualifiedName&) const;
void UpdateId(const AtomicString& old_id, const AtomicString& new_id);
void UpdateId(TreeScope&,
const AtomicString& old_id,
const AtomicString& new_id);
void UpdateName(const AtomicString& old_name, const AtomicString& new_name);
void ClientQuads(Vector<FloatQuad>& quads);
NodeType getNodeType() const final;
bool ChildTypeAllowed(NodeType) const final;
void SetAttributeInternal(wtf_size_t index,
const QualifiedName&,
const AtomicString& value,
void AppendAttributeInternal(const QualifiedName&,
const AtomicString& value,
void RemoveAttributeInternal(wtf_size_t index,
std::pair<wtf_size_t, const QualifiedName> LookupAttributeQNameInternal(
const AtomicString& local_name) const;
SpecificTrustedType ExpectedTrustedTypeForAttribute(
const QualifiedName&) const;
void CancelFocusAppearanceUpdate();
virtual int DefaultTabIndex() const;
const ComputedStyle* VirtualEnsureComputedStyle(
PseudoId pseudo_element_specifier = kPseudoIdNone) override {
return EnsureComputedStyle(pseudo_element_specifier);
inline void UpdateCallbackSelectors(const ComputedStyle* old_style,
const ComputedStyle* new_style);
// Clone is private so that non-virtual CloneElementWithChildren and
// CloneElementWithoutChildren are used instead.
Node* Clone(Document&, CloneChildrenFlag) const override;
virtual Element& CloneWithoutAttributesAndChildren(Document& factory) const;
QualifiedName tag_name_;
void UpdateNamedItemRegistration(NamedItemType,
const AtomicString& old_name,
const AtomicString& new_name);
void UpdateIdNamedItemRegistration(NamedItemType,
const AtomicString& old_name,
const AtomicString& new_name);
void CreateUniqueElementData();
bool ShouldInvalidateDistributionWhenAttributeChanged(ShadowRoot&,
const QualifiedName&,
const AtomicString&);
ElementRareData* GetElementRareData() const;
ElementRareData& EnsureElementRareData();
void RemoveAttrNodeList();
void DetachAllAttrNodesFromElement();
void DetachAttrNodeFromElementWithValue(Attr*, const AtomicString& value);
void DetachAttrNodeAtIndex(Attr*, wtf_size_t index);
bool DisplayLockPreventsActivation(DisplayLockActivationReason reason) const;
// Return whether this element type requires legacy layout.
virtual bool TypeShouldForceLegacyLayout() const { return false; }
// Return whether the computed style of this element causes need for legacy
// layout.
bool StyleShouldForceLegacyLayout() const {
if (!HasRareData())
return false;
return StyleShouldForceLegacyLayoutInternal();
bool StyleShouldForceLegacyLayoutInternal() const;
void SetStyleShouldForceLegacyLayout(bool force) {
if (!force && !HasRareData())
void SetStyleShouldForceLegacyLayoutInternal(bool);
// Return whether this element needs legacy layout because of a child.
bool ShouldForceLegacyLayoutForChild() const {
if (!HasRareData())
return false;
return ShouldForceLegacyLayoutForChildInternal();
bool ShouldForceLegacyLayoutForChildInternal() const;
void SetShouldForceLegacyLayoutForChild(bool force) {
if (!force && !HasRareData())
void SetShouldForceLegacyLayoutForChildInternal(bool);
// Update ForceLegacyLayout flags for this element, and for ancestors, if
// necessary. We cannot establish a ForceLegacyLayout subtree at an arbitrary
// element; it needs to be a block formatting context root.
void UpdateForceLegacyLayout(const ComputedStyle& new_style,
const ComputedStyle* old_style);
// If this element requires legacy layout, and we can't tell for sure that it
// is going to establish a new formatting context, we need to force legacy
// layout on ancestors until we reach one that we're sure that will establish
// a new formatting context. LayoutNG and legacy layout cannot cooperate
// within a formatting context.
void ForceLegacyLayoutInFormattingContext(const ComputedStyle& new_style);
// If this element requires legacy layout, and we're inside a fragmentation
// context, we need to force legacy layout for the entire fragmentation
// context. LayoutNG block fragmentation and legacy block fragmentation cannot
// cooperate within a fragmentation context.
void ForceLegacyLayoutInFragmentationContext(const ComputedStyle& new_style);
void SynchronizeContentAttributeAndElementReference(
const QualifiedName& name);
Member<ElementData> element_data_;
DEFINE_NODE_TYPE_CASTS(Element, IsElementNode());
template <typename T>
bool IsElementOfType(const Node&);
template <>
inline bool IsElementOfType<const Element>(const Node& node) {
return node.IsElementNode();
template <typename T>
inline bool IsElementOfType(const Element& element) {
return IsElementOfType<T>(static_cast<const Node&>(element));
template <>
inline bool IsElementOfType<const Element>(const Element&) {
return true;
template <>
struct DowncastTraits<Element> {
static bool AllowFrom(const Node& node) { return node.IsElementNode(); }
// Type casting.
template <typename T>
inline T& ToElement(Node& node) {
SECURITY_DCHECK(IsElementOfType<const T>(node));
return static_cast<T&>(node);
template <typename T>
inline T* ToElement(Node* node) {
SECURITY_DCHECK(!node || IsElementOfType<const T>(*node));
return static_cast<T*>(node);
template <typename T>
inline const T& ToElement(const Node& node) {
SECURITY_DCHECK(IsElementOfType<const T>(node));
return static_cast<const T&>(node);
template <typename T>
inline const T* ToElement(const Node* node) {
SECURITY_DCHECK(!node || IsElementOfType<const T>(*node));
return static_cast<const T*>(node);
inline bool IsDisabledFormControl(const Node* node) {
auto* element = DynamicTo<Element>(node);
return element && element->IsDisabledFormControl();
inline Element* Node::parentElement() const {
return DynamicTo<Element>(parentNode());
inline bool Element::FastHasAttribute(const QualifiedName& name) const {
<< TagQName().ToString().Utf8() << "/@" << name.ToString().Utf8();
return GetElementData() &&
GetElementData()->Attributes().FindIndex(name) != kNotFound;
inline const AtomicString& Element::FastGetAttribute(
const QualifiedName& name) const {
<< TagQName().ToString().Utf8() << "/@" << name.ToString().Utf8();
if (GetElementData()) {
if (const Attribute* attribute = GetElementData()->Attributes().Find(name))
return attribute->Value();
return g_null_atom;
inline AttributeCollection Element::Attributes() const {
if (!GetElementData())
return AttributeCollection();
return GetElementData()->Attributes();
inline AttributeCollection Element::AttributesWithoutUpdate() const {
if (!GetElementData())
return AttributeCollection();
return GetElementData()->Attributes();
inline bool Element::hasAttributes() const {
return !Attributes().IsEmpty();
inline const AtomicString& Element::IdForStyleResolution() const {
return GetElementData()->IdForStyleResolution();
inline const AtomicString& Element::GetIdAttribute() const {
return HasID() ? FastGetAttribute(html_names::kIdAttr) : g_null_atom;
inline const AtomicString& Element::GetNameAttribute() const {
return HasName() ? FastGetAttribute(html_names::kNameAttr) : g_null_atom;
inline const AtomicString& Element::GetClassAttribute() const {
if (!HasClass())
return g_null_atom;
if (IsSVGElement())
return getAttribute(html_names::kClassAttr);
return FastGetAttribute(html_names::kClassAttr);
inline void Element::SetIdAttribute(const AtomicString& value) {
setAttribute(html_names::kIdAttr, value);
inline const SpaceSplitString& Element::ClassNames() const {
return GetElementData()->ClassNames();
inline bool Element::HasClassName(const AtomicString& class_name) const {
return HasClass() && ClassNames().Contains(class_name);
inline bool Element::HasID() const {
return GetElementData() && GetElementData()->HasID();
inline bool Element::HasClass() const {
return GetElementData() && GetElementData()->HasClass();
inline UniqueElementData& Element::EnsureUniqueElementData() {
if (!GetElementData() || !GetElementData()->IsUnique())
return To<UniqueElementData>(*element_data_);
inline void Element::InvalidateStyleAttribute() {
GetElementData()->style_attribute_is_dirty_ = true;
inline const CSSPropertyValueSet* Element::PresentationAttributeStyle() {
if (!GetElementData())
return nullptr;
if (GetElementData()->presentation_attribute_style_is_dirty_)
// Need to call elementData() again since updatePresentationAttributeStyle()
// might swap it with a UniqueElementData.
return GetElementData()->PresentationAttributeStyle();
inline void Element::SetTagNameForCreateElementNS(
const QualifiedName& tag_name) {
// We expect this method to be called only to reset the prefix.
DCHECK_EQ(tag_name.LocalName(), tag_name_.LocalName());
DCHECK_EQ(tag_name.NamespaceURI(), tag_name_.NamespaceURI());
tag_name_ = tag_name;
inline bool IsShadowHost(const Node* node) {
return node && node->GetShadowRoot();
inline bool IsShadowHost(const Node& node) {
return node.GetShadowRoot();
inline bool IsShadowHost(const Element* element) {
return element && element->GetShadowRoot();
inline bool IsShadowHost(const Element& element) {
return element.GetShadowRoot();
inline bool IsAtShadowBoundary(const Element* element) {
if (!element)
return false;
ContainerNode* parent_node = element->parentNode();
return parent_node && parent_node->IsShadowRoot();
// These macros do the same as their NODE equivalents but additionally provide a
// template specialization for isElementOfType<>() so that the Traversal<> API
// works for these Element types.
#define DEFINE_ELEMENT_TYPE_CASTS(thisType, predicate) \
template <> \
inline bool IsElementOfType<const thisType>(const Node& node) { \
return node.predicate; \
} \
DEFINE_NODE_TYPE_CASTS(thisType, predicate)
template <> \
inline bool IsElementOfType<const thisType>(const Node& node) { \
return Is##thisType(node); \
} \
} // namespace blink