2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Peter Kelly (pmk@post.com)
5 * (C) 2001 Dirk Mueller (mueller@kde.org)
6 * (C) 2007 David Smith (catfish.man@gmail.com)
7 * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
8 * (C) 2007 Eric Seidel (eric@webkit.org)
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
29 #include "AXObjectCache.h"
31 #include "AttributeChangeInvalidation.h"
32 #include "CSSAnimationController.h"
33 #include "CSSParser.h"
35 #include "ChromeClient.h"
36 #include "ClassChangeInvalidation.h"
37 #include "ComposedTreeAncestorIterator.h"
38 #include "ContainerNodeAlgorithms.h"
39 #include "CustomElementReactionQueue.h"
40 #include "CustomElementRegistry.h"
42 #include "DOMRectList.h"
43 #include "DOMTokenList.h"
44 #include "DocumentSharedObjectPool.h"
45 #include "DocumentTimeline.h"
47 #include "ElementIterator.h"
48 #include "ElementRareData.h"
49 #include "EventDispatcher.h"
50 #include "EventHandler.h"
51 #include "EventNames.h"
52 #include "FocusController.h"
53 #include "FocusEvent.h"
55 #include "FrameSelection.h"
56 #include "FrameView.h"
57 #include "HTMLBodyElement.h"
58 #include "HTMLCanvasElement.h"
59 #include "HTMLCollection.h"
60 #include "HTMLDocument.h"
61 #include "HTMLHtmlElement.h"
62 #include "HTMLLabelElement.h"
63 #include "HTMLNameCollection.h"
64 #include "HTMLObjectElement.h"
65 #include "HTMLOptGroupElement.h"
66 #include "HTMLOptionElement.h"
67 #include "HTMLParserIdioms.h"
68 #include "HTMLSelectElement.h"
69 #include "HTMLTemplateElement.h"
70 #include "IdChangeInvalidation.h"
71 #include "IdTargetObserverRegistry.h"
72 #include "InspectorInstrumentation.h"
73 #include "JSLazyEventListener.h"
74 #include "KeyboardEvent.h"
75 #include "KeyframeEffect.h"
76 #include "MutationObserverInterestGroup.h"
77 #include "MutationRecord.h"
78 #include "NodeRenderStyle.h"
79 #include "PlatformWheelEvent.h"
80 #include "PointerLockController.h"
81 #include "RenderFragmentContainer.h"
82 #include "RenderLayer.h"
83 #include "RenderListBox.h"
84 #include "RenderTheme.h"
85 #include "RenderTreeUpdater.h"
86 #include "RenderView.h"
87 #include "RenderWidget.h"
88 #include "RuntimeEnabledFeatures.h"
89 #include "SVGDocumentExtensions.h"
90 #include "SVGElement.h"
92 #include "SVGSVGElement.h"
93 #include "ScriptDisallowedScope.h"
94 #include "ScrollLatchingState.h"
95 #include "SelectorQuery.h"
97 #include "SimulatedClick.h"
98 #include "SlotAssignment.h"
99 #include "StyleProperties.h"
100 #include "StyleResolver.h"
101 #include "StyleScope.h"
102 #include "StyleTreeResolver.h"
103 #include "TextIterator.h"
104 #include "VoidCallback.h"
105 #include "WebAnimation.h"
106 #include "WheelEvent.h"
107 #include "XLinkNames.h"
108 #include "XMLNSNames.h"
109 #include "XMLNames.h"
111 #include <wtf/IsoMallocInlines.h>
112 #include <wtf/NeverDestroyed.h>
113 #include <wtf/text/CString.h>
117 WTF_MAKE_ISO_ALLOCATED_IMPL(Element);
119 using namespace HTMLNames;
120 using namespace XMLNames;
122 static HashMap<Element*, Vector<RefPtr<Attr>>>& attrNodeListMap()
124 static NeverDestroyed<HashMap<Element*, Vector<RefPtr<Attr>>>> map;
128 static Vector<RefPtr<Attr>>* attrNodeListForElement(Element& element)
130 if (!element.hasSyntheticAttrChildNodes())
132 ASSERT(attrNodeListMap().contains(&element));
133 return &attrNodeListMap().find(&element)->value;
136 static Vector<RefPtr<Attr>>& ensureAttrNodeListForElement(Element& element)
138 if (element.hasSyntheticAttrChildNodes()) {
139 ASSERT(attrNodeListMap().contains(&element));
140 return attrNodeListMap().find(&element)->value;
142 ASSERT(!attrNodeListMap().contains(&element));
143 element.setHasSyntheticAttrChildNodes(true);
144 return attrNodeListMap().add(&element, Vector<RefPtr<Attr>>()).iterator->value;
147 static void removeAttrNodeListForElement(Element& element)
149 ASSERT(element.hasSyntheticAttrChildNodes());
150 ASSERT(attrNodeListMap().contains(&element));
151 attrNodeListMap().remove(&element);
152 element.setHasSyntheticAttrChildNodes(false);
155 static Attr* findAttrNodeInList(Vector<RefPtr<Attr>>& attrNodeList, const QualifiedName& name)
157 for (auto& node : attrNodeList) {
158 if (node->qualifiedName().matches(name))
164 static Attr* findAttrNodeInList(Vector<RefPtr<Attr>>& attrNodeList, const AtomicString& localName, bool shouldIgnoreAttributeCase)
166 const AtomicString& caseAdjustedName = shouldIgnoreAttributeCase ? localName.convertToASCIILowercase() : localName;
167 for (auto& node : attrNodeList) {
168 if (node->qualifiedName().localName() == caseAdjustedName)
174 Ref<Element> Element::create(const QualifiedName& tagName, Document& document)
176 return adoptRef(*new Element(tagName, document, CreateElement));
179 Element::Element(const QualifiedName& tagName, Document& document, ConstructionType type)
180 : ContainerNode(document, type)
187 ASSERT(!beforePseudoElement());
188 ASSERT(!afterPseudoElement());
192 if (hasSyntheticAttrChildNodes())
193 detachAllAttrNodesFromElement();
195 if (hasPendingResources()) {
196 document().accessSVGExtensions().removeElementFromPendingResources(this);
197 ASSERT(!hasPendingResources());
201 inline ElementRareData* Element::elementRareData() const
203 ASSERT_WITH_SECURITY_IMPLICATION(hasRareData());
204 return static_cast<ElementRareData*>(rareData());
207 inline ElementRareData& Element::ensureElementRareData()
209 return static_cast<ElementRareData&>(ensureRareData());
212 void Element::clearTabIndexExplicitlyIfNeeded()
215 elementRareData()->clearTabIndexExplicitly();
218 void Element::setTabIndexExplicitly(int tabIndex)
220 ensureElementRareData().setTabIndexExplicitly(tabIndex);
223 bool Element::tabIndexSetExplicitly() const
225 return hasRareData() && elementRareData()->tabIndexSetExplicitly();
228 bool Element::supportsFocus() const
230 return tabIndexSetExplicitly();
233 RefPtr<Element> Element::focusDelegate()
238 int Element::tabIndex() const
240 return hasRareData() ? elementRareData()->tabIndex() : 0;
243 void Element::setTabIndex(int value)
245 setIntegralAttribute(tabindexAttr, value);
248 bool Element::isKeyboardFocusable(KeyboardEvent*) const
250 return isFocusable() && tabIndex() >= 0;
253 bool Element::isMouseFocusable() const
255 return isFocusable();
258 bool Element::shouldUseInputMethod()
260 return computeEditability(UserSelectAllIsAlwaysNonEditable, ShouldUpdateStyle::Update) != Editability::ReadOnly;
263 static bool isForceEvent(const PlatformMouseEvent& platformEvent)
265 return platformEvent.type() == PlatformEvent::MouseForceChanged || platformEvent.type() == PlatformEvent::MouseForceDown || platformEvent.type() == PlatformEvent::MouseForceUp;
268 bool Element::dispatchMouseEvent(const PlatformMouseEvent& platformEvent, const AtomicString& eventType, int detail, Element* relatedTarget)
270 if (isDisabledFormControl())
273 if (isForceEvent(platformEvent) && !document().hasListenerTypeForEventType(platformEvent.type()))
276 Ref<MouseEvent> mouseEvent = MouseEvent::create(eventType, document().windowProxy(), platformEvent, detail, relatedTarget);
278 if (mouseEvent->type().isEmpty())
279 return true; // Shouldn't happen.
281 ASSERT(!mouseEvent->target() || mouseEvent->target() != relatedTarget);
282 dispatchEvent(mouseEvent);
283 bool didNotSwallowEvent = !mouseEvent->defaultPrevented() && !mouseEvent->defaultHandled();
285 if (mouseEvent->type() == eventNames().clickEvent && mouseEvent->detail() == 2) {
286 // Special case: If it's a double click event, we also send the dblclick event. This is not part
287 // of the DOM specs, but is used for compatibility with the ondblclick="" attribute. This is treated
288 // as a separate event in other DOM-compliant browsers like Firefox, and so we do the same.
289 Ref<MouseEvent> doubleClickEvent = MouseEvent::create(eventNames().dblclickEvent,
290 mouseEvent->bubbles(), mouseEvent->cancelable(), mouseEvent->view(), mouseEvent->detail(),
291 mouseEvent->screenX(), mouseEvent->screenY(), mouseEvent->clientX(), mouseEvent->clientY(),
292 mouseEvent->ctrlKey(), mouseEvent->altKey(), mouseEvent->shiftKey(), mouseEvent->metaKey(),
293 mouseEvent->button(), mouseEvent->buttons(), mouseEvent->syntheticClickType(), relatedTarget);
295 if (mouseEvent->defaultHandled())
296 doubleClickEvent->setDefaultHandled();
298 dispatchEvent(doubleClickEvent);
299 if (doubleClickEvent->defaultHandled() || doubleClickEvent->defaultPrevented())
302 return didNotSwallowEvent;
305 bool Element::dispatchWheelEvent(const PlatformWheelEvent& platformEvent)
307 auto event = WheelEvent::create(platformEvent, document().windowProxy());
309 // Events with no deltas are important because they convey platform information about scroll gestures
310 // and momentum beginning or ending. However, those events should not be sent to the DOM since some
311 // websites will break. They need to be dispatched because dispatching them will call into the default
312 // event handler, and our platform code will correctly handle the phase changes. Calling stopPropogation()
313 // will prevent the event from being sent to the DOM, but will still call the default event handler.
314 // FIXME: Move this logic into WheelEvent::create.
315 if (!platformEvent.deltaX() && !platformEvent.deltaY())
316 event->stopPropagation();
318 dispatchEvent(event);
319 return !event->defaultPrevented() && !event->defaultHandled();
322 bool Element::dispatchKeyEvent(const PlatformKeyboardEvent& platformEvent)
324 auto event = KeyboardEvent::create(platformEvent, document().windowProxy());
326 if (Frame* frame = document().frame()) {
327 if (frame->eventHandler().accessibilityPreventsEventPropagation(event))
328 event->stopPropagation();
331 dispatchEvent(event);
332 return !event->defaultPrevented() && !event->defaultHandled();
335 void Element::dispatchSimulatedClick(Event* underlyingEvent, SimulatedClickMouseEventOptions eventOptions, SimulatedClickVisualOptions visualOptions)
337 simulateClick(*this, underlyingEvent, eventOptions, visualOptions, SimulatedClickSource::UserAgent);
340 Ref<Node> Element::cloneNodeInternal(Document& targetDocument, CloningOperation type)
343 case CloningOperation::OnlySelf:
344 case CloningOperation::SelfWithTemplateContent:
345 return cloneElementWithoutChildren(targetDocument);
346 case CloningOperation::Everything:
349 return cloneElementWithChildren(targetDocument);
352 Ref<Element> Element::cloneElementWithChildren(Document& targetDocument)
354 Ref<Element> clone = cloneElementWithoutChildren(targetDocument);
355 cloneChildNodes(clone);
359 Ref<Element> Element::cloneElementWithoutChildren(Document& targetDocument)
361 Ref<Element> clone = cloneElementWithoutAttributesAndChildren(targetDocument);
363 // This will catch HTML elements in the wrong namespace that are not correctly copied.
364 // This is a sanity check as HTML overloads some of the DOM methods.
365 ASSERT(isHTMLElement() == clone->isHTMLElement());
367 clone->cloneDataFromElement(*this);
371 Ref<Element> Element::cloneElementWithoutAttributesAndChildren(Document& targetDocument)
373 return targetDocument.createElement(tagQName(), false);
376 Ref<Attr> Element::detachAttribute(unsigned index)
378 ASSERT(elementData());
380 const Attribute& attribute = elementData()->attributeAt(index);
382 RefPtr<Attr> attrNode = attrIfExists(attribute.name());
384 detachAttrNodeFromElementWithValue(attrNode.get(), attribute.value());
386 attrNode = Attr::create(document(), attribute.name(), attribute.value());
388 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
389 return attrNode.releaseNonNull();
392 bool Element::removeAttribute(const QualifiedName& name)
397 unsigned index = elementData()->findAttributeIndexByName(name);
398 if (index == ElementData::attributeNotFound)
401 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
405 void Element::setBooleanAttribute(const QualifiedName& name, bool value)
408 setAttribute(name, emptyAtom());
410 removeAttribute(name);
413 NamedNodeMap& Element::attributes() const
415 ElementRareData& rareData = const_cast<Element*>(this)->ensureElementRareData();
416 if (NamedNodeMap* attributeMap = rareData.attributeMap())
417 return *attributeMap;
419 rareData.setAttributeMap(std::make_unique<NamedNodeMap>(const_cast<Element&>(*this)));
420 return *rareData.attributeMap();
423 Node::NodeType Element::nodeType() const
428 bool Element::hasAttribute(const QualifiedName& name) const
430 return hasAttributeNS(name.namespaceURI(), name.localName());
433 void Element::synchronizeAllAttributes() const
437 if (elementData()->styleAttributeIsDirty()) {
438 ASSERT(isStyledElement());
439 static_cast<const StyledElement*>(this)->synchronizeStyleAttributeInternal();
442 if (elementData()->animatedSVGAttributesAreDirty()) {
443 ASSERT(isSVGElement());
444 downcast<SVGElement>(*this).synchronizeAnimatedSVGAttribute(anyQName());
448 ALWAYS_INLINE void Element::synchronizeAttribute(const QualifiedName& name) const
452 if (UNLIKELY(name == styleAttr && elementData()->styleAttributeIsDirty())) {
453 ASSERT_WITH_SECURITY_IMPLICATION(isStyledElement());
454 static_cast<const StyledElement*>(this)->synchronizeStyleAttributeInternal();
458 if (UNLIKELY(elementData()->animatedSVGAttributesAreDirty())) {
459 ASSERT(isSVGElement());
460 downcast<SVGElement>(*this).synchronizeAnimatedSVGAttribute(name);
464 static ALWAYS_INLINE bool isStyleAttribute(const Element& element, const AtomicString& attributeLocalName)
466 if (shouldIgnoreAttributeCase(element))
467 return equalLettersIgnoringASCIICase(attributeLocalName, "style");
468 return attributeLocalName == styleAttr->localName();
471 ALWAYS_INLINE void Element::synchronizeAttribute(const AtomicString& localName) const
473 // This version of synchronizeAttribute() is streamlined for the case where you don't have a full QualifiedName,
474 // e.g when called from DOM API.
477 if (elementData()->styleAttributeIsDirty() && isStyleAttribute(*this, localName)) {
478 ASSERT_WITH_SECURITY_IMPLICATION(isStyledElement());
479 static_cast<const StyledElement*>(this)->synchronizeStyleAttributeInternal();
482 if (elementData()->animatedSVGAttributesAreDirty()) {
483 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
484 ASSERT_WITH_SECURITY_IMPLICATION(isSVGElement());
485 downcast<SVGElement>(*this).synchronizeAnimatedSVGAttribute(QualifiedName(nullAtom(), localName, nullAtom()));
489 const AtomicString& Element::getAttribute(const QualifiedName& name) const
493 synchronizeAttribute(name);
494 if (const Attribute* attribute = findAttributeByName(name))
495 return attribute->value();
499 Vector<String> Element::getAttributeNames() const
501 Vector<String> attributesVector;
502 if (!hasAttributes())
503 return attributesVector;
505 auto attributes = attributesIterator();
506 attributesVector.reserveInitialCapacity(attributes.attributeCount());
507 for (auto& attribute : attributes)
508 attributesVector.uncheckedAppend(attribute.name().toString());
509 return attributesVector;
512 bool Element::isFocusable() const
514 if (!isConnected() || !supportsFocus())
518 // If the node is in a display:none tree it might say it needs style recalc but
519 // the whole document is actually up to date.
520 ASSERT(!needsStyleRecalc() || !document().childNeedsStyleRecalc());
522 // Elements in canvas fallback content are not rendered, but they are allowed to be
523 // focusable as long as their canvas is displayed and visible.
524 if (auto* canvas = ancestorsOfType<HTMLCanvasElement>(*this).first())
525 return canvas->renderer() && canvas->renderer()->style().visibility() == VISIBLE;
528 // FIXME: Even if we are not visible, we might have a child that is visible.
529 // Hyatt wants to fix that some day with a "has visible content" flag or the like.
530 if (!renderer() || renderer()->style().visibility() != VISIBLE)
536 bool Element::isUserActionElementInActiveChain() const
538 ASSERT(isUserActionElement());
539 return document().userActionElements().inActiveChain(*this);
542 bool Element::isUserActionElementActive() const
544 ASSERT(isUserActionElement());
545 return document().userActionElements().isActive(*this);
548 bool Element::isUserActionElementFocused() const
550 ASSERT(isUserActionElement());
551 return document().userActionElements().isFocused(*this);
554 bool Element::isUserActionElementHovered() const
556 ASSERT(isUserActionElement());
557 return document().userActionElements().isHovered(*this);
560 void Element::setActive(bool flag, bool pause)
562 if (flag == active())
565 document().userActionElements().setActive(*this, flag);
567 const RenderStyle* renderStyle = this->renderStyle();
568 bool reactsToPress = (renderStyle && renderStyle->affectedByActive()) || styleAffectedByActive();
570 invalidateStyleForSubtree();
575 if (renderer()->style().hasAppearance() && renderer()->theme().stateChanged(*renderer(), ControlStates::PressedState))
576 reactsToPress = true;
578 // The rest of this function implements a feature that only works if the
579 // platform supports immediate invalidations on the ChromeClient, so bail if
580 // that isn't supported.
581 if (!document().page()->chrome().client().supportsImmediateInvalidation())
584 if (reactsToPress && pause) {
585 // The delay here is subtle. It relies on an assumption, namely that the amount of time it takes
586 // to repaint the "down" state of the control is about the same time as it would take to repaint the
587 // "up" state. Once you assume this, you can just delay for 100ms - that time (assuming that after you
588 // leave this method, it will be about that long before the flush of the up state happens again).
589 #ifdef HAVE_FUNC_USLEEP
590 MonotonicTime startTime = MonotonicTime::now();
593 document().updateStyleIfNeeded();
595 // Do an immediate repaint.
597 renderer()->repaint();
599 // FIXME: Come up with a less ridiculous way of doing this.
600 #ifdef HAVE_FUNC_USLEEP
601 // Now pause for a small amount of time (1/10th of a second from before we repainted in the pressed state)
602 Seconds remainingTime = 100_ms - (MonotonicTime::now() - startTime);
603 if (remainingTime > 0_s)
604 usleep(static_cast<useconds_t>(remainingTime.microseconds()));
609 void Element::setFocus(bool flag)
611 if (flag == focused())
614 document().userActionElements().setFocused(*this, flag);
615 invalidateStyleForSubtree();
617 for (Element* element = this; element; element = element->parentElementInComposedTree())
618 element->setHasFocusWithin(flag);
621 void Element::setHovered(bool flag)
623 if (flag == hovered())
626 document().userActionElements().setHovered(*this, flag);
629 // When setting hover to false, the style needs to be recalc'd even when
630 // there's no renderer (imagine setting display:none in the :hover class,
631 // if a nil renderer would prevent this element from recalculating its
632 // style, it would never go back to its normal style and remain
633 // stuck in its hovered style).
635 invalidateStyleForSubtree();
640 if (renderer()->style().affectedByHover() || childrenAffectedByHover())
641 invalidateStyleForSubtree();
643 if (renderer()->style().hasAppearance())
644 renderer()->theme().stateChanged(*renderer(), ControlStates::HoverState);
647 void Element::scrollIntoView(bool alignToTop)
649 document().updateLayoutIgnorePendingStylesheets();
655 LayoutRect absoluteBounds = renderer()->absoluteAnchorRect(&insideFixed);
656 // Align to the top / bottom and to the closest edge.
658 renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
660 renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
663 void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
665 document().updateLayoutIgnorePendingStylesheets();
671 LayoutRect absoluteBounds = renderer()->absoluteAnchorRect(&insideFixed);
673 renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
675 renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
678 void Element::scrollIntoViewIfNotVisible(bool centerIfNotVisible)
680 document().updateLayoutIgnorePendingStylesheets();
686 LayoutRect absoluteBounds = renderer()->absoluteAnchorRect(&insideFixed);
687 if (centerIfNotVisible)
688 renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignCenterIfNotVisible, ScrollAlignment::alignCenterIfNotVisible);
690 renderer()->scrollRectToVisible(SelectionRevealMode::Reveal, absoluteBounds, insideFixed, ScrollAlignment::alignToEdgeIfNotVisible, ScrollAlignment::alignToEdgeIfNotVisible);
693 void Element::scrollBy(const ScrollToOptions& options)
695 return scrollBy(options.left.value_or(0), options.top.value_or(0));
698 static inline double normalizeNonFiniteValue(double f)
700 return std::isfinite(f) ? f : 0;
703 void Element::scrollBy(double x, double y)
705 scrollTo(scrollLeft() + normalizeNonFiniteValue(x), scrollTop() + normalizeNonFiniteValue(y));
708 void Element::scrollTo(const ScrollToOptions& options, ScrollClamping clamping)
710 // If the element is the root element and document is in quirks mode, terminate these steps.
711 // Note that WebKit always uses quirks mode document scrolling behavior. See Document::scrollingElement().
712 if (this == document().documentElement())
715 document().updateLayoutIgnorePendingStylesheets();
717 // If the element does not have any associated CSS layout box, the element has no associated scrolling box,
718 // or the element has no overflow, terminate these steps.
719 RenderBox* renderer = renderBox();
720 if (!renderer || !renderer->hasOverflowClip())
723 // Normalize non-finite values for left and top dictionary members of options, if present.
724 double x = options.left ? normalizeNonFiniteValue(options.left.value()) : adjustForAbsoluteZoom(renderer->scrollLeft(), *renderer);
725 double y = options.top ? normalizeNonFiniteValue(options.top.value()) : adjustForAbsoluteZoom(renderer->scrollTop(), *renderer);
727 renderer->setScrollLeft(clampToInteger(x * renderer->style().effectiveZoom()), clamping);
728 renderer->setScrollTop(clampToInteger(y * renderer->style().effectiveZoom()), clamping);
731 void Element::scrollTo(double x, double y)
736 void Element::scrollByUnits(int units, ScrollGranularity granularity)
738 document().updateLayoutIgnorePendingStylesheets();
740 auto* renderer = this->renderer();
744 if (!renderer->hasOverflowClip())
747 ScrollDirection direction = ScrollDown;
749 direction = ScrollUp;
752 Element* stopElement = this;
753 downcast<RenderBox>(*renderer).scroll(direction, granularity, units, &stopElement);
756 void Element::scrollByLines(int lines)
758 scrollByUnits(lines, ScrollByLine);
761 void Element::scrollByPages(int pages)
763 scrollByUnits(pages, ScrollByPage);
766 static double localZoomForRenderer(const RenderElement& renderer)
768 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
769 // other out, but the alternative is that we'd have to crawl up the whole render tree every
770 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
771 double zoomFactor = 1;
772 if (renderer.style().effectiveZoom() != 1) {
773 // Need to find the nearest enclosing RenderElement that set up
774 // a differing zoom, and then we divide our result by it to eliminate the zoom.
775 const RenderElement* prev = &renderer;
776 for (RenderElement* curr = prev->parent(); curr; curr = curr->parent()) {
777 if (curr->style().effectiveZoom() != prev->style().effectiveZoom()) {
778 zoomFactor = prev->style().zoom();
783 if (prev->isRenderView())
784 zoomFactor = prev->style().zoom();
789 static double adjustForLocalZoom(LayoutUnit value, const RenderElement& renderer, double& zoomFactor)
791 zoomFactor = localZoomForRenderer(renderer);
793 return value.toDouble();
794 return value.toDouble() / zoomFactor;
797 enum LegacyCSSOMElementMetricsRoundingStrategy { Round, Floor };
799 static bool subpixelMetricsEnabled(const Document& document)
801 return document.settings().subpixelCSSOMElementMetricsEnabled();
804 static double convertToNonSubpixelValueIfNeeded(double value, const Document& document, LegacyCSSOMElementMetricsRoundingStrategy roundStrategy = Round)
806 return subpixelMetricsEnabled(document) ? value : roundStrategy == Round ? round(value) : floor(value);
809 double Element::offsetLeft()
811 document().updateLayoutIgnorePendingStylesheets();
812 if (RenderBoxModelObject* renderer = renderBoxModelObject()) {
813 LayoutUnit offsetLeft = subpixelMetricsEnabled(renderer->document()) ? renderer->offsetLeft() : LayoutUnit(roundToInt(renderer->offsetLeft()));
814 double zoomFactor = 1;
815 double offsetLeftAdjustedWithZoom = adjustForLocalZoom(offsetLeft, *renderer, zoomFactor);
816 return convertToNonSubpixelValueIfNeeded(offsetLeftAdjustedWithZoom, renderer->document(), zoomFactor == 1 ? Floor : Round);
821 double Element::offsetTop()
823 document().updateLayoutIgnorePendingStylesheets();
824 if (RenderBoxModelObject* renderer = renderBoxModelObject()) {
825 LayoutUnit offsetTop = subpixelMetricsEnabled(renderer->document()) ? renderer->offsetTop() : LayoutUnit(roundToInt(renderer->offsetTop()));
826 double zoomFactor = 1;
827 double offsetTopAdjustedWithZoom = adjustForLocalZoom(offsetTop, *renderer, zoomFactor);
828 return convertToNonSubpixelValueIfNeeded(offsetTopAdjustedWithZoom, renderer->document(), zoomFactor == 1 ? Floor : Round);
833 double Element::offsetWidth()
835 document().updateLayoutIfDimensionsOutOfDate(*this, WidthDimensionsCheck);
836 if (RenderBoxModelObject* renderer = renderBoxModelObject()) {
837 LayoutUnit offsetWidth = subpixelMetricsEnabled(renderer->document()) ? renderer->offsetWidth() : LayoutUnit(roundToInt(renderer->offsetWidth()));
838 return convertToNonSubpixelValueIfNeeded(adjustLayoutUnitForAbsoluteZoom(offsetWidth, *renderer).toDouble(), renderer->document());
843 double Element::offsetHeight()
845 document().updateLayoutIfDimensionsOutOfDate(*this, HeightDimensionsCheck);
846 if (RenderBoxModelObject* renderer = renderBoxModelObject()) {
847 LayoutUnit offsetHeight = subpixelMetricsEnabled(renderer->document()) ? renderer->offsetHeight() : LayoutUnit(roundToInt(renderer->offsetHeight()));
848 return convertToNonSubpixelValueIfNeeded(adjustLayoutUnitForAbsoluteZoom(offsetHeight, *renderer).toDouble(), renderer->document());
853 Element* Element::bindingsOffsetParent()
855 Element* element = offsetParent();
856 if (!element || !element->isInShadowTree())
858 return element->containingShadowRoot()->mode() == ShadowRootMode::UserAgent ? nullptr : element;
861 Element* Element::offsetParent()
863 document().updateLayoutIgnorePendingStylesheets();
864 auto renderer = this->renderer();
867 auto offsetParent = renderer->offsetParent();
870 return offsetParent->element();
873 double Element::clientLeft()
875 document().updateLayoutIgnorePendingStylesheets();
877 if (auto* renderer = renderBox()) {
878 LayoutUnit clientLeft = subpixelMetricsEnabled(renderer->document()) ? renderer->clientLeft() : LayoutUnit(roundToInt(renderer->clientLeft()));
879 return convertToNonSubpixelValueIfNeeded(adjustLayoutUnitForAbsoluteZoom(clientLeft, *renderer).toDouble(), renderer->document());
884 double Element::clientTop()
886 document().updateLayoutIgnorePendingStylesheets();
888 if (auto* renderer = renderBox()) {
889 LayoutUnit clientTop = subpixelMetricsEnabled(renderer->document()) ? renderer->clientTop() : LayoutUnit(roundToInt(renderer->clientTop()));
890 return convertToNonSubpixelValueIfNeeded(adjustLayoutUnitForAbsoluteZoom(clientTop, *renderer).toDouble(), renderer->document());
895 double Element::clientWidth()
897 document().updateLayoutIfDimensionsOutOfDate(*this, WidthDimensionsCheck);
899 if (!document().hasLivingRenderTree())
902 RenderView& renderView = *document().renderView();
904 // When in strict mode, clientWidth for the document element should return the width of the containing frame.
905 // When in quirks mode, clientWidth for the body element should return the width of the containing frame.
906 bool inQuirksMode = document().inQuirksMode();
907 if ((!inQuirksMode && document().documentElement() == this) || (inQuirksMode && isHTMLElement() && document().bodyOrFrameset() == this))
908 return adjustForAbsoluteZoom(renderView.frameView().layoutWidth(), renderView);
910 if (RenderBox* renderer = renderBox()) {
911 LayoutUnit clientWidth = subpixelMetricsEnabled(renderer->document()) ? renderer->clientWidth() : LayoutUnit(roundToInt(renderer->clientWidth()));
912 return convertToNonSubpixelValueIfNeeded(adjustLayoutUnitForAbsoluteZoom(clientWidth, *renderer).toDouble(), renderer->document());
917 double Element::clientHeight()
919 document().updateLayoutIfDimensionsOutOfDate(*this, HeightDimensionsCheck);
920 if (!document().hasLivingRenderTree())
923 RenderView& renderView = *document().renderView();
925 // When in strict mode, clientHeight for the document element should return the height of the containing frame.
926 // When in quirks mode, clientHeight for the body element should return the height of the containing frame.
927 bool inQuirksMode = document().inQuirksMode();
928 if ((!inQuirksMode && document().documentElement() == this) || (inQuirksMode && isHTMLElement() && document().bodyOrFrameset() == this))
929 return adjustForAbsoluteZoom(renderView.frameView().layoutHeight(), renderView);
931 if (RenderBox* renderer = renderBox()) {
932 LayoutUnit clientHeight = subpixelMetricsEnabled(renderer->document()) ? renderer->clientHeight() : LayoutUnit(roundToInt(renderer->clientHeight()));
933 return convertToNonSubpixelValueIfNeeded(adjustLayoutUnitForAbsoluteZoom(clientHeight, *renderer).toDouble(), renderer->document());
938 int Element::scrollLeft()
940 document().updateLayoutIgnorePendingStylesheets();
942 if (auto* renderer = renderBox())
943 return adjustForAbsoluteZoom(renderer->scrollLeft(), *renderer);
947 int Element::scrollTop()
949 document().updateLayoutIgnorePendingStylesheets();
951 if (RenderBox* renderer = renderBox())
952 return adjustForAbsoluteZoom(renderer->scrollTop(), *renderer);
956 void Element::setScrollLeft(int newLeft)
958 document().updateLayoutIgnorePendingStylesheets();
960 if (auto* renderer = renderBox()) {
961 renderer->setScrollLeft(static_cast<int>(newLeft * renderer->style().effectiveZoom()));
962 if (auto* scrollableArea = renderer->layer())
963 scrollableArea->setScrolledProgrammatically(true);
967 void Element::setScrollTop(int newTop)
969 document().updateLayoutIgnorePendingStylesheets();
971 if (auto* renderer = renderBox()) {
972 renderer->setScrollTop(static_cast<int>(newTop * renderer->style().effectiveZoom()));
973 if (auto* scrollableArea = renderer->layer())
974 scrollableArea->setScrolledProgrammatically(true);
978 int Element::scrollWidth()
980 document().updateLayoutIfDimensionsOutOfDate(*this, WidthDimensionsCheck);
981 if (auto* renderer = renderBox())
982 return adjustForAbsoluteZoom(renderer->scrollWidth(), *renderer);
986 int Element::scrollHeight()
988 document().updateLayoutIfDimensionsOutOfDate(*this, HeightDimensionsCheck);
989 if (auto* renderer = renderBox())
990 return adjustForAbsoluteZoom(renderer->scrollHeight(), *renderer);
994 IntRect Element::boundsInRootViewSpace()
996 document().updateLayoutIgnorePendingStylesheets();
998 FrameView* view = document().view();
1002 Vector<FloatQuad> quads;
1004 if (isSVGElement() && renderer()) {
1005 // Get the bounding rectangle from the SVG model.
1006 SVGElement& svgElement = downcast<SVGElement>(*this);
1007 FloatRect localRect;
1008 if (svgElement.getBoundingBox(localRect))
1009 quads.append(renderer()->localToAbsoluteQuad(localRect));
1011 // Get the bounding rectangle from the box model.
1012 if (renderBoxModelObject())
1013 renderBoxModelObject()->absoluteQuads(quads);
1016 if (quads.isEmpty())
1019 IntRect result = quads[0].enclosingBoundingBox();
1020 for (size_t i = 1; i < quads.size(); ++i)
1021 result.unite(quads[i].enclosingBoundingBox());
1023 result = view->contentsToRootView(result);
1027 static bool layoutOverflowRectContainsAllDescendants(const RenderBox& renderBox)
1029 if (renderBox.isRenderView())
1032 if (!renderBox.element())
1035 // If there are any position:fixed inside of us, game over.
1036 if (auto* viewPositionedObjects = renderBox.view().positionedObjects()) {
1037 for (auto* positionedBox : *viewPositionedObjects) {
1038 if (positionedBox == &renderBox)
1040 if (positionedBox->isFixedPositioned() && renderBox.element()->contains(positionedBox->element()))
1045 if (renderBox.canContainAbsolutelyPositionedObjects()) {
1046 // Our layout overflow will include all descendant positioned elements.
1050 // This renderer may have positioned descendants whose containing block is some ancestor.
1051 if (auto* containingBlock = renderBox.containingBlockForAbsolutePosition()) {
1052 if (auto* positionedObjects = containingBlock->positionedObjects()) {
1053 for (auto* positionedBox : *positionedObjects) {
1054 if (positionedBox == &renderBox)
1056 if (renderBox.element()->contains(positionedBox->element()))
1064 LayoutRect Element::absoluteEventBounds(bool& boundsIncludeAllDescendantElements, bool& includesFixedPositionElements)
1066 boundsIncludeAllDescendantElements = false;
1067 includesFixedPositionElements = false;
1070 return LayoutRect();
1073 if (isSVGElement()) {
1074 // Get the bounding rectangle from the SVG model.
1075 SVGElement& svgElement = downcast<SVGElement>(*this);
1076 FloatRect localRect;
1077 if (svgElement.getBoundingBox(localRect, SVGLocatable::DisallowStyleUpdate))
1078 result = LayoutRect(renderer()->localToAbsoluteQuad(localRect, UseTransforms, &includesFixedPositionElements).boundingBox());
1080 auto* renderer = this->renderer();
1081 if (is<RenderBox>(renderer)) {
1082 auto& box = downcast<RenderBox>(*renderer);
1084 bool computedBounds = false;
1086 if (RenderFragmentedFlow* fragmentedFlow = box.enclosingFragmentedFlow()) {
1087 bool wasFixed = false;
1088 Vector<FloatQuad> quads;
1089 FloatRect localRect(0, 0, box.width(), box.height());
1090 if (fragmentedFlow->absoluteQuadsForBox(quads, &wasFixed, &box, localRect.y(), localRect.maxY())) {
1091 FloatRect quadBounds = quads[0].boundingBox();
1092 for (size_t i = 1; i < quads.size(); ++i)
1093 quadBounds.unite(quads[i].boundingBox());
1095 result = LayoutRect(quadBounds);
1096 computedBounds = true;
1098 // Probably columns. Just return the bounds of the multicol block for now.
1099 // FIXME: this doesn't handle nested columns.
1100 RenderElement* multicolContainer = fragmentedFlow->parent();
1101 if (multicolContainer && is<RenderBox>(multicolContainer)) {
1102 auto overflowRect = downcast<RenderBox>(*multicolContainer).layoutOverflowRect();
1103 result = LayoutRect(multicolContainer->localToAbsoluteQuad(FloatRect(overflowRect), UseTransforms, &includesFixedPositionElements).boundingBox());
1104 computedBounds = true;
1109 if (!computedBounds) {
1110 LayoutRect overflowRect = box.layoutOverflowRect();
1111 result = LayoutRect(box.localToAbsoluteQuad(FloatRect(overflowRect), UseTransforms, &includesFixedPositionElements).boundingBox());
1112 boundsIncludeAllDescendantElements = layoutOverflowRectContainsAllDescendants(box);
1115 result = LayoutRect(renderer->absoluteBoundingBoxRect(true /* useTransforms */, &includesFixedPositionElements));
1121 LayoutRect Element::absoluteEventBoundsOfElementAndDescendants(bool& includesFixedPositionElements)
1123 bool boundsIncludeDescendants;
1124 LayoutRect result = absoluteEventBounds(boundsIncludeDescendants, includesFixedPositionElements);
1125 if (boundsIncludeDescendants)
1128 for (auto& child : childrenOfType<Element>(*this)) {
1129 bool includesFixedPosition = false;
1130 LayoutRect childBounds = child.absoluteEventBoundsOfElementAndDescendants(includesFixedPosition);
1131 includesFixedPositionElements |= includesFixedPosition;
1132 result.unite(childBounds);
1138 LayoutRect Element::absoluteEventHandlerBounds(bool& includesFixedPositionElements)
1140 // This is not web-exposed, so don't call the FOUC-inducing updateLayoutIgnorePendingStylesheets().
1141 FrameView* frameView = document().view();
1143 return LayoutRect();
1145 return absoluteEventBoundsOfElementAndDescendants(includesFixedPositionElements);
1148 static std::optional<std::pair<RenderObject*, LayoutRect>> listBoxElementBoundingBox(Element& element)
1150 HTMLSelectElement* selectElement;
1152 if (is<HTMLOptionElement>(element)) {
1153 selectElement = downcast<HTMLOptionElement>(element).ownerSelectElement();
1155 } else if (is<HTMLOptGroupElement>(element)) {
1156 selectElement = downcast<HTMLOptGroupElement>(element).ownerSelectElement();
1159 return std::nullopt;
1161 if (!selectElement || !selectElement->renderer() || !is<RenderListBox>(selectElement->renderer()))
1162 return std::nullopt;
1164 auto& renderer = downcast<RenderListBox>(*selectElement->renderer());
1165 std::optional<LayoutRect> boundingBox;
1166 int optionIndex = 0;
1167 for (auto* item : selectElement->listItems()) {
1168 if (item == &element) {
1169 LayoutPoint additionOffset;
1170 boundingBox = renderer.itemBoundingBoxRect(additionOffset, optionIndex);
1173 } else if (isGroup && boundingBox) {
1174 if (item->parentNode() != &element)
1176 LayoutPoint additionOffset;
1177 boundingBox->setHeight(boundingBox->height() + renderer.itemBoundingBoxRect(additionOffset, optionIndex).height());
1183 return std::nullopt;
1185 return std::pair<RenderObject*, LayoutRect> { &renderer, boundingBox.value() };
1188 Ref<DOMRectList> Element::getClientRects()
1190 document().updateLayoutIgnorePendingStylesheets();
1192 RenderObject* renderer = this->renderer();
1193 Vector<FloatQuad> quads;
1195 if (auto pair = listBoxElementBoundingBox(*this)) {
1196 renderer = pair.value().first;
1197 quads.append(renderer->localToAbsoluteQuad(FloatQuad { pair.value().second }));
1198 } else if (auto* renderBoxModelObject = this->renderBoxModelObject())
1199 renderBoxModelObject->absoluteQuads(quads);
1201 // FIXME: Handle SVG elements.
1202 // FIXME: Handle table/inline-table with a caption.
1204 if (quads.isEmpty())
1205 return DOMRectList::create();
1207 document().convertAbsoluteToClientQuads(quads, renderer->style());
1208 return DOMRectList::create(quads);
1211 FloatRect Element::boundingClientRect()
1213 document().updateLayoutIgnorePendingStylesheets();
1215 RenderObject* renderer = this->renderer();
1216 Vector<FloatQuad> quads;
1217 if (isSVGElement() && renderer && !renderer->isSVGRoot()) {
1218 // Get the bounding rectangle from the SVG model.
1219 SVGElement& svgElement = downcast<SVGElement>(*this);
1220 FloatRect localRect;
1221 if (svgElement.getBoundingBox(localRect))
1222 quads.append(renderer->localToAbsoluteQuad(localRect));
1223 } else if (auto pair = listBoxElementBoundingBox(*this)) {
1224 renderer = pair.value().first;
1225 quads.append(renderer->localToAbsoluteQuad(FloatQuad { pair.value().second }));
1226 } else if (auto* renderBoxModelObject = this->renderBoxModelObject())
1227 renderBoxModelObject->absoluteQuads(quads);
1229 if (quads.isEmpty())
1232 FloatRect result = quads[0].boundingBox();
1233 for (size_t i = 1; i < quads.size(); ++i)
1234 result.unite(quads[i].boundingBox());
1236 document().convertAbsoluteToClientRect(result, renderer->style());
1240 Ref<DOMRect> Element::getBoundingClientRect()
1242 return DOMRect::create(boundingClientRect());
1245 // Note that this is not web-exposed, and does not use the same coordinate system as getBoundingClientRect() and friends.
1246 IntRect Element::clientRect() const
1248 if (RenderObject* renderer = this->renderer())
1249 return document().view()->contentsToRootView(renderer->absoluteBoundingBoxRect());
1253 IntRect Element::screenRect() const
1255 if (RenderObject* renderer = this->renderer())
1256 return document().view()->contentsToScreen(renderer->absoluteBoundingBoxRect());
1260 const AtomicString& Element::getAttribute(const AtomicString& localName) const
1264 synchronizeAttribute(localName);
1265 if (const Attribute* attribute = elementData()->findAttributeByName(localName, shouldIgnoreAttributeCase(*this)))
1266 return attribute->value();
1270 const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
1272 return getAttribute(QualifiedName(nullAtom(), localName, namespaceURI));
1275 ExceptionOr<void> Element::setAttribute(const AtomicString& localName, const AtomicString& value)
1277 if (!Document::isValidName(localName))
1278 return Exception { InvalidCharacterError };
1280 synchronizeAttribute(localName);
1281 auto caseAdjustedLocalName = shouldIgnoreAttributeCase(*this) ? localName.convertToASCIILowercase() : localName;
1282 unsigned index = elementData() ? elementData()->findAttributeIndexByName(caseAdjustedLocalName, false) : ElementData::attributeNotFound;
1283 auto name = index != ElementData::attributeNotFound ? attributeAt(index).name() : QualifiedName { nullAtom(), caseAdjustedLocalName, nullAtom() };
1284 setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute);
1289 void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
1291 synchronizeAttribute(name);
1292 unsigned index = elementData() ? elementData()->findAttributeIndexByName(name) : ElementData::attributeNotFound;
1293 setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute);
1296 void Element::setAttributeWithoutSynchronization(const QualifiedName& name, const AtomicString& value)
1298 unsigned index = elementData() ? elementData()->findAttributeIndexByName(name) : ElementData::attributeNotFound;
1299 setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute);
1302 void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value)
1304 unsigned index = elementData() ? elementData()->findAttributeIndexByName(name) : ElementData::attributeNotFound;
1305 setAttributeInternal(index, name, value, InSynchronizationOfLazyAttribute);
1308 inline void Element::setAttributeInternal(unsigned index, const QualifiedName& name, const AtomicString& newValue, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1310 if (newValue.isNull()) {
1311 if (index != ElementData::attributeNotFound)
1312 removeAttributeInternal(index, inSynchronizationOfLazyAttribute);
1316 if (index == ElementData::attributeNotFound) {
1317 addAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute);
1321 if (inSynchronizationOfLazyAttribute) {
1322 ensureUniqueElementData().attributeAt(index).setValue(newValue);
1326 const Attribute& attribute = attributeAt(index);
1327 QualifiedName attributeName = attribute.name();
1328 AtomicString oldValue = attribute.value();
1330 willModifyAttribute(attributeName, oldValue, newValue);
1332 if (newValue != oldValue) {
1333 Style::AttributeChangeInvalidation styleInvalidation(*this, name, oldValue, newValue);
1334 ensureUniqueElementData().attributeAt(index).setValue(newValue);
1337 didModifyAttribute(attributeName, oldValue, newValue);
1340 static inline AtomicString makeIdForStyleResolution(const AtomicString& value, bool inQuirksMode)
1343 return value.convertToASCIILowercase();
1347 void Element::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason)
1349 bool valueIsSameAsBefore = oldValue == newValue;
1351 if (!valueIsSameAsBefore) {
1352 if (name == HTMLNames::idAttr) {
1353 if (!oldValue.isEmpty())
1354 treeScope().idTargetObserverRegistry().notifyObservers(*oldValue.impl());
1355 if (!newValue.isEmpty())
1356 treeScope().idTargetObserverRegistry().notifyObservers(*newValue.impl());
1358 AtomicString oldId = elementData()->idForStyleResolution();
1359 AtomicString newId = makeIdForStyleResolution(newValue, document().inQuirksMode());
1360 if (newId != oldId) {
1361 Style::IdChangeInvalidation styleInvalidation(*this, oldId, newId);
1362 elementData()->setIdForStyleResolution(newId);
1364 } else if (name == classAttr)
1365 classAttributeChanged(newValue);
1366 else if (name == HTMLNames::nameAttr)
1367 elementData()->setHasNameAttribute(!newValue.isNull());
1368 else if (name == HTMLNames::pseudoAttr) {
1369 if (needsStyleInvalidation() && isInShadowTree())
1370 invalidateStyleForSubtree();
1372 else if (name == HTMLNames::slotAttr) {
1373 if (auto* parent = parentElement()) {
1374 if (auto* shadowRoot = parent->shadowRoot())
1375 shadowRoot->hostChildElementDidChangeSlotAttribute(*this, oldValue, newValue);
1380 parseAttribute(name, newValue);
1382 document().incDOMTreeVersion();
1384 if (UNLIKELY(isDefinedCustomElement()))
1385 CustomElementReactionQueue::enqueueAttributeChangedCallbackIfNeeded(*this, name, oldValue, newValue);
1387 if (valueIsSameAsBefore)
1390 invalidateNodeListAndCollectionCachesInAncestorsForAttribute(name);
1392 if (AXObjectCache* cache = document().existingAXObjectCache())
1393 cache->deferAttributeChangeIfNeeded(name, this);
1396 template <typename CharacterType>
1397 static inline bool classStringHasClassName(const CharacterType* characters, unsigned length)
1403 if (isNotHTMLSpace(characters[i]))
1406 } while (i < length);
1411 static inline bool classStringHasClassName(const AtomicString& newClassString)
1413 unsigned length = newClassString.length();
1418 if (newClassString.is8Bit())
1419 return classStringHasClassName(newClassString.characters8(), length);
1420 return classStringHasClassName(newClassString.characters16(), length);
1423 void Element::classAttributeChanged(const AtomicString& newClassString)
1425 // Note: We'll need ElementData, but it doesn't have to be UniqueElementData.
1427 ensureUniqueElementData();
1429 bool shouldFoldCase = document().inQuirksMode();
1430 bool newStringHasClasses = classStringHasClassName(newClassString);
1432 auto oldClassNames = elementData()->classNames();
1433 auto newClassNames = newStringHasClasses ? SpaceSplitString(newClassString, shouldFoldCase) : SpaceSplitString();
1435 Style::ClassChangeInvalidation styleInvalidation(*this, oldClassNames, newClassNames);
1436 elementData()->setClassNames(newClassNames);
1439 if (hasRareData()) {
1440 if (auto* classList = elementRareData()->classList())
1441 classList->associatedAttributeValueChanged(newClassString);
1445 URL Element::absoluteLinkURL() const
1450 AtomicString linkAttribute;
1451 if (hasTagName(SVGNames::aTag))
1452 linkAttribute = getAttribute(XLinkNames::hrefAttr);
1454 linkAttribute = getAttribute(HTMLNames::hrefAttr);
1456 if (linkAttribute.isEmpty())
1459 return document().completeURL(stripLeadingAndTrailingHTMLSpaces(linkAttribute));
1462 #if ENABLE(TOUCH_EVENTS)
1463 bool Element::allowsDoubleTapGesture() const
1465 if (renderStyle() && renderStyle()->touchAction() != TouchAction::Auto)
1468 Element* parent = parentElement();
1469 return !parent || parent->allowsDoubleTapGesture();
1473 StyleResolver& Element::styleResolver()
1475 if (auto* shadowRoot = containingShadowRoot())
1476 return shadowRoot->styleScope().resolver();
1478 return document().styleScope().resolver();
1481 ElementStyle Element::resolveStyle(const RenderStyle* parentStyle)
1483 return styleResolver().styleForElement(*this, parentStyle);
1486 static void invalidateForSiblingCombinators(Element* sibling)
1488 for (; sibling; sibling = sibling->nextElementSibling()) {
1489 if (sibling->styleIsAffectedByPreviousSibling())
1490 sibling->invalidateStyleInternal();
1491 if (sibling->descendantsAffectedByPreviousSibling()) {
1492 for (auto* siblingChild = sibling->firstElementChild(); siblingChild; siblingChild = siblingChild->nextElementSibling())
1493 siblingChild->invalidateStyleForSubtreeInternal();
1495 if (!sibling->affectsNextSiblingElementStyle())
1500 static void invalidateSiblingsIfNeeded(Element& element)
1502 if (!element.affectsNextSiblingElementStyle())
1504 auto* parent = element.parentElement();
1505 if (parent && parent->styleValidity() >= Style::Validity::SubtreeInvalid)
1508 invalidateForSiblingCombinators(element.nextElementSibling());
1511 void Element::invalidateStyle()
1513 Node::invalidateStyle(Style::Validity::ElementInvalid);
1514 invalidateSiblingsIfNeeded(*this);
1517 void Element::invalidateStyleAndLayerComposition()
1519 Node::invalidateStyle(Style::Validity::ElementInvalid, Style::InvalidationMode::RecompositeLayer);
1520 invalidateSiblingsIfNeeded(*this);
1523 void Element::invalidateStyleForSubtree()
1525 Node::invalidateStyle(Style::Validity::SubtreeInvalid);
1526 invalidateSiblingsIfNeeded(*this);
1529 void Element::invalidateStyleAndRenderersForSubtree()
1531 Node::invalidateStyle(Style::Validity::SubtreeAndRenderersInvalid);
1532 invalidateSiblingsIfNeeded(*this);
1535 void Element::invalidateStyleInternal()
1537 Node::invalidateStyle(Style::Validity::ElementInvalid);
1540 void Element::invalidateStyleForSubtreeInternal()
1542 Node::invalidateStyle(Style::Validity::SubtreeInvalid);
1545 bool Element::hasDisplayContents() const
1550 const RenderStyle* style = elementRareData()->computedStyle();
1551 return style && style->display() == CONTENTS;
1554 void Element::storeDisplayContentsStyle(std::unique_ptr<RenderStyle> style)
1556 ASSERT(style && style->display() == CONTENTS);
1557 ASSERT(!renderer() || isPseudoElement());
1558 ensureElementRareData().setComputedStyle(WTFMove(style));
1561 // Returns true is the given attribute is an event handler.
1562 // We consider an event handler any attribute that begins with "on".
1563 // It is a simple solution that has the advantage of not requiring any
1564 // code or configuration change if a new event handler is defined.
1566 bool Element::isEventHandlerAttribute(const Attribute& attribute) const
1568 return attribute.name().namespaceURI().isNull() && attribute.name().localName().startsWith("on");
1571 bool Element::isJavaScriptURLAttribute(const Attribute& attribute) const
1573 return isURLAttribute(attribute) && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(attribute.value()));
1576 void Element::stripScriptingAttributes(Vector<Attribute>& attributeVector) const
1578 attributeVector.removeAllMatching([this](auto& attribute) -> bool {
1579 return this->isEventHandlerAttribute(attribute)
1580 || this->isJavaScriptURLAttribute(attribute)
1581 || this->isHTMLContentAttribute(attribute);
1585 void Element::parserSetAttributes(const Vector<Attribute>& attributeVector)
1587 ASSERT(!isConnected());
1588 ASSERT(!parentNode());
1589 ASSERT(!m_elementData);
1591 if (!attributeVector.isEmpty()) {
1592 if (document().sharedObjectPool())
1593 m_elementData = document().sharedObjectPool()->cachedShareableElementDataWithAttributes(attributeVector);
1595 m_elementData = ShareableElementData::createWithAttributes(attributeVector);
1599 parserDidSetAttributes();
1601 // Use attributeVector instead of m_elementData because attributeChanged might modify m_elementData.
1602 for (const auto& attribute : attributeVector)
1603 attributeChanged(attribute.name(), nullAtom(), attribute.value(), ModifiedDirectly);
1606 void Element::parserDidSetAttributes()
1610 void Element::didMoveToNewDocument(Document& oldDocument, Document& newDocument)
1612 ASSERT_WITH_SECURITY_IMPLICATION(&document() == &newDocument);
1614 if (oldDocument.inQuirksMode() != document().inQuirksMode()) {
1615 // ElementData::m_classNames or ElementData::m_idForStyleResolution need to be updated with the right case.
1617 attributeChanged(idAttr, nullAtom(), getIdAttribute());
1619 attributeChanged(classAttr, nullAtom(), getAttribute(classAttr));
1622 if (UNLIKELY(isDefinedCustomElement()))
1623 CustomElementReactionQueue::enqueueAdoptedCallbackIfNeeded(*this, oldDocument, newDocument);
1626 bool Element::hasAttributes() const
1628 synchronizeAllAttributes();
1629 return elementData() && elementData()->length();
1632 bool Element::hasEquivalentAttributes(const Element* other) const
1634 synchronizeAllAttributes();
1635 other->synchronizeAllAttributes();
1636 if (elementData() == other->elementData())
1639 return elementData()->isEquivalent(other->elementData());
1640 if (other->elementData())
1641 return other->elementData()->isEquivalent(elementData());
1645 String Element::nodeName() const
1647 return m_tagName.toString();
1650 String Element::nodeNamePreservingCase() const
1652 return m_tagName.toString();
1655 ExceptionOr<void> Element::setPrefix(const AtomicString& prefix)
1657 auto result = checkSetPrefix(prefix);
1658 if (result.hasException())
1659 return result.releaseException();
1661 m_tagName.setPrefix(prefix.isEmpty() ? nullAtom() : prefix);
1665 const AtomicString& Element::imageSourceURL() const
1667 return attributeWithoutSynchronization(srcAttr);
1670 bool Element::rendererIsNeeded(const RenderStyle& style)
1672 return style.display() != NONE && style.display() != CONTENTS;
1675 RenderPtr<RenderElement> Element::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
1677 return RenderElement::createFor(*this, WTFMove(style));
1680 Node::InsertedIntoAncestorResult Element::insertedIntoAncestor(InsertionType insertionType, ContainerNode& parentOfInsertedTree)
1682 ContainerNode::insertedIntoAncestor(insertionType, parentOfInsertedTree);
1684 #if ENABLE(FULLSCREEN_API)
1685 if (containsFullScreenElement() && parentElement() && !parentElement()->containsFullScreenElement())
1686 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
1689 if (parentNode() == &parentOfInsertedTree) {
1690 if (auto* shadowRoot = parentNode()->shadowRoot())
1691 shadowRoot->hostChildElementDidChange(*this);
1694 if (!parentOfInsertedTree.isInTreeScope())
1695 return InsertedIntoAncestorResult::Done;
1697 bool becomeConnected = insertionType.connectedToDocument;
1698 TreeScope* newScope = &parentOfInsertedTree.treeScope();
1699 HTMLDocument* newDocument = becomeConnected && is<HTMLDocument>(newScope->documentScope()) ? &downcast<HTMLDocument>(newScope->documentScope()) : nullptr;
1700 if (!insertionType.treeScopeChanged)
1703 const AtomicString& idValue = getIdAttribute();
1704 if (!idValue.isNull()) {
1706 updateIdForTreeScope(*newScope, nullAtom(), idValue);
1708 updateIdForDocument(*newDocument, nullAtom(), idValue, AlwaysUpdateHTMLDocumentNamedItemMaps);
1711 const AtomicString& nameValue = getNameAttribute();
1712 if (!nameValue.isNull()) {
1714 updateNameForTreeScope(*newScope, nullAtom(), nameValue);
1716 updateNameForDocument(*newDocument, nullAtom(), nameValue);
1719 if (newScope && hasTagName(labelTag)) {
1720 if (newScope->shouldCacheLabelsByForAttribute())
1721 updateLabel(*newScope, nullAtom(), attributeWithoutSynchronization(forAttr));
1724 if (becomeConnected) {
1725 if (UNLIKELY(isCustomElementUpgradeCandidate()))
1726 CustomElementReactionQueue::enqueueElementUpgradeIfDefined(*this);
1727 if (UNLIKELY(isDefinedCustomElement()))
1728 CustomElementReactionQueue::enqueueConnectedCallbackIfNeeded(*this);
1731 return InsertedIntoAncestorResult::Done;
1734 void Element::removedFromAncestor(RemovalType removalType, ContainerNode& oldParentOfRemovedTree)
1736 #if ENABLE(FULLSCREEN_API)
1737 if (containsFullScreenElement())
1738 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
1740 #if ENABLE(POINTER_LOCK)
1741 if (document().page())
1742 document().page()->pointerLockController().elementRemoved(*this);
1745 setSavedLayerScrollPosition(ScrollPosition());
1747 if (oldParentOfRemovedTree.isInTreeScope()) {
1748 TreeScope* oldScope = &oldParentOfRemovedTree.treeScope();
1749 Document* oldDocument = removalType.disconnectedFromDocument ? &oldScope->documentScope() : nullptr;
1750 HTMLDocument* oldHTMLDocument = oldDocument && is<HTMLDocument>(*oldDocument) ? &downcast<HTMLDocument>(*oldDocument) : nullptr;
1751 if (!removalType.treeScopeChanged)
1754 const AtomicString& idValue = getIdAttribute();
1755 if (!idValue.isNull()) {
1757 updateIdForTreeScope(*oldScope, idValue, nullAtom());
1758 if (oldHTMLDocument)
1759 updateIdForDocument(*oldHTMLDocument, idValue, nullAtom(), AlwaysUpdateHTMLDocumentNamedItemMaps);
1762 const AtomicString& nameValue = getNameAttribute();
1763 if (!nameValue.isNull()) {
1765 updateNameForTreeScope(*oldScope, nameValue, nullAtom());
1766 if (oldHTMLDocument)
1767 updateNameForDocument(*oldHTMLDocument, nameValue, nullAtom());
1770 if (oldScope && hasTagName(labelTag)) {
1771 if (oldScope->shouldCacheLabelsByForAttribute())
1772 updateLabel(*oldScope, attributeWithoutSynchronization(forAttr), nullAtom());
1776 if (oldDocument->cssTarget() == this)
1777 oldDocument->setCSSTarget(nullptr);
1780 if (removalType.disconnectedFromDocument && UNLIKELY(isDefinedCustomElement()))
1781 CustomElementReactionQueue::enqueueDisconnectedCallbackIfNeeded(*this);
1784 if (!parentNode()) {
1785 if (auto* shadowRoot = oldParentOfRemovedTree.shadowRoot())
1786 shadowRoot->hostChildElementDidChange(*this);
1789 clearBeforePseudoElement();
1790 clearAfterPseudoElement();
1792 ContainerNode::removedFromAncestor(removalType, oldParentOfRemovedTree);
1794 if (hasPendingResources())
1795 document().accessSVGExtensions().removeElementFromPendingResources(this);
1797 RefPtr<Frame> frame = document().frame();
1798 if (RuntimeEnabledFeatures::sharedFeatures().cssAnimationsAndCSSTransitionsBackedByWebAnimationsEnabled()) {
1799 if (auto* timeline = document().existingTimeline())
1800 timeline->cancelDeclarativeAnimationsForElement(*this);
1802 frame->animation().cancelAnimations(*this);
1805 if (frame && frame->page())
1806 frame->page()->removeLatchingStateForTarget(*this);
1810 ShadowRoot* Element::shadowRoot() const
1812 return hasRareData() ? elementRareData()->shadowRoot() : nullptr;
1815 void Element::addShadowRoot(Ref<ShadowRoot>&& newShadowRoot)
1817 ASSERT(!newShadowRoot->hasChildNodes());
1818 ASSERT(!shadowRoot());
1820 ShadowRoot& shadowRoot = newShadowRoot;
1822 ScriptDisallowedScope::InMainThread scriptDisallowedScope;
1824 RenderTreeUpdater::tearDownRenderers(*this);
1826 ensureElementRareData().setShadowRoot(WTFMove(newShadowRoot));
1828 shadowRoot.setHost(this);
1829 shadowRoot.setParentTreeScope(treeScope());
1831 #if !ASSERT_DISABLED
1832 ASSERT(notifyChildNodeInserted(*this, shadowRoot).isEmpty());
1834 notifyChildNodeInserted(*this, shadowRoot);
1837 invalidateStyleAndRenderersForSubtree();
1840 if (shadowRoot.mode() == ShadowRootMode::UserAgent)
1841 didAddUserAgentShadowRoot(shadowRoot);
1843 InspectorInstrumentation::didPushShadowRoot(*this, shadowRoot);
1846 void Element::removeShadowRoot()
1848 RefPtr<ShadowRoot> oldRoot = shadowRoot();
1852 InspectorInstrumentation::willPopShadowRoot(*this, *oldRoot);
1853 document().removeFocusedNodeOfSubtree(*oldRoot);
1855 ASSERT(!oldRoot->renderer());
1857 elementRareData()->clearShadowRoot();
1859 oldRoot->setHost(nullptr);
1860 oldRoot->setParentTreeScope(document());
1863 static bool canAttachAuthorShadowRoot(const Element& element)
1865 static NeverDestroyed<HashSet<AtomicString>> tagNames = [] {
1866 static const HTMLQualifiedName* const tagList[] = {
1869 &blockquoteTag.get(),
1885 HashSet<AtomicString> set;
1886 for (auto& name : tagList)
1887 set.add(name->localName());
1891 if (!is<HTMLElement>(element))
1894 const auto& localName = element.localName();
1895 return tagNames.get().contains(localName) || Document::validateCustomElementName(localName) == CustomElementNameValidationStatus::Valid;
1898 ExceptionOr<ShadowRoot&> Element::attachShadow(const ShadowRootInit& init)
1900 if (!canAttachAuthorShadowRoot(*this))
1901 return Exception { NotSupportedError };
1903 return Exception { InvalidStateError };
1904 if (init.mode == ShadowRootMode::UserAgent)
1905 return Exception { TypeError };
1906 auto shadow = ShadowRoot::create(document(), init.mode);
1907 auto& result = shadow.get();
1908 addShadowRoot(WTFMove(shadow));
1912 ShadowRoot* Element::shadowRootForBindings(JSC::ExecState& state) const
1914 auto* shadow = shadowRoot();
1917 if (shadow->mode() == ShadowRootMode::Open)
1919 if (JSC::jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject())->world().shadowRootIsAlwaysOpen())
1924 RefPtr<ShadowRoot> Element::userAgentShadowRoot() const
1926 ASSERT(!shadowRoot() || shadowRoot()->mode() == ShadowRootMode::UserAgent);
1927 return shadowRoot();
1930 ShadowRoot& Element::ensureUserAgentShadowRoot()
1932 if (auto shadow = userAgentShadowRoot())
1934 auto newShadow = ShadowRoot::create(document(), ShadowRootMode::UserAgent);
1935 ShadowRoot& shadow = newShadow;
1936 addShadowRoot(WTFMove(newShadow));
1940 void Element::setIsDefinedCustomElement(JSCustomElementInterface& elementInterface)
1942 clearFlag(IsEditingTextOrUndefinedCustomElementFlag);
1943 setFlag(IsCustomElement);
1944 auto& data = ensureElementRareData();
1945 if (!data.customElementReactionQueue())
1946 data.setCustomElementReactionQueue(std::make_unique<CustomElementReactionQueue>(elementInterface));
1947 InspectorInstrumentation::didChangeCustomElementState(*this);
1950 void Element::setIsFailedCustomElement(JSCustomElementInterface&)
1952 ASSERT(isUndefinedCustomElement());
1953 ASSERT(getFlag(IsEditingTextOrUndefinedCustomElementFlag));
1954 clearFlag(IsCustomElement);
1956 if (hasRareData()) {
1957 // Clear the queue instead of deleting it since this function can be called inside CustomElementReactionQueue::invokeAll during upgrades.
1958 if (auto* queue = elementRareData()->customElementReactionQueue())
1961 InspectorInstrumentation::didChangeCustomElementState(*this);
1964 void Element::setIsCustomElementUpgradeCandidate()
1966 ASSERT(!getFlag(IsCustomElement));
1967 setFlag(IsCustomElement);
1968 setFlag(IsEditingTextOrUndefinedCustomElementFlag);
1969 InspectorInstrumentation::didChangeCustomElementState(*this);
1972 void Element::enqueueToUpgrade(JSCustomElementInterface& elementInterface)
1974 ASSERT(!isDefinedCustomElement() && !isFailedCustomElement());
1975 setFlag(IsCustomElement);
1976 setFlag(IsEditingTextOrUndefinedCustomElementFlag);
1977 InspectorInstrumentation::didChangeCustomElementState(*this);
1979 auto& data = ensureElementRareData();
1980 ASSERT(!data.customElementReactionQueue());
1982 data.setCustomElementReactionQueue(std::make_unique<CustomElementReactionQueue>(elementInterface));
1983 data.customElementReactionQueue()->enqueueElementUpgrade(*this);
1986 CustomElementReactionQueue* Element::reactionQueue() const
1988 ASSERT(isDefinedCustomElement() || isCustomElementUpgradeCandidate());
1991 return elementRareData()->customElementReactionQueue();
1994 const AtomicString& Element::shadowPseudoId() const
1999 bool Element::childTypeAllowed(NodeType type) const
2005 case PROCESSING_INSTRUCTION_NODE:
2006 case CDATA_SECTION_NODE:
2014 static void checkForEmptyStyleChange(Element& element)
2016 if (element.styleAffectedByEmpty()) {
2017 auto* style = element.renderStyle();
2018 if (!style || (!style->emptyState() || element.hasChildNodes()))
2019 element.invalidateStyleForSubtree();
2024 static void invalidateForForwardPositionalRules(Element& parent, Element* elementAfterChange)
2026 bool childrenAffected = parent.childrenAffectedByForwardPositionalRules();
2027 bool descendantsAffected = parent.descendantsAffectedByForwardPositionalRules();
2029 if (!childrenAffected && !descendantsAffected)
2032 for (auto* sibling = elementAfterChange; sibling; sibling = sibling->nextElementSibling()) {
2033 if (childrenAffected)
2034 sibling->invalidateStyleInternal();
2035 if (descendantsAffected) {
2036 for (auto* siblingChild = sibling->firstElementChild(); siblingChild; siblingChild = siblingChild->nextElementSibling())
2037 siblingChild->invalidateStyleForSubtreeInternal();
2042 static void invalidateForBackwardPositionalRules(Element& parent, Element* elementBeforeChange)
2044 bool childrenAffected = parent.childrenAffectedByBackwardPositionalRules();
2045 bool descendantsAffected = parent.descendantsAffectedByBackwardPositionalRules();
2047 if (!childrenAffected && !descendantsAffected)
2050 for (auto* sibling = elementBeforeChange; sibling; sibling = sibling->previousElementSibling()) {
2051 if (childrenAffected)
2052 sibling->invalidateStyleInternal();
2053 if (descendantsAffected) {
2054 for (auto* siblingChild = sibling->firstElementChild(); siblingChild; siblingChild = siblingChild->nextElementSibling())
2055 siblingChild->invalidateStyleForSubtreeInternal();
2060 enum SiblingCheckType { FinishedParsingChildren, SiblingElementRemoved, Other };
2062 static void checkForSiblingStyleChanges(Element& parent, SiblingCheckType checkType, Element* elementBeforeChange, Element* elementAfterChange)
2065 checkForEmptyStyleChange(parent);
2067 if (parent.styleValidity() >= Style::Validity::SubtreeInvalid)
2070 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
2071 // In the DOM case, we only need to do something if |afterChange| is not 0.
2072 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
2073 if (parent.childrenAffectedByFirstChildRules() && elementAfterChange) {
2074 // Find our new first child.
2075 RefPtr<Element> newFirstElement = ElementTraversal::firstChild(parent);
2076 // Find the first element node following |afterChange|
2078 // This is the insert/append case.
2079 if (newFirstElement != elementAfterChange) {
2080 auto* style = elementAfterChange->renderStyle();
2081 if (!style || style->firstChildState())
2082 elementAfterChange->invalidateStyleForSubtreeInternal();
2085 // We also have to handle node removal.
2086 if (checkType == SiblingElementRemoved && newFirstElement == elementAfterChange && newFirstElement) {
2087 auto* style = newFirstElement->renderStyle();
2088 if (!style || !style->firstChildState())
2089 newFirstElement->invalidateStyleForSubtreeInternal();
2093 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
2094 // In the DOM case, we only need to do something if |afterChange| is not 0.
2095 if (parent.childrenAffectedByLastChildRules() && elementBeforeChange) {
2096 // Find our new last child.
2097 RefPtr<Element> newLastElement = ElementTraversal::lastChild(parent);
2099 if (newLastElement != elementBeforeChange) {
2100 auto* style = elementBeforeChange->renderStyle();
2101 if (!style || style->lastChildState())
2102 elementBeforeChange->invalidateStyleForSubtreeInternal();
2105 // We also have to handle node removal. The parser callback case is similar to node removal as well in that we need to change the last child
2107 if ((checkType == SiblingElementRemoved || checkType == FinishedParsingChildren) && newLastElement == elementBeforeChange && newLastElement) {
2108 auto* style = newLastElement->renderStyle();
2109 if (!style || !style->lastChildState())
2110 newLastElement->invalidateStyleForSubtreeInternal();
2114 invalidateForSiblingCombinators(elementAfterChange);
2116 invalidateForForwardPositionalRules(parent, elementAfterChange);
2117 invalidateForBackwardPositionalRules(parent, elementBeforeChange);
2120 void Element::childrenChanged(const ChildChange& change)
2122 ContainerNode::childrenChanged(change);
2123 if (change.source == ChildChangeSource::Parser)
2124 checkForEmptyStyleChange(*this);
2126 SiblingCheckType checkType = change.type == ElementRemoved ? SiblingElementRemoved : Other;
2127 checkForSiblingStyleChanges(*this, checkType, change.previousSiblingElement, change.nextSiblingElement);
2130 if (ShadowRoot* shadowRoot = this->shadowRoot()) {
2131 switch (change.type) {
2132 case ElementInserted:
2133 case ElementRemoved:
2134 // For elements, we notify shadowRoot in Element::insertedInto and Element::removedFrom.
2136 case AllChildrenRemoved:
2137 case AllChildrenReplaced:
2138 shadowRoot->didRemoveAllChildrenOfShadowHost();
2143 shadowRoot->didChangeDefaultSlot();
2145 case NonContentsChildInserted:
2146 case NonContentsChildRemoved:
2152 void Element::setAttributeEventListener(const AtomicString& eventType, const QualifiedName& attributeName, const AtomicString& attributeValue)
2154 setAttributeEventListener(eventType, JSLazyEventListener::create(*this, attributeName, attributeValue), mainThreadNormalWorld());
2157 void Element::removeAllEventListeners()
2159 ContainerNode::removeAllEventListeners();
2160 if (ShadowRoot* shadowRoot = this->shadowRoot())
2161 shadowRoot->removeAllEventListeners();
2164 void Element::beginParsingChildren()
2166 clearIsParsingChildrenFinished();
2169 void Element::finishParsingChildren()
2171 ContainerNode::finishParsingChildren();
2172 setIsParsingChildrenFinished();
2173 checkForSiblingStyleChanges(*this, FinishedParsingChildren, ElementTraversal::lastChild(*this), nullptr);
2176 #if ENABLE(TREE_DEBUGGING)
2177 void Element::formatForDebugger(char* buffer, unsigned length) const
2179 StringBuilder result;
2182 result.append(nodeName());
2184 s = getIdAttribute();
2185 if (s.length() > 0) {
2186 if (result.length() > 0)
2187 result.appendLiteral("; ");
2188 result.appendLiteral("id=");
2192 s = getAttribute(classAttr);
2193 if (s.length() > 0) {
2194 if (result.length() > 0)
2195 result.appendLiteral("; ");
2196 result.appendLiteral("class=");
2200 strncpy(buffer, result.toString().utf8().data(), length - 1);
2204 const Vector<RefPtr<Attr>>& Element::attrNodeList()
2206 ASSERT(hasSyntheticAttrChildNodes());
2207 return *attrNodeListForElement(*this);
2210 void Element::attachAttributeNodeIfNeeded(Attr& attrNode)
2212 ASSERT(!attrNode.ownerElement() || attrNode.ownerElement() == this);
2213 if (attrNode.ownerElement() == this)
2216 ScriptDisallowedScope::InMainThread scriptDisallowedScope;
2218 attrNode.attachToElement(*this);
2219 ensureAttrNodeListForElement(*this).append(&attrNode);
2222 ExceptionOr<RefPtr<Attr>> Element::setAttributeNode(Attr& attrNode)
2224 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode.localName(), shouldIgnoreAttributeCase(*this));
2225 if (oldAttrNode.get() == &attrNode)
2226 return WTFMove(oldAttrNode);
2228 // InUseAttributeError: Raised if node is an Attr that is already an attribute of another Element object.
2229 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
2230 if (attrNode.ownerElement() && attrNode.ownerElement() != this)
2231 return Exception { InUseAttributeError };
2234 ScriptDisallowedScope::InMainThread scriptDisallowedScope;
2235 synchronizeAllAttributes();
2238 auto& elementData = ensureUniqueElementData();
2240 auto existingAttributeIndex = elementData.findAttributeIndexByName(attrNode.localName(), shouldIgnoreAttributeCase(*this));
2242 // Attr::value() will return its 'm_standaloneValue' member any time its Element is set to nullptr. We need to cache this value
2243 // before making changes to attrNode's Element connections.
2244 auto attrNodeValue = attrNode.value();
2246 if (existingAttributeIndex == ElementData::attributeNotFound) {
2247 attachAttributeNodeIfNeeded(attrNode);
2248 setAttributeInternal(elementData.findAttributeIndexByName(attrNode.qualifiedName()), attrNode.qualifiedName(), attrNodeValue, NotInSynchronizationOfLazyAttribute);
2250 const Attribute& attribute = attributeAt(existingAttributeIndex);
2252 detachAttrNodeFromElementWithValue(oldAttrNode.get(), attribute.value());
2254 oldAttrNode = Attr::create(document(), attrNode.qualifiedName(), attribute.value());
2256 attachAttributeNodeIfNeeded(attrNode);
2258 if (attribute.name().matches(attrNode.qualifiedName()))
2259 setAttributeInternal(existingAttributeIndex, attrNode.qualifiedName(), attrNodeValue, NotInSynchronizationOfLazyAttribute);
2261 removeAttributeInternal(existingAttributeIndex, NotInSynchronizationOfLazyAttribute);
2262 setAttributeInternal(ensureUniqueElementData().findAttributeIndexByName(attrNode.qualifiedName()), attrNode.qualifiedName(), attrNodeValue, NotInSynchronizationOfLazyAttribute);
2266 return WTFMove(oldAttrNode);
2269 ExceptionOr<RefPtr<Attr>> Element::setAttributeNodeNS(Attr& attrNode)
2271 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode.qualifiedName());
2272 if (oldAttrNode.get() == &attrNode)
2273 return WTFMove(oldAttrNode);
2275 // InUseAttributeError: Raised if node is an Attr that is already an attribute of another Element object.
2276 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
2277 if (attrNode.ownerElement() && attrNode.ownerElement() != this)
2278 return Exception { InUseAttributeError };
2280 // Attr::value() will return its 'm_standaloneValue' member any time its Element is set to nullptr. We need to cache this value
2281 // before making changes to attrNode's Element connections.
2282 auto attrNodeValue = attrNode.value();
2285 ScriptDisallowedScope::InMainThread scriptDisallowedScope;
2286 synchronizeAllAttributes();
2287 auto& elementData = ensureUniqueElementData();
2289 index = elementData.findAttributeIndexByName(attrNode.qualifiedName());
2291 if (index != ElementData::attributeNotFound) {
2293 detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData.attributeAt(index).value());
2295 oldAttrNode = Attr::create(document(), attrNode.qualifiedName(), elementData.attributeAt(index).value());
2299 attachAttributeNodeIfNeeded(attrNode);
2300 setAttributeInternal(index, attrNode.qualifiedName(), attrNodeValue, NotInSynchronizationOfLazyAttribute);
2302 return WTFMove(oldAttrNode);
2305 ExceptionOr<Ref<Attr>> Element::removeAttributeNode(Attr& attr)
2307 if (attr.ownerElement() != this)
2308 return Exception { NotFoundError };
2310 ASSERT(&document() == &attr.document());
2312 synchronizeAllAttributes();
2315 return Exception { NotFoundError };
2317 auto existingAttributeIndex = m_elementData->findAttributeIndexByName(attr.qualifiedName());
2318 if (existingAttributeIndex == ElementData::attributeNotFound)
2319 return Exception { NotFoundError };
2321 Ref<Attr> oldAttrNode { attr };
2323 detachAttrNodeFromElementWithValue(&attr, m_elementData->attributeAt(existingAttributeIndex).value());
2324 removeAttributeInternal(existingAttributeIndex, NotInSynchronizationOfLazyAttribute);
2326 return WTFMove(oldAttrNode);
2329 ExceptionOr<QualifiedName> Element::parseAttributeName(const AtomicString& namespaceURI, const AtomicString& qualifiedName)
2331 auto parseResult = Document::parseQualifiedName(namespaceURI, qualifiedName);
2332 if (parseResult.hasException())
2333 return parseResult.releaseException();
2334 QualifiedName parsedAttributeName { parseResult.releaseReturnValue() };
2335 if (!Document::hasValidNamespaceForAttributes(parsedAttributeName))
2336 return Exception { NamespaceError };
2337 return WTFMove(parsedAttributeName);
2340 ExceptionOr<void> Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value)
2342 auto result = parseAttributeName(namespaceURI, qualifiedName);
2343 if (result.hasException())
2344 return result.releaseException();
2345 setAttribute(result.releaseReturnValue(), value);
2349 void Element::removeAttributeInternal(unsigned index, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
2351 ASSERT_WITH_SECURITY_IMPLICATION(index < attributeCount());
2353 UniqueElementData& elementData = ensureUniqueElementData();
2355 QualifiedName name = elementData.attributeAt(index).name();
2356 AtomicString valueBeingRemoved = elementData.attributeAt(index).value();
2358 if (RefPtr<Attr> attrNode = attrIfExists(name))
2359 detachAttrNodeFromElementWithValue(attrNode.get(), elementData.attributeAt(index).value());
2361 if (inSynchronizationOfLazyAttribute) {
2362 elementData.removeAttribute(index);
2366 ASSERT(!valueBeingRemoved.isNull());
2367 willModifyAttribute(name, valueBeingRemoved, nullAtom());
2369 Style::AttributeChangeInvalidation styleInvalidation(*this, name, valueBeingRemoved, nullAtom());
2370 elementData.removeAttribute(index);
2373 didRemoveAttribute(name, valueBeingRemoved);
2376 void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
2378 if (inSynchronizationOfLazyAttribute) {
2379 ensureUniqueElementData().addAttribute(name, value);
2383 willModifyAttribute(name, nullAtom(), value);
2385 Style::AttributeChangeInvalidation styleInvalidation(*this, name, nullAtom(), value);
2386 ensureUniqueElementData().addAttribute(name, value);
2388 didAddAttribute(name, value);
2391 bool Element::removeAttribute(const AtomicString& name)
2396 AtomicString localName = shouldIgnoreAttributeCase(*this) ? name.convertToASCIILowercase() : name;
2397 unsigned index = elementData()->findAttributeIndexByName(localName, false);
2398 if (index == ElementData::attributeNotFound) {
2399 if (UNLIKELY(localName == styleAttr) && elementData()->styleAttributeIsDirty() && is<StyledElement>(*this))
2400 downcast<StyledElement>(*this).removeAllInlineStyleProperties();
2404 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
2408 bool Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName)
2410 return removeAttribute(QualifiedName(nullAtom(), localName, namespaceURI));
2413 RefPtr<Attr> Element::getAttributeNode(const AtomicString& localName)
2417 synchronizeAttribute(localName);
2418 const Attribute* attribute = elementData()->findAttributeByName(localName, shouldIgnoreAttributeCase(*this));
2421 return ensureAttr(attribute->name());
2424 RefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
2428 QualifiedName qName(nullAtom(), localName, namespaceURI);
2429 synchronizeAttribute(qName);
2430 const Attribute* attribute = elementData()->findAttributeByName(qName);
2433 return ensureAttr(attribute->name());
2436 bool Element::hasAttribute(const AtomicString& localName) const
2440 synchronizeAttribute(localName);
2441 return elementData()->findAttributeByName(localName, shouldIgnoreAttributeCase(*this));
2444 bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
2448 QualifiedName qName(nullAtom(), localName, namespaceURI);
2449 synchronizeAttribute(qName);
2450 return elementData()->findAttributeByName(qName);
2453 void Element::focus(bool restorePreviousSelection, FocusDirection direction)
2458 if (document().focusedElement() == this) {
2459 if (document().page())
2460 document().page()->chrome().client().elementDidRefocus(*this);
2465 // If the stylesheets have already been loaded we can reliably check isFocusable.
2466 // If not, we continue and set the focused node on the focus controller below so
2467 // that it can be updated soon after attach.
2468 if (document().haveStylesheetsLoaded()) {
2469 document().updateStyleIfNeeded();
2474 if (!supportsFocus())
2477 RefPtr<Node> protect;
2478 if (Page* page = document().page()) {
2479 // Focus and change event handlers can cause us to lose our last ref.
2480 // If a focus event handler changes the focus to a different node it
2481 // does not make sense to continue and update appearence.
2483 if (!page->focusController().setFocusedElement(this, *document().frame(), direction))
2487 SelectionRevealMode revealMode = SelectionRevealMode::Reveal;
2489 // Focusing a form element triggers animation in UIKit to scroll to the right position.
2490 // Calling updateFocusAppearance() would generate an unnecessary call to ScrollView::setScrollPosition(),
2491 // which would jump us around during this animation. See <rdar://problem/6699741>.
2492 bool isFormControl = is<HTMLFormControlElement>(*this);
2494 revealMode = SelectionRevealMode::RevealUpToMainFrame;
2497 auto target = focusAppearanceUpdateTarget();
2501 target->updateFocusAppearance(restorePreviousSelection ? SelectionRestorationMode::Restore : SelectionRestorationMode::SetDefault, revealMode);
2504 RefPtr<Element> Element::focusAppearanceUpdateTarget()
2509 void Element::updateFocusAppearance(SelectionRestorationMode, SelectionRevealMode revealMode)
2511 if (isRootEditableElement()) {
2512 // Keep frame alive in this method, since setSelection() may release the last reference to |frame|.
2513 RefPtr<Frame> frame = document().frame();
2517 // When focusing an editable element in an iframe, don't reset the selection if it already contains a selection.
2518 if (this == frame->selection().selection().rootEditableElement())
2521 // FIXME: We should restore the previous selection if there is one.
2522 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
2524 if (frame->selection().shouldChangeSelection(newSelection)) {
2525 frame->selection().setSelection(newSelection, FrameSelection::defaultSetSelectionOptions(), Element::defaultFocusTextStateChangeIntent());
2526 frame->selection().revealSelection(revealMode);
2530 if (RefPtr<FrameView> view = document().view())
2531 view->scheduleScrollToFocusedElement(revealMode);
2534 void Element::blur()
2536 if (treeScope().focusedElementInScope() == this) {
2537 if (Frame* frame = document().frame())
2538 frame->page()->focusController().setFocusedElement(nullptr, *frame);
2540 document().setFocusedElement(nullptr);
2544 void Element::dispatchFocusInEvent(const AtomicString& eventType, RefPtr<Element>&& oldFocusedElement)
2546 ASSERT_WITH_SECURITY_IMPLICATION(ScriptDisallowedScope::InMainThread::isScriptAllowed());
2547 ASSERT(eventType == eventNames().focusinEvent || eventType == eventNames().DOMFocusInEvent);
2548 dispatchScopedEvent(FocusEvent::create(eventType, true, false, document().windowProxy(), 0, WTFMove(oldFocusedElement)));
2551 void Element::dispatchFocusOutEvent(const AtomicString& eventType, RefPtr<Element>&& newFocusedElement)
2553 ASSERT_WITH_SECURITY_IMPLICATION(ScriptDisallowedScope::InMainThread::isScriptAllowed());
2554 ASSERT(eventType == eventNames().focusoutEvent || eventType == eventNames().DOMFocusOutEvent);
2555 dispatchScopedEvent(FocusEvent::create(eventType, true, false, document().windowProxy(), 0, WTFMove(newFocusedElement)));
2558 void Element::dispatchFocusEvent(RefPtr<Element>&& oldFocusedElement, FocusDirection)
2560 if (auto* page = document().page())
2561 page->chrome().client().elementDidFocus(*this);
2562 dispatchEvent(FocusEvent::create(eventNames().focusEvent, false, false, document().windowProxy(), 0, WTFMove(oldFocusedElement)));
2565 void Element::dispatchBlurEvent(RefPtr<Element>&& newFocusedElement)
2567 if (auto* page = document().page())
2568 page->chrome().client().elementDidBlur(*this);
2569 dispatchEvent(FocusEvent::create(eventNames().blurEvent, false, false, document().windowProxy(), 0, WTFMove(newFocusedElement)));
2572 void Element::dispatchWebKitImageReadyEventForTesting()
2574 if (document().settings().webkitImageReadyEventEnabled())
2575 dispatchEvent(Event::create("webkitImageFrameReady", true, true));
2578 bool Element::dispatchMouseForceWillBegin()
2580 #if ENABLE(MOUSE_FORCE_EVENTS)
2581 if (!document().hasListenerType(Document::FORCEWILLBEGIN_LISTENER))
2584 Frame* frame = document().frame();
2588 PlatformMouseEvent platformMouseEvent { frame->eventHandler().lastKnownMousePosition(), frame->eventHandler().lastKnownMouseGlobalPosition(), NoButton, PlatformEvent::NoType, 1, false, false, false, false, WallTime::now(), ForceAtClick, NoTap };
2589 auto mouseForceWillBeginEvent = MouseEvent::create(eventNames().webkitmouseforcewillbeginEvent, document().windowProxy(), platformMouseEvent, 0, nullptr);
2590 mouseForceWillBeginEvent->setTarget(this);
2591 dispatchEvent(mouseForceWillBeginEvent);
2593 if (mouseForceWillBeginEvent->defaultHandled() || mouseForceWillBeginEvent->defaultPrevented())
2600 ExceptionOr<void> Element::mergeWithNextTextNode(Text& node)
2602 auto* next = node.nextSibling();
2603 if (!is<Text>(next))
2605 Ref<Text> textNext { downcast<Text>(*next) };
2606 node.appendData(textNext->data());
2607 return textNext->remove();
2610 String Element::innerHTML() const
2612 return createMarkup(*this, ChildrenOnly);
2615 String Element::outerHTML() const
2617 return createMarkup(*this);
2620 ExceptionOr<void> Element::setOuterHTML(const String& html)
2622 auto* parentElement = this->parentElement();
2623 if (!is<HTMLElement>(parentElement))
2624 return Exception { NoModificationAllowedError };
2626 Ref<HTMLElement> parent = downcast<HTMLElement>(*parentElement);
2627 RefPtr<Node> prev = previousSibling();
2628 RefPtr<Node> next = nextSibling();
2630 auto fragment = createFragmentForInnerOuterHTML(parent, html, AllowScriptingContent);
2631 if (fragment.hasException())
2632 return fragment.releaseException();
2634 auto replaceResult = parent->replaceChild(fragment.releaseReturnValue().get(), *this);
2635 if (replaceResult.hasException())
2636 return replaceResult.releaseException();
2638 RefPtr<Node> node = next ? next->previousSibling() : nullptr;
2639 if (is<Text>(node)) {
2640 auto result = mergeWithNextTextNode(downcast<Text>(*node));
2641 if (result.hasException())
2642 return result.releaseException();
2644 if (is<Text>(prev)) {
2645 auto result = mergeWithNextTextNode(downcast<Text>(*prev));
2646 if (result.hasException())
2647 return result.releaseException();
2653 ExceptionOr<void> Element::setInnerHTML(const String& html)
2655 auto fragment = createFragmentForInnerOuterHTML(*this, html, AllowScriptingContent);
2656 if (fragment.hasException())
2657 return fragment.releaseException();
2659 ContainerNode* container;
2660 if (!is<HTMLTemplateElement>(*this))
2663 container = &downcast<HTMLTemplateElement>(*this).content();
2665 return replaceChildrenWithFragment(*container, fragment.releaseReturnValue());
2668 String Element::innerText()
2670 // We need to update layout, since plainText uses line boxes in the render tree.
2671 document().updateLayoutIgnorePendingStylesheets();
2674 return textContent(true);
2676 return plainText(rangeOfContents(*this).ptr());
2679 String Element::outerText()
2681 // Getting outerText is the same as getting innerText, only
2682 // setting is different. You would think this should get the plain
2683 // text for the outer range, but this is wrong, <br> for instance
2684 // would return different values for inner and outer text by such
2685 // a rule, but it doesn't in WinIE, and we want to match that.
2689 String Element::title() const
2694 const AtomicString& Element::pseudo() const
2696 return attributeWithoutSynchronization(pseudoAttr);
2699 void Element::setPseudo(const AtomicString& value)
2701 setAttributeWithoutSynchronization(pseudoAttr, value);
2704 LayoutSize Element::minimumSizeForResizing() const
2706 return hasRareData() ? elementRareData()->minimumSizeForResizing() : defaultMinimumSizeForResizing();
2709 void Element::setMinimumSizeForResizing(const LayoutSize& size)
2711 if (!hasRareData() && size == defaultMinimumSizeForResizing())
2713 ensureElementRareData().setMinimumSizeForResizing(size);
2716 void Element::willBecomeFullscreenElement()
2718 for (auto& child : descendantsOfType<Element>(*this))
2719 child.ancestorWillEnterFullscreen();
2722 static PseudoElement* beforeOrAfterPseudoElement(Element& host, PseudoId pseudoElementSpecifier)
2724 switch (pseudoElementSpecifier) {
2726 return host.beforePseudoElement();
2728 return host.afterPseudoElement();
2734 const RenderStyle* Element::existingComputedStyle() const
2736 if (hasRareData()) {
2737 if (auto* style = elementRareData()->computedStyle())
2741 return renderStyle();
2744 const RenderStyle& Element::resolveComputedStyle()
2746 ASSERT(isConnected());
2747 ASSERT(!existingComputedStyle());
2749 Deque<Element*, 32> elementsRequiringComputedStyle({ this });
2750 const RenderStyle* computedStyle = nullptr;
2752 // Collect ancestors until we find one that has style.
2753 auto composedAncestors = composedTreeAncestors(*this);
2754 for (auto& ancestor : composedAncestors) {
2755 if (auto* existingStyle = ancestor.existingComputedStyle()) {
2756 computedStyle = existingStyle;
2759 elementsRequiringComputedStyle.prepend(&ancestor);
2762 // Resolve and cache styles starting from the most distant ancestor.
2763 for (auto* element : elementsRequiringComputedStyle) {
2764 auto style = document().styleForElementIgnoringPendingStylesheets(*element, computedStyle);
2765 computedStyle = style.get();
2766 ElementRareData& rareData = element->ensureElementRareData();
2767 rareData.setComputedStyle(WTFMove(style));
2770 return *computedStyle;
2773 const RenderStyle& Element::resolvePseudoElementStyle(PseudoId pseudoElementSpecifier)
2775 ASSERT(!isPseudoElement());
2777 auto* parentStyle = existingComputedStyle();
2778 ASSERT(parentStyle);
2779 ASSERT(!parentStyle->getCachedPseudoStyle(pseudoElementSpecifier));
2781 auto style = document().styleForElementIgnoringPendingStylesheets(*this, parentStyle, pseudoElementSpecifier);
2783 style = RenderStyle::createPtr();
2784 style->inheritFrom(*parentStyle);
2785 style->setStyleType(pseudoElementSpecifier);
2788 auto* computedStyle = style.get();
2789 const_cast<RenderStyle*>(parentStyle)->addCachedPseudoStyle(WTFMove(style));
2790 return *computedStyle;
2793 const RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
2798 if (PseudoElement* pseudoElement = beforeOrAfterPseudoElement(*this, pseudoElementSpecifier))
2799 return pseudoElement->computedStyle();
2801 auto* style = existingComputedStyle();
2803 style = &resolveComputedStyle();
2805 if (pseudoElementSpecifier) {
2806 if (auto* cachedPseudoStyle = style->getCachedPseudoStyle(pseudoElementSpecifier))
2807 return cachedPseudoStyle;
2808 return &resolvePseudoElementStyle(pseudoElementSpecifier);
2814 bool Element::needsStyleInvalidation() const
2816 if (!inRenderedDocument())
2818 if (styleValidity() >= Style::Validity::SubtreeInvalid)
2820 if (document().hasPendingForcedStyleRecalc())
2826 void Element::setStyleAffectedByEmpty()
2828 ensureElementRareData().setStyleAffectedByEmpty(true);
2831 void Element::setStyleAffectedByFocusWithin()
2833 ensureElementRareData().setStyleAffectedByFocusWithin(true);
2836 void Element::setStyleAffectedByActive()
2838 ensureElementRareData().setStyleAffectedByActive(true);
2841 void Element::setChildrenAffectedByDrag()
2843 ensureElementRareData().setChildrenAffectedByDrag(true);
2846 void Element::setChildrenAffectedByForwardPositionalRules()
2848 ensureElementRareData().setChildrenAffectedByForwardPositionalRules(true);
2851 void Element::setDescendantsAffectedByForwardPositionalRules()
2853 ensureElementRareData().setDescendantsAffectedByForwardPositionalRules(true);
2856 void Element::setChildrenAffectedByBackwardPositionalRules()
2858 ensureElementRareData().setChildrenAffectedByBackwardPositionalRules(true);
2861 void Element::setDescendantsAffectedByBackwardPositionalRules()
2863 ensureElementRareData().setDescendantsAffectedByBackwardPositionalRules(true);
2866 void Element::setChildrenAffectedByPropertyBasedBackwardPositionalRules()
2868 ensureElementRareData().setChildrenAffectedByPropertyBasedBackwardPositionalRules(true);
2871 void Element::setChildIndex(unsigned index)
2873 ElementRareData& rareData = ensureElementRareData();
2874 rareData.setChildIndex(index);
2877 bool Element::hasFlagsSetDuringStylingOfChildren() const
2879 if (childrenAffectedByHover() || childrenAffectedByFirstChildRules() || childrenAffectedByLastChildRules())
2884 return rareDataStyleAffectedByActive()
2885 || rareDataChildrenAffectedByDrag()
2886 || rareDataChildrenAffectedByForwardPositionalRules()
2887 || rareDataDescendantsAffectedByForwardPositionalRules()
2888 || rareDataChildrenAffectedByBackwardPositionalRules()
2889 || rareDataDescendantsAffectedByBackwardPositionalRules()
2890 || rareDataChildrenAffectedByPropertyBasedBackwardPositionalRules();
2893 bool Element::rareDataStyleAffectedByEmpty() const
2895 ASSERT(hasRareData());
2896 return elementRareData()->styleAffectedByEmpty();
2899 bool Element::rareDataStyleAffectedByFocusWithin() const
2901 ASSERT(hasRareData());
2902 return elementRareData()->styleAffectedByFocusWithin();
2905 bool Element::rareDataStyleAffectedByActive() const
2907 ASSERT(hasRareData());
2908 return elementRareData()->styleAffectedByActive();
2911 bool Element::rareDataChildrenAffectedByDrag() const
2913 ASSERT(hasRareData());
2914 return elementRareData()->childrenAffectedByDrag();
2917 bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
2919 ASSERT(hasRareData());
2920 return elementRareData()->childrenAffectedByForwardPositionalRules();
2923 bool Element::rareDataDescendantsAffectedByForwardPositionalRules() const
2925 ASSERT(hasRareData());
2926 return elementRareData()->descendantsAffectedByForwardPositionalRules();
2929 bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
2931 ASSERT(hasRareData());
2932 return elementRareData()->childrenAffectedByBackwardPositionalRules();
2935 bool Element::rareDataDescendantsAffectedByBackwardPositionalRules() const
2937 ASSERT(hasRareData());
2938 return elementRareData()->descendantsAffectedByBackwardPositionalRules();
2941 bool Element::rareDataChildrenAffectedByPropertyBasedBackwardPositionalRules() const
2943 ASSERT(hasRareData());
2944 return elementRareData()->childrenAffectedByPropertyBasedBackwardPositionalRules();
2947 unsigned Element::rareDataChildIndex() const
2949 ASSERT(hasRareData());
2950 return elementRareData()->childIndex();
2953 AtomicString Element::computeInheritedLanguage() const
2955 if (const ElementData* elementData = this->elementData()) {
2956 if (const Attribute* attribute = elementData->findLanguageAttribute())
2957 return attribute->value();
2960 // The language property is inherited, so we iterate over the parents to find the first language.
2961 const Node* currentNode = this;
2962 while ((currentNode = currentNode->parentNode())) {
2963 if (is<Element>(*currentNode)) {
2964 if (const ElementData* elementData = downcast<Element>(*currentNode).elementData()) {
2965 if (const Attribute* attribute = elementData->findLanguageAttribute())
2966 return attribute->value();
2968 } else if (is<Document>(*currentNode)) {
2969 // checking the MIME content-language
2970 return downcast<Document>(*currentNode).contentLanguage();
2977 Locale& Element::locale() const
2979 return document().getCachedLocale(computeInheritedLanguage());
2982 void Element::normalizeAttributes()
2984 if (!hasAttributes())
2987 auto* attrNodeList = attrNodeListForElement(*this);
2991 // Copy the Attr Vector because Node::normalize() can fire synchronous JS
2992 // events (e.g. DOMSubtreeModified) and a JS listener could add / remove
2993 // attributes while we are iterating.
2994 auto copyOfAttrNodeList = *attrNodeList;
2995 for (auto& attrNode : copyOfAttrNodeList)
2996 attrNode->normalize();
2999 PseudoElement* Element::beforePseudoElement() const
3001 return hasRareData() ? elementRareData()->beforePseudoElement() : nullptr;
3004 PseudoElement* Element::afterPseudoElement() const
3006 return hasRareData() ? elementRareData()->afterPseudoElement() : nullptr;
3009 void Element::setBeforePseudoElement(Ref<PseudoElement>&& element)
3011 ensureElementRareData().setBeforePseudoElement(WTFMove(element));
3014 void Element::setAfterPseudoElement(Ref<PseudoElement>&& element)
3016 ensureElementRareData().setAfterPseudoElement(WTFMove(element));
3019 static void disconnectPseudoElement(PseudoElement* pseudoElement)
3023 ASSERT(!pseudoElement->renderer());
3024 ASSERT(pseudoElement->hostElement());
3025 pseudoElement->clearHostElement();
3028 void Element::clearBeforePseudoElement()
3032 disconnectPseudoElement(elementRareData()->beforePseudoElement());
3033 elementRareData()->setBeforePseudoElement(nullptr);
3036 void Element::clearAfterPseudoElement()
3040 disconnectPseudoElement(elementRareData()->afterPseudoElement());
3041 elementRareData()->setAfterPseudoElement(nullptr);
3044 bool Element::matchesValidPseudoClass() const
3049 bool Element::matchesInvalidPseudoClass() const
3054 bool Element::matchesReadWritePseudoClass() const
3059 bool Element::matchesIndeterminatePseudoClass() const
3061 return shouldAppearIndeterminate();
3064 bool Element::matchesDefaultPseudoClass() const
3069 ExceptionOr<bool> Element::matches(const String& selector)
3071 auto query = document().selectorQueryForString(selector);
3072 if (query.hasException())
3073 return query.releaseException();
3074 return query.releaseReturnValue().matches(*this);
3077 ExceptionOr<Element*> Element::closest(const String& selector)
3079 auto query = document().selectorQueryForString(selector);
3080 if (query.hasException())
3081 return query.releaseException();
3082 return query.releaseReturnValue().closest(*this);
3085 bool Element::shouldAppearIndeterminate() const
3090 bool Element::mayCauseRepaintInsideViewport(const IntRect* visibleRect) const
3092 return renderer() && renderer()->mayCauseRepaintInsideViewport(visibleRect);
3095 DOMTokenList& Element::classList()
3097 ElementRareData& data = ensureElementRareData();
3098 if (!data.classList())
3099 data.setClassList(std::make_unique<DOMTokenList>(*this, HTMLNames::classAttr));
3100 return *data.classList();
3103 DatasetDOMStringMap& Element::dataset()
3105 ElementRareData& data = ensureElementRareData();
3106 if (!data.dataset())
3107 data.setDataset(std::make_unique<DatasetDOMStringMap>(*this));
3108 return *data.dataset();
3111 URL Element::getURLAttribute(const QualifiedName& name) const
3113 #if !ASSERT_DISABLED
3114 if (elementData()) {
3115 if (const Attribute* attribute = findAttributeByName(name))
3116 ASSERT(isURLAttribute(*attribute));
3119 return document().completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
3122 URL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
3124 #if !ASSERT_DISABLED
3125 if (elementData()) {
3126 if (const Attribute* attribute = findAttributeByName(name))
3127 ASSERT(isURLAttribute(*attribute));
3130 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
3131 if (value.isEmpty())
3133 return document().completeURL(value);
3136 int Element::getIntegralAttribute(const QualifiedName& attributeName) const
3138 return parseHTMLInteger(getAttribute(attributeName)).value_or(0);
3141 void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
3143 setAttribute(attributeName, AtomicString::number(value));
3146 unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
3148 return parseHTMLNonNegativeInteger(getAttribute(attributeName)).value_or(0);
3151 void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
3153 setAttribute(attributeName, AtomicString::number(limitToOnlyHTMLNonNegative(value)));
3156 bool Element::childShouldCreateRenderer(const Node& child) const
3158 // Only create renderers for SVG elements whose parents are SVG elements, or for proper <svg xmlns="svgNS"> subdocuments.
3159 if (child.isSVGElement()) {
3160 ASSERT(!isSVGElement());
3161 const SVGElement& childElement = downcast<SVGElement>(child);
3162 return is<SVGSVGElement>(childElement) && childElement.isValid();
3167 #if ENABLE(FULLSCREEN_API)
3168 void Element::webkitRequestFullscreen()
3170 document().requestFullScreenForElement(this, Document::EnforceIFrameAllowFullScreenRequirement);
3173 bool Element::containsFullScreenElement() const
3175 return hasRareData() && elementRareData()->containsFullScreenElement();
3178 void Element::setContainsFullScreenElement(bool flag)
3180 ensureElementRareData().setContainsFullScreenElement(flag);
3181 invalidateStyleAndLayerComposition();
3184 static Element* parentCrossingFrameBoundaries(Element* element)
3187 return element->parentElement() ? element->parentElement() : element->document().ownerElement();
3190 void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool flag)
3192 Element* element = this;
3193 while ((element = parentCrossingFrameBoundaries(element)))
3194 element->setContainsFullScreenElement(flag);
3198 #if ENABLE(POINTER_LOCK)
3199 void Element::requestPointerLock()
3201 if (document().page())
3202 document().page()->pointerLockController().requestPointerLock(this);
3206 SpellcheckAttributeState Element::spellcheckAttributeState() const
3208 const AtomicString& value = attributeWithoutSynchronization(HTMLNames::spellcheckAttr);
3210 return SpellcheckAttributeDefault;
3211 if (value.isEmpty() || equalLettersIgnoringASCIICase(value, "true"))
3212 return SpellcheckAttributeTrue;
3213 if (equalLettersIgnoringASCIICase(value, "false"))
3214 return SpellcheckAttributeFalse;
3215 return SpellcheckAttributeDefault;
3218 bool Element::isSpellCheckingEnabled() const
3220 for (const Element* element = this; element; element = element->parentOrShadowHostElement()) {
3221 switch (element->spellcheckAttributeState()) {
3222 case SpellcheckAttributeTrue:
3224 case SpellcheckAttributeFalse:
3226 case SpellcheckAttributeDefault:
3235 bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
3237 if (name == HTMLNames::styleAttr)
3241 return !downcast<SVGElement>(*this).isAnimatableAttribute(name);
3247 #ifdef DUMP_NODE_STATISTICS
3248 bool Element::hasNamedNodeMap() const
3250 return hasRareData() && elementRareData()->attributeMap();
3254 inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName)
3256 if (!isInTreeScope())
3259 if (oldName == newName)
3262 updateNameForTreeScope(treeScope(), oldName, newName);
3266 if (!is<HTMLDocument>(document()))
3268 updateNameForDocument(downcast<HTMLDocument>(document()), oldName, newName);
3271 void Element::updateNameForTreeScope(TreeScope& scope, const AtomicString& oldName, const AtomicString& newName)
3273 ASSERT(oldName != newName);
3275 if (!oldName.isEmpty())
3276 scope.removeElementByName(*oldName.impl(), *this);
3277 if (!newName.isEmpty())
3278 scope.addElementByName(*newName.impl(), *this);
3281 void Element::updateNameForDocument(HTMLDocument& document, const AtomicString& oldName, const AtomicString& newName)
3283 ASSERT(oldName != newName);
3285 if (isInShadowTree())
3288 if (WindowNameCollection::elementMatchesIfNameAttributeMatch(*this)) {
3289 const AtomicString& id = WindowNameCollection::elementMatchesIfIdAttributeMatch(*this) ? getIdAttribute() : nullAtom();
3290 if (!oldName.isEmpty() && oldName != id)
3291 document.removeWindowNamedItem(*oldName.impl(), *this);
3292 if (!newName.isEmpty() && newName != id)
3293 document.addWindowNamedItem(*newName.impl(), *this);
3296 if (DocumentNameCollection::elementMatchesIfNameAttributeMatch(*this)) {
3297 const AtomicString& id = DocumentNameCollection::elementMatchesIfIdAttributeMatch(*this) ? getIdAttribute() : nullAtom();
3298 if (!oldName.isEmpty() && oldName != id)
3299 document.removeDocumentNamedItem(*oldName.impl(), *this);
3300 if (!newName.isEmpty() && newName != id)
3301 document.addDocumentNamedItem(*newName.impl(), *this);
3305 inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId, NotifyObservers notifyObservers)
3307 if (!isInTreeScope())
3313 updateIdForTreeScope(treeScope(), oldId, newId, notifyObservers);
3317 if (!is<HTMLDocument>(document()))
3319 updateIdForDocument(downcast<HTMLDocument>(document()), oldId, newId, UpdateHTMLDocumentNamedItemMapsOnlyIfDiffersFromNameAttribute);
3322 void Element::updateIdForTreeScope(TreeScope& scope, const AtomicString& oldId, const AtomicString& newId, NotifyObservers notifyObservers)
3324 ASSERT(isInTreeScope());
3325 ASSERT(oldId != newId);
3327 if (!oldId.isEmpty())
3328 scope.removeElementById(*oldId.impl(), *this, notifyObservers == NotifyObservers::Yes);
3329 if (!newId.isEmpty())
3330 scope.addElementById(*newId.impl(), *this, notifyObservers == NotifyObservers::Yes);
3333 void Element::updateIdForDocument(HTMLDocument& document, const AtomicString& oldId, const AtomicString& newId, HTMLDocumentNamedItemMapsUpdatingCondition condition)
3335 ASSERT(isConnected());
3336 ASSERT(oldId != newId);
3338 if (isInShadowTree())
3341 if (WindowNameCollection::elementMatchesIfIdAttributeMatch(*this)) {
3342 const AtomicString& name = condition == UpdateHTMLDocumentNamedItemMapsOnlyIfDiffersFromNameAttribute && WindowNameCollection::elementMatchesIfNameAttributeMatch(*this) ? getNameAttribute() : nullAtom();
3343 if (!oldId.isEmpty() && oldId != name)
3344 document.removeWindowNamedItem(*oldId.impl(), *this);
3345 if (!newId.isEmpty() && newId != name)
3346 document.addWindowNamedItem(*newId.impl(), *this);
3349 if (DocumentNameCollection::elementMatchesIfIdAttributeMatch(*this)) {
3350 const AtomicString& name = condition == UpdateHTMLDocumentNamedItemMapsOnlyIfDiffersFromNameAttribute && DocumentNameCollection::elementMatchesIfNameAttributeMatch(*this) ? getNameAttribute() : nullAtom();
3351 if (!oldId.isEmpty() && oldId != name)
3352 document.removeDocumentNamedItem(*oldId.impl(), *this);
3353 if (!newId.isEmpty() && newId != name)
3354 document.addDocumentNamedItem(*newId.impl(), *this);
3358 void Element::updateLabel(TreeScope& scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
3360 ASSERT(hasTagName(labelTag));
3365 if (oldForAttributeValue == newForAttributeValue)
3368 if (!oldForAttributeValue.isEmpty())
3369 scope.removeLabel(*oldForAttributeValue.impl(), downcast<HTMLLabelElement>(*this));
3370 if (!newForAttributeValue.isEmpty())
3371 scope.addLabel(*newForAttributeValue.impl(), downcast<HTMLLabelElement>(*this));
3374 void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
3376 if (name == HTMLNames::idAttr)
3377 updateId(oldValue, newValue, NotifyObservers::No); // Will notify observers after the attribute is actually changed.
3378 else if (name == HTMLNames::nameAttr)
3379 updateName(oldValue, newValue);
3380 else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
3381 if (treeScope().shouldCacheLabelsByForAttribute())
3382 updateLabel(treeScope(), oldValue, newValue);
3385 if (auto recipients = MutationObserverInterestGroup::createForAttributesMutation(*this, name))
3386 recipients->enqueueMutationRecord(MutationRecord::createAttributes(*this, name, oldValue));
3388 InspectorInstrumentation::willModifyDOMAttr(document(), *this, oldValue, newValue);
3391 void Element::didAddAttribute(const QualifiedName& name, const AtomicString& value)
3393 attributeChanged(name, nullAtom(), value);
3394 InspectorInstrumentation::didModifyDOMAttr(document(), *this, name.localName(), value);
3395 dispatchSubtreeModifiedEvent();
3398 void Element::didModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
3400 attributeChanged(name, oldValue, newValue);
3401 InspectorInstrumentation::didModifyDOMAttr(document(), *this, name.localName(), newValue);
3402 // Do not dispatch a DOMSubtreeModified event here; see bug 81141.
3405 void Element::didRemoveAttribute(const QualifiedName& name, const AtomicString& oldValue)
3407 attributeChanged(name, oldValue, nullAtom());
3408 InspectorInstrumentation::didRemoveDOMAttr(document(), *this, name.localName());
3409 dispatchSubtreeModifiedEvent();
3412 IntPoint Element::savedLayerScrollPosition() const
3414 return hasRareData() ? elementRareData()->savedLayerScrollPosition() : IntPoint();
3417 void Element::setSavedLayerScrollPosition(const IntPoint& position)
3419 if (position.isZero() && !hasRareData())
3421 ensureElementRareData().setSavedLayerScrollPosition(position);
3424 RefPtr<Attr> Element::attrIfExists(const AtomicString& localName, bool shouldIgnoreAttributeCase)
3426 if (auto* attrNodeList = attrNodeListForElement(*this))
3427 return findAttrNodeInList(*attrNodeList, localName, shouldIgnoreAttributeCase);
3431 RefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
3433 if (auto* attrNodeList = attrNodeListForElement(*this))
3434 return findAttrNodeInList(*attrNodeList, name);
3438 Ref<Attr> Element::ensureAttr(const QualifiedName& name)
3440 auto& attrNodeList = ensureAttrNodeListForElement(*this);
3441 RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
3443 attrNode = Attr::create(*this, name);
3444 attrNode->setTreeScopeRecursively(treeScope());
3445 attrNodeList.append(attrNode);
3447 return attrNode.releaseNonNull();
3450 void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value)
3452 ASSERT(hasSyntheticAttrChildNodes());
3453 attrNode->detachFromElementWithValue(value);
3455 auto& attrNodeList = *attrNodeListForElement(*this);
3456 bool found = attrNodeList.removeFirstMatching([attrNode](auto& attribute) {
3457 return attribute->qualifiedName() == attrNode->qualifiedName();
3459 ASSERT_UNUSED(found, found);
3460 if (attrNodeList.isEmpty())
3461 removeAttrNodeListForElement(*this);
3464 void Element::detachAllAttrNodesFromElement()
3466 auto* attrNodeList = attrNodeListForElement(*this);
3467 ASSERT(attrNodeList);
3469 for (const Attribute& attribute : attributesIterator()) {
3470 if (RefPtr<Attr> attrNode = findAttrNodeInList(*attrNodeList, attribute.name()))
3471 attrNode->detachFromElementWithValue(attribute.value());
3474 removeAttrNodeListForElement(*this);
3477 void Element::resetComputedStyle()
3479 if (!hasRareData() || !elementRareData()->computedStyle())
3482 auto reset = [](Element& element) {
3483 if (!element.hasRareData() || !element.elementRareData()->computedStyle())
3485 if (element.hasCustomStyleResolveCallbacks())
3486 element.willResetComputedStyle();
3487 element.elementRareData()->resetComputedStyle();
3490 for (auto& child : descendantsOfType<Element>(*this))
3494 void Element::resetStyleRelations()
3498 elementRareData()->resetStyleRelations();
3501 void Element::clearHoverAndActiveStatusBeforeDetachingRenderer()
3503 if (!isUserActionElement())
3506 document().hoveredElementDidDetach(this);
3507 if (inActiveChain())
3508 document().elementInActiveChainDidDetach(this);
3509 document().userActionElements().clearActiveAndHovered(*this);
3512 void Element::willRecalcStyle(Style::Change)
3514 ASSERT(hasCustomStyleResolveCallbacks());
3517 void Element::didRecalcStyle(Style::Change)
3519 ASSERT(hasCustomStyleResolveCallbacks());
3522 void Element::willResetComputedStyle()
3524 ASSERT(hasCustomStyleResolveCallbacks());
3527 void Element::willAttachRenderers()
3529 ASSERT(hasCustomStyleResolveCallbacks());
3532 void Element::didAttachRenderers()
3534 ASSERT(hasCustomStyleResolveCallbacks());
3537 void Element::willDetachRenderers()
3539 ASSERT(hasCustomStyleResolveCallbacks());
3542 void Element::didDetachRenderers()
3544 ASSERT(hasCustomStyleResolveCallbacks());
3547 std::optional<ElementStyle> Element::resolveCustomStyle(const RenderStyle&, const RenderStyle*)
3549 ASSERT(hasCustomStyleResolveCallbacks());
3550 return std::nullopt;
3553 void Element::cloneAttributesFromElement(const Element& other)
3555 if (hasSyntheticAttrChildNodes())
3556 detachAllAttrNodesFromElement();
3558 other.synchronizeAllAttributes();
3559 if (!other.m_elementData) {
3560 m_elementData = nullptr;
3564 // We can't update window and document's named item maps since the presence of image and object elements depend on other attributes and children.
3565 // Fortunately, those named item maps are only updated when this element is in the document, which should never be the case.
3566 ASSERT(!isConnected());
3568 const AtomicString& oldID = getIdAttribute();
3569 const AtomicString& newID = other.getIdAttribute();
3571 if (!oldID.isNull() || !newID.isNull())
3572 updateId(oldID, newID, NotifyObservers::No); // Will notify observers after the attribute is actually changed.
3574 const AtomicString& oldName = getNameAttribute();
3575 const AtomicString& newName = other.getNameAttribute();
3577 if (!oldName.isNull() || !newName.isNull())
3578 updateName(oldName, newName);
3580 // If 'other' has a mutable ElementData, convert it to an immutable one so we can share it between both elements.
3581 // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes.
3582 if (is<UniqueElementData>(*other.m_elementData)
3583 && !other.m_elementData->presentationAttributeStyle()
3584 && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper()))
3585 const_cast<Element&>(other).m_elementData = downcast<UniqueElementData>(*other.m_elementData).makeShareableCopy();
3587 if (!other.m_elementData->isUnique())
3588 m_elementData = other.m_elementData;
3590 m_elementData = other.m_elementData->makeUniqueCopy();
3592 for (const Attribute& attribute : attributesIterator())
3593 attributeChanged(attribute.name(), nullAtom(), attribute.value(), ModifiedByCloning);
3596 void Element::cloneDataFromElement(const Element& other)
3598 cloneAttributesFromElement(other);
3599 copyNonAttributePropertiesFromElement(other);
3602 void Element::createUniqueElementData()
3605 m_elementData = UniqueElementData::create();
3607 m_elementData = downcast<ShareableElementData>(*m_elementData).makeUniqueCopy();
3610 bool Element::hasPendingResources() const
3612 return hasRareData() && elementRareData()->hasPendingResources();
3615 void Element::setHasPendingResources()
3617 ensureElementRareData().setHasPendingResources(true);
3620 void Element::clearHasPendingResources()
3624 elementRareData()->setHasPendingResources(false);
3627 bool Element::hasCSSAnimation() const
3629 return hasRareData() && elementRareData()->hasCSSAnimation();
3632 void Element::setHasCSSAnimation()
3634 ensureElementRareData().setHasCSSAnimation(true);
3637 void Element::clearHasCSSAnimation()
3641 elementRareData()->setHasCSSAnimation(false);
3644 bool Element::canContainRangeEndPoint() const
3646 return !equalLettersIgnoringASCIICase(attributeWithoutSynchronization(roleAttr), "img");
3649 String Element::completeURLsInAttributeValue(const URL& base, const Attribute& attribute) const
3651 return URL(base, attribute.value()).string();
3654 ExceptionOr<Node*> Element::insertAdjacent(const String& where, Ref<Node>&& newChild)
3656 // In Internet Explorer if the element has no parent and where is "beforeBegin" or "afterEnd",
3657 // a document fragment is created and the elements appended in the correct order. This document
3658 // fragment isn't returned anywhere.
3660 // This is impossible for us to implement as the DOM tree does not allow for such structures,
3661 // Opera also appears to disallow such usage.
3663 if (equalLettersIgnoringASCIICase(where, "beforebegin")) {
3664 auto* parent = this->parentNode();
3667 auto result = parent->insertBefore(newChild, this);
3668 if (result.hasException())
3669 return result.releaseException();
3670 return newChild.ptr();
3673 if (equalLettersIgnoringASCIICase(where, "afterbegin")) {
3674 auto result = insertBefore(newChild, firstChild());
3675 if (result.hasException())
3676 return result.releaseException();
3677 return newChild.ptr();
3680 if (equalLettersIgnoringASCIICase(where, "beforeend")) {
3681 auto result = appendChild(newChild);
3682 if (result.hasException())
3683 return result.releaseException();
3684 return newChild.ptr();
3687 if (equalLettersIgnoringASCIICase(where, "afterend")) {
3688 auto* parent = this->parentNode();