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-2016 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 "CSSParser.h"
34 #include "ChromeClient.h"
35 #include "ClassChangeInvalidation.h"
36 #include "ClientRect.h"
37 #include "ClientRectList.h"
38 #include "ComposedTreeAncestorIterator.h"
39 #include "ContainerNodeAlgorithms.h"
40 #include "CustomElementDefinitions.h"
41 #include "DOMTokenList.h"
42 #include "Dictionary.h"
43 #include "DocumentSharedObjectPool.h"
44 #include "ElementIterator.h"
45 #include "ElementRareData.h"
46 #include "EventDispatcher.h"
47 #include "EventHandler.h"
48 #include "EventNames.h"
49 #include "FlowThreadController.h"
50 #include "FocusController.h"
51 #include "FocusEvent.h"
52 #include "FrameSelection.h"
53 #include "FrameView.h"
54 #include "HTMLCanvasElement.h"
55 #include "HTMLCollection.h"
56 #include "HTMLDocument.h"
57 #include "HTMLEmbedElement.h"
58 #include "HTMLHtmlElement.h"
59 #include "HTMLIFrameElement.h"
60 #include "HTMLLabelElement.h"
61 #include "HTMLNameCollection.h"
62 #include "HTMLObjectElement.h"
63 #include "HTMLParserIdioms.h"
64 #include "HTMLSelectElement.h"
65 #include "HTMLTemplateElement.h"
66 #include "IdChangeInvalidation.h"
67 #include "IdTargetObserverRegistry.h"
68 #include "JSLazyEventListener.h"
69 #include "KeyboardEvent.h"
70 #include "LifecycleCallbackQueue.h"
71 #include "MainFrame.h"
72 #include "MutationObserverInterestGroup.h"
73 #include "MutationRecord.h"
74 #include "NoEventDispatchAssertion.h"
75 #include "NodeRenderStyle.h"
76 #include "PlatformWheelEvent.h"
77 #include "PointerLockController.h"
78 #include "RenderFlowThread.h"
79 #include "RenderLayer.h"
80 #include "RenderNamedFlowFragment.h"
81 #include "RenderRegion.h"
82 #include "RenderTheme.h"
83 #include "RenderTreeUpdater.h"
84 #include "RenderView.h"
85 #include "RenderWidget.h"
86 #include "SVGDocumentExtensions.h"
87 #include "SVGElement.h"
89 #include "SVGSVGElement.h"
90 #include "ScrollLatchingState.h"
91 #include "SelectorQuery.h"
93 #include "SimulatedClick.h"
94 #include "SlotAssignment.h"
95 #include "StyleProperties.h"
96 #include "StyleResolver.h"
97 #include "StyleTreeResolver.h"
98 #include "TextIterator.h"
99 #include "VoidCallback.h"
100 #include "WheelEvent.h"
101 #include "XLinkNames.h"
102 #include "XMLNSNames.h"
103 #include "XMLNames.h"
104 #include "htmlediting.h"
106 #include <wtf/BitVector.h>
107 #include <wtf/CurrentTime.h>
108 #include <wtf/NeverDestroyed.h>
109 #include <wtf/text/CString.h>
113 using namespace HTMLNames;
114 using namespace XMLNames;
116 static HashMap<Element*, Vector<RefPtr<Attr>>>& attrNodeListMap()
118 static NeverDestroyed<HashMap<Element*, Vector<RefPtr<Attr>>>> map;
122 static Vector<RefPtr<Attr>>* attrNodeListForElement(Element& element)
124 if (!element.hasSyntheticAttrChildNodes())
126 ASSERT(attrNodeListMap().contains(&element));
127 return &attrNodeListMap().find(&element)->value;
130 static Vector<RefPtr<Attr>>& ensureAttrNodeListForElement(Element& element)
132 if (element.hasSyntheticAttrChildNodes()) {
133 ASSERT(attrNodeListMap().contains(&element));
134 return attrNodeListMap().find(&element)->value;
136 ASSERT(!attrNodeListMap().contains(&element));
137 element.setHasSyntheticAttrChildNodes(true);
138 return attrNodeListMap().add(&element, Vector<RefPtr<Attr>>()).iterator->value;
141 static void removeAttrNodeListForElement(Element& element)
143 ASSERT(element.hasSyntheticAttrChildNodes());
144 ASSERT(attrNodeListMap().contains(&element));
145 attrNodeListMap().remove(&element);
146 element.setHasSyntheticAttrChildNodes(false);
149 static Attr* findAttrNodeInList(Vector<RefPtr<Attr>>& attrNodeList, const QualifiedName& name)
151 for (auto& node : attrNodeList) {
152 if (node->qualifiedName().matches(name))
158 static Attr* findAttrNodeInList(Vector<RefPtr<Attr>>& attrNodeList, const AtomicString& localName, bool shouldIgnoreAttributeCase)
160 const AtomicString& caseAdjustedName = shouldIgnoreAttributeCase ? localName.convertToASCIILowercase() : localName;
161 for (auto& node : attrNodeList) {
162 if (node->qualifiedName().localName() == caseAdjustedName)
168 Ref<Element> Element::create(const QualifiedName& tagName, Document& document)
170 return adoptRef(*new Element(tagName, document, CreateElement));
173 Element::Element(const QualifiedName& tagName, Document& document, ConstructionType type)
174 : ContainerNode(document, type)
182 if (document().hasLivingRenderTree()) {
183 // When the document is not destroyed, an element that was part of a named flow
184 // content nodes should have been removed from the content nodes collection
185 // and the isNamedFlowContentNode flag reset.
186 ASSERT_WITH_SECURITY_IMPLICATION(!isNamedFlowContentNode());
190 ASSERT(!beforePseudoElement());
191 ASSERT(!afterPseudoElement());
195 if (hasSyntheticAttrChildNodes())
196 detachAllAttrNodesFromElement();
198 if (hasPendingResources()) {
199 document().accessSVGExtensions().removeElementFromPendingResources(this);
200 ASSERT(!hasPendingResources());
204 inline ElementRareData* Element::elementRareData() const
206 ASSERT_WITH_SECURITY_IMPLICATION(hasRareData());
207 return static_cast<ElementRareData*>(rareData());
210 inline ElementRareData& Element::ensureElementRareData()
212 return static_cast<ElementRareData&>(ensureRareData());
215 void Element::clearTabIndexExplicitlyIfNeeded()
218 elementRareData()->clearTabIndexExplicitly();
221 void Element::setTabIndexExplicitly(int tabIndex)
223 ensureElementRareData().setTabIndexExplicitly(tabIndex);
226 bool Element::tabIndexSetExplicitly() const
228 return hasRareData() && elementRareData()->tabIndexSetExplicitly();
231 bool Element::supportsFocus() const
233 return tabIndexSetExplicitly();
236 Element* Element::focusDelegate()
241 int Element::tabIndex() const
243 return hasRareData() ? elementRareData()->tabIndex() : 0;
246 void Element::setTabIndex(int value)
248 setIntegralAttribute(tabindexAttr, value);
251 bool Element::isKeyboardFocusable(KeyboardEvent*) const
253 return isFocusable() && tabIndex() >= 0;
256 bool Element::isMouseFocusable() const
258 return isFocusable();
261 bool Element::shouldUseInputMethod()
263 return computeEditability(UserSelectAllIsAlwaysNonEditable, ShouldUpdateStyle::Update) != Editability::ReadOnly;
266 static bool isForceEvent(const PlatformMouseEvent& platformEvent)
268 return platformEvent.type() == PlatformEvent::MouseForceChanged || platformEvent.type() == PlatformEvent::MouseForceDown || platformEvent.type() == PlatformEvent::MouseForceUp;
271 bool Element::dispatchMouseEvent(const PlatformMouseEvent& platformEvent, const AtomicString& eventType, int detail, Element* relatedTarget)
273 if (isDisabledFormControl())
276 if (isForceEvent(platformEvent) && !document().hasListenerTypeForEventType(platformEvent.type()))
279 Ref<MouseEvent> mouseEvent = MouseEvent::create(eventType, document().defaultView(), platformEvent, detail, relatedTarget);
281 if (mouseEvent->type().isEmpty())
282 return true; // Shouldn't happen.
284 ASSERT(!mouseEvent->target() || mouseEvent->target() != relatedTarget);
285 bool didNotSwallowEvent = dispatchEvent(mouseEvent) && !mouseEvent->defaultHandled();
287 if (mouseEvent->type() == eventNames().clickEvent && mouseEvent->detail() == 2) {
288 // Special case: If it's a double click event, we also send the dblclick event. This is not part
289 // of the DOM specs, but is used for compatibility with the ondblclick="" attribute. This is treated
290 // as a separate event in other DOM-compliant browsers like Firefox, and so we do the same.
291 Ref<MouseEvent> doubleClickEvent = MouseEvent::create(eventNames().dblclickEvent,
292 mouseEvent->bubbles(), mouseEvent->cancelable(), mouseEvent->view(), mouseEvent->detail(),
293 mouseEvent->screenX(), mouseEvent->screenY(), mouseEvent->clientX(), mouseEvent->clientY(),
294 mouseEvent->ctrlKey(), mouseEvent->altKey(), mouseEvent->shiftKey(), mouseEvent->metaKey(),
295 mouseEvent->button(), relatedTarget);
297 if (mouseEvent->defaultHandled())
298 doubleClickEvent->setDefaultHandled();
300 dispatchEvent(doubleClickEvent);
301 if (doubleClickEvent->defaultHandled() || doubleClickEvent->defaultPrevented())
304 return didNotSwallowEvent;
308 bool Element::dispatchWheelEvent(const PlatformWheelEvent& event)
310 Ref<WheelEvent> wheelEvent = WheelEvent::create(event, document().defaultView());
312 // Events with no deltas are important because they convey platform information about scroll gestures
313 // and momentum beginning or ending. However, those events should not be sent to the DOM since some
314 // websites will break. They need to be dispatched because dispatching them will call into the default
315 // event handler, and our platform code will correctly handle the phase changes. Calling stopPropogation()
316 // will prevent the event from being sent to the DOM, but will still call the default event handler.
317 if (!event.deltaX() && !event.deltaY())
318 wheelEvent->stopPropagation();
320 return EventDispatcher::dispatchEvent(this, wheelEvent) && !wheelEvent->defaultHandled();
323 bool Element::dispatchKeyEvent(const PlatformKeyboardEvent& platformEvent)
325 Ref<KeyboardEvent> event = KeyboardEvent::create(platformEvent, document().defaultView());
326 if (Frame* frame = document().frame()) {
327 if (frame->eventHandler().accessibilityPreventsEventPropogation(event))
328 event->stopPropagation();
330 return EventDispatcher::dispatchEvent(this, event) && !event->defaultHandled();
333 void Element::dispatchSimulatedClick(Event* underlyingEvent, SimulatedClickMouseEventOptions eventOptions, SimulatedClickVisualOptions visualOptions)
335 simulateClick(*this, underlyingEvent, eventOptions, visualOptions, SimulatedClickCreationOptions::FromUserAgent);
338 void Element::dispatchSimulatedClickForBindings(Event* underlyingEvent)
340 simulateClick(*this, underlyingEvent, SendNoEvents, DoNotShowPressedLook, SimulatedClickCreationOptions::FromBindings);
343 Ref<Node> Element::cloneNodeInternal(Document& targetDocument, CloningOperation type)
346 case CloningOperation::OnlySelf:
347 case CloningOperation::SelfWithTemplateContent:
348 return cloneElementWithoutChildren(targetDocument);
349 case CloningOperation::Everything:
352 return cloneElementWithChildren(targetDocument);
355 Ref<Element> Element::cloneElementWithChildren(Document& targetDocument)
357 Ref<Element> clone = cloneElementWithoutChildren(targetDocument);
358 cloneChildNodes(clone);
362 Ref<Element> Element::cloneElementWithoutChildren(Document& targetDocument)
364 Ref<Element> clone = cloneElementWithoutAttributesAndChildren(targetDocument);
365 // This will catch HTML elements in the wrong namespace that are not correctly copied.
366 // This is a sanity check as HTML overloads some of the DOM methods.
367 ASSERT(isHTMLElement() == clone->isHTMLElement());
369 clone->cloneDataFromElement(*this);
373 Ref<Element> Element::cloneElementWithoutAttributesAndChildren(Document& targetDocument)
375 return targetDocument.createElement(tagQName(), false);
378 Ref<Attr> Element::detachAttribute(unsigned index)
380 ASSERT(elementData());
382 const Attribute& attribute = elementData()->attributeAt(index);
384 RefPtr<Attr> attrNode = attrIfExists(attribute.name());
386 detachAttrNodeFromElementWithValue(attrNode.get(), attribute.value());
388 attrNode = Attr::create(document(), attribute.name(), attribute.value());
390 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
391 return attrNode.releaseNonNull();
394 bool Element::removeAttribute(const QualifiedName& name)
399 unsigned index = elementData()->findAttributeIndexByName(name);
400 if (index == ElementData::attributeNotFound)
403 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
407 void Element::setBooleanAttribute(const QualifiedName& name, bool value)
410 setAttribute(name, emptyAtom);
412 removeAttribute(name);
415 NamedNodeMap& Element::attributes() const
417 ElementRareData& rareData = const_cast<Element*>(this)->ensureElementRareData();
418 if (NamedNodeMap* attributeMap = rareData.attributeMap())
419 return *attributeMap;
421 rareData.setAttributeMap(std::make_unique<NamedNodeMap>(const_cast<Element&>(*this)));
422 return *rareData.attributeMap();
425 Node::NodeType Element::nodeType() const
430 bool Element::hasAttribute(const QualifiedName& name) const
432 return hasAttributeNS(name.namespaceURI(), name.localName());
435 void Element::synchronizeAllAttributes() const
439 if (elementData()->styleAttributeIsDirty()) {
440 ASSERT(isStyledElement());
441 static_cast<const StyledElement*>(this)->synchronizeStyleAttributeInternal();
444 if (elementData()->animatedSVGAttributesAreDirty()) {
445 ASSERT(isSVGElement());
446 downcast<SVGElement>(*this).synchronizeAnimatedSVGAttribute(anyQName());
450 ALWAYS_INLINE void Element::synchronizeAttribute(const QualifiedName& name) const
454 if (UNLIKELY(name == styleAttr && elementData()->styleAttributeIsDirty())) {
455 ASSERT_WITH_SECURITY_IMPLICATION(isStyledElement());
456 static_cast<const StyledElement*>(this)->synchronizeStyleAttributeInternal();
460 if (UNLIKELY(elementData()->animatedSVGAttributesAreDirty())) {
461 ASSERT(isSVGElement());
462 downcast<SVGElement>(*this).synchronizeAnimatedSVGAttribute(name);
466 static ALWAYS_INLINE bool isStyleAttribute(const Element& element, const AtomicString& attributeLocalName)
468 if (shouldIgnoreAttributeCase(element))
469 return equalLettersIgnoringASCIICase(attributeLocalName, "style");
470 return attributeLocalName == styleAttr.localName();
473 ALWAYS_INLINE void Element::synchronizeAttribute(const AtomicString& localName) const
475 // This version of synchronizeAttribute() is streamlined for the case where you don't have a full QualifiedName,
476 // e.g when called from DOM API.
479 if (elementData()->styleAttributeIsDirty() && isStyleAttribute(*this, localName)) {
480 ASSERT_WITH_SECURITY_IMPLICATION(isStyledElement());
481 static_cast<const StyledElement*>(this)->synchronizeStyleAttributeInternal();
484 if (elementData()->animatedSVGAttributesAreDirty()) {
485 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
486 ASSERT_WITH_SECURITY_IMPLICATION(isSVGElement());
487 downcast<SVGElement>(*this).synchronizeAnimatedSVGAttribute(QualifiedName(nullAtom, localName, nullAtom));
491 const AtomicString& Element::getAttribute(const QualifiedName& name) const
495 synchronizeAttribute(name);
496 if (const Attribute* attribute = findAttributeByName(name))
497 return attribute->value();
501 bool Element::isFocusable() const
503 if (!inDocument() || !supportsFocus())
507 // If the node is in a display:none tree it might say it needs style recalc but
508 // the whole document is actually up to date.
509 ASSERT(!needsStyleRecalc() || !document().childNeedsStyleRecalc());
511 // Elements in canvas fallback content are not rendered, but they are allowed to be
512 // focusable as long as their canvas is displayed and visible.
513 if (auto* canvas = ancestorsOfType<HTMLCanvasElement>(*this).first())
514 return canvas->renderer() && canvas->renderer()->style().visibility() == VISIBLE;
517 // FIXME: Even if we are not visible, we might have a child that is visible.
518 // Hyatt wants to fix that some day with a "has visible content" flag or the like.
519 if (!renderer() || renderer()->style().visibility() != VISIBLE)
525 bool Element::isUserActionElementInActiveChain() const
527 ASSERT(isUserActionElement());
528 return document().userActionElements().isInActiveChain(this);
531 bool Element::isUserActionElementActive() const
533 ASSERT(isUserActionElement());
534 return document().userActionElements().isActive(this);
537 bool Element::isUserActionElementFocused() const
539 ASSERT(isUserActionElement());
540 return document().userActionElements().isFocused(this);
543 bool Element::isUserActionElementHovered() const
545 ASSERT(isUserActionElement());
546 return document().userActionElements().isHovered(this);
549 void Element::setActive(bool flag, bool pause)
551 if (flag == active())
554 document().userActionElements().setActive(this, flag);
559 bool reactsToPress = renderStyle()->affectedByActive() || childrenAffectedByActive();
561 setNeedsStyleRecalc();
563 if (renderer()->style().hasAppearance() && renderer()->theme().stateChanged(*renderer(), ControlStates::PressedState))
564 reactsToPress = true;
566 // The rest of this function implements a feature that only works if the
567 // platform supports immediate invalidations on the ChromeClient, so bail if
568 // that isn't supported.
569 if (!document().page()->chrome().client().supportsImmediateInvalidation())
572 if (reactsToPress && pause) {
573 // The delay here is subtle. It relies on an assumption, namely that the amount of time it takes
574 // to repaint the "down" state of the control is about the same time as it would take to repaint the
575 // "up" state. Once you assume this, you can just delay for 100ms - that time (assuming that after you
576 // leave this method, it will be about that long before the flush of the up state happens again).
577 #ifdef HAVE_FUNC_USLEEP
578 double startTime = monotonicallyIncreasingTime();
581 document().updateStyleIfNeeded();
583 // Do an immediate repaint.
585 renderer()->repaint();
587 // FIXME: Come up with a less ridiculous way of doing this.
588 #ifdef HAVE_FUNC_USLEEP
589 // Now pause for a small amount of time (1/10th of a second from before we repainted in the pressed state)
590 double remainingTime = 0.1 - (monotonicallyIncreasingTime() - startTime);
591 if (remainingTime > 0)
592 usleep(static_cast<useconds_t>(remainingTime * 1000000.0));
597 void Element::setFocus(bool flag)
599 if (flag == focused())
602 document().userActionElements().setFocused(this, flag);
603 setNeedsStyleRecalc();
606 void Element::setHovered(bool flag)
608 if (flag == hovered())
611 document().userActionElements().setHovered(this, flag);
614 // When setting hover to false, the style needs to be recalc'd even when
615 // there's no renderer (imagine setting display:none in the :hover class,
616 // if a nil renderer would prevent this element from recalculating its
617 // style, it would never go back to its normal style and remain
618 // stuck in its hovered style).
620 setNeedsStyleRecalc();
625 if (renderer()->style().affectedByHover() || childrenAffectedByHover())
626 setNeedsStyleRecalc();
628 if (renderer()->style().hasAppearance())
629 renderer()->theme().stateChanged(*renderer(), ControlStates::HoverState);
632 void Element::scrollIntoView(bool alignToTop)
634 document().updateLayoutIgnorePendingStylesheets();
639 LayoutRect bounds = renderer()->anchorRect();
640 // Align to the top / bottom and to the closest edge.
642 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
644 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
647 void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
649 document().updateLayoutIgnorePendingStylesheets();
654 LayoutRect bounds = renderer()->anchorRect();
656 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
658 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
661 void Element::scrollIntoViewIfNotVisible(bool centerIfNotVisible)
663 document().updateLayoutIgnorePendingStylesheets();
668 LayoutRect bounds = renderer()->anchorRect();
669 if (centerIfNotVisible)
670 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignCenterIfNotVisible, ScrollAlignment::alignCenterIfNotVisible);
672 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNotVisible, ScrollAlignment::alignToEdgeIfNotVisible);
675 void Element::scrollByUnits(int units, ScrollGranularity granularity)
677 document().updateLayoutIgnorePendingStylesheets();
679 auto* renderer = this->renderer();
683 if (!renderer->hasOverflowClip())
686 ScrollDirection direction = ScrollDown;
688 direction = ScrollUp;
691 Element* stopElement = this;
692 downcast<RenderBox>(*renderer).scroll(direction, granularity, units, &stopElement);
695 void Element::scrollByLines(int lines)
697 scrollByUnits(lines, ScrollByLine);
700 void Element::scrollByPages(int pages)
702 scrollByUnits(pages, ScrollByPage);
705 static double localZoomForRenderer(const RenderElement& renderer)
707 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
708 // other out, but the alternative is that we'd have to crawl up the whole render tree every
709 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
710 double zoomFactor = 1;
711 if (renderer.style().effectiveZoom() != 1) {
712 // Need to find the nearest enclosing RenderElement that set up
713 // a differing zoom, and then we divide our result by it to eliminate the zoom.
714 const RenderElement* prev = &renderer;
715 for (RenderElement* curr = prev->parent(); curr; curr = curr->parent()) {
716 if (curr->style().effectiveZoom() != prev->style().effectiveZoom()) {
717 zoomFactor = prev->style().zoom();
722 if (prev->isRenderView())
723 zoomFactor = prev->style().zoom();
728 static double adjustForLocalZoom(LayoutUnit value, const RenderElement& renderer, double& zoomFactor)
730 zoomFactor = localZoomForRenderer(renderer);
732 return value.toDouble();
733 return value.toDouble() / zoomFactor;
736 enum LegacyCSSOMElementMetricsRoundingStrategy { Round, Floor };
738 static bool subpixelMetricsEnabled(const Document& document)
740 return document.settings() && document.settings()->subpixelCSSOMElementMetricsEnabled();
743 static double convertToNonSubpixelValueIfNeeded(double value, const Document& document, LegacyCSSOMElementMetricsRoundingStrategy roundStrategy = Round)
745 return subpixelMetricsEnabled(document) ? value : roundStrategy == Round ? round(value) : floor(value);
748 double Element::offsetLeft()
750 document().updateLayoutIgnorePendingStylesheets();
751 if (RenderBoxModelObject* renderer = renderBoxModelObject()) {
752 LayoutUnit offsetLeft = subpixelMetricsEnabled(renderer->document()) ? renderer->offsetLeft() : LayoutUnit(roundToInt(renderer->offsetLeft()));
753 double zoomFactor = 1;
754 double offsetLeftAdjustedWithZoom = adjustForLocalZoom(offsetLeft, *renderer, zoomFactor);
755 return convertToNonSubpixelValueIfNeeded(offsetLeftAdjustedWithZoom, renderer->document(), zoomFactor == 1 ? Floor : Round);
760 double Element::offsetTop()
762 document().updateLayoutIgnorePendingStylesheets();
763 if (RenderBoxModelObject* renderer = renderBoxModelObject()) {
764 LayoutUnit offsetTop = subpixelMetricsEnabled(renderer->document()) ? renderer->offsetTop() : LayoutUnit(roundToInt(renderer->offsetTop()));
765 double zoomFactor = 1;
766 double offsetTopAdjustedWithZoom = adjustForLocalZoom(offsetTop, *renderer, zoomFactor);
767 return convertToNonSubpixelValueIfNeeded(offsetTopAdjustedWithZoom, renderer->document(), zoomFactor == 1 ? Floor : Round);
772 double Element::offsetWidth()
774 document().updateLayoutIfDimensionsOutOfDate(*this, WidthDimensionsCheck);
775 if (RenderBoxModelObject* renderer = renderBoxModelObject()) {
776 LayoutUnit offsetWidth = subpixelMetricsEnabled(renderer->document()) ? renderer->offsetWidth() : LayoutUnit(roundToInt(renderer->offsetWidth()));
777 return convertToNonSubpixelValueIfNeeded(adjustLayoutUnitForAbsoluteZoom(offsetWidth, *renderer).toDouble(), renderer->document());
782 double Element::offsetHeight()
784 document().updateLayoutIfDimensionsOutOfDate(*this, HeightDimensionsCheck);
785 if (RenderBoxModelObject* renderer = renderBoxModelObject()) {
786 LayoutUnit offsetHeight = subpixelMetricsEnabled(renderer->document()) ? renderer->offsetHeight() : LayoutUnit(roundToInt(renderer->offsetHeight()));
787 return convertToNonSubpixelValueIfNeeded(adjustLayoutUnitForAbsoluteZoom(offsetHeight, *renderer).toDouble(), renderer->document());
792 Element* Element::bindingsOffsetParent()
794 Element* element = offsetParent();
795 if (!element || !element->isInShadowTree())
797 return element->containingShadowRoot()->type() == ShadowRoot::Type::UserAgent ? nullptr : element;
800 Element* Element::offsetParent()
802 document().updateLayoutIgnorePendingStylesheets();
803 auto renderer = this->renderer();
806 auto offsetParent = renderer->offsetParent();
809 return offsetParent->element();
812 double Element::clientLeft()
814 document().updateLayoutIgnorePendingStylesheets();
816 if (RenderBox* renderer = renderBox()) {
817 LayoutUnit clientLeft = subpixelMetricsEnabled(renderer->document()) ? renderer->clientLeft() : LayoutUnit(roundToInt(renderer->clientLeft()));
818 return convertToNonSubpixelValueIfNeeded(adjustLayoutUnitForAbsoluteZoom(clientLeft, *renderer).toDouble(), renderer->document());
823 double Element::clientTop()
825 document().updateLayoutIgnorePendingStylesheets();
827 if (RenderBox* renderer = renderBox()) {
828 LayoutUnit clientTop = subpixelMetricsEnabled(renderer->document()) ? renderer->clientTop() : LayoutUnit(roundToInt(renderer->clientTop()));
829 return convertToNonSubpixelValueIfNeeded(adjustLayoutUnitForAbsoluteZoom(clientTop, *renderer).toDouble(), renderer->document());
834 double Element::clientWidth()
836 document().updateLayoutIfDimensionsOutOfDate(*this, WidthDimensionsCheck);
838 if (!document().hasLivingRenderTree())
840 RenderView& renderView = *document().renderView();
842 // When in strict mode, clientWidth for the document element should return the width of the containing frame.
843 // When in quirks mode, clientWidth for the body element should return the width of the containing frame.
844 bool inQuirksMode = document().inQuirksMode();
845 if ((!inQuirksMode && document().documentElement() == this) || (inQuirksMode && isHTMLElement() && document().bodyOrFrameset() == this))
846 return adjustForAbsoluteZoom(renderView.frameView().layoutWidth(), renderView);
848 if (RenderBox* renderer = renderBox()) {
849 LayoutUnit clientWidth = subpixelMetricsEnabled(renderer->document()) ? renderer->clientWidth() : LayoutUnit(roundToInt(renderer->clientWidth()));
850 return convertToNonSubpixelValueIfNeeded(adjustLayoutUnitForAbsoluteZoom(clientWidth, *renderer).toDouble(), renderer->document());
855 double Element::clientHeight()
857 document().updateLayoutIfDimensionsOutOfDate(*this, HeightDimensionsCheck);
858 if (!document().hasLivingRenderTree())
860 RenderView& renderView = *document().renderView();
862 // When in strict mode, clientHeight for the document element should return the height of the containing frame.
863 // When in quirks mode, clientHeight for the body element should return the height of the containing frame.
864 bool inQuirksMode = document().inQuirksMode();
865 if ((!inQuirksMode && document().documentElement() == this) || (inQuirksMode && isHTMLElement() && document().bodyOrFrameset() == this))
866 return adjustForAbsoluteZoom(renderView.frameView().layoutHeight(), renderView);
868 if (RenderBox* renderer = renderBox()) {
869 LayoutUnit clientHeight = subpixelMetricsEnabled(renderer->document()) ? renderer->clientHeight() : LayoutUnit(roundToInt(renderer->clientHeight()));
870 return convertToNonSubpixelValueIfNeeded(adjustLayoutUnitForAbsoluteZoom(clientHeight, *renderer).toDouble(), renderer->document());
875 int Element::scrollLeft()
877 document().updateLayoutIgnorePendingStylesheets();
879 if (RenderBox* rend = renderBox())
880 return adjustForAbsoluteZoom(rend->scrollLeft(), *rend);
884 int Element::scrollTop()
886 document().updateLayoutIgnorePendingStylesheets();
888 if (RenderBox* rend = renderBox())
889 return adjustForAbsoluteZoom(rend->scrollTop(), *rend);
893 void Element::setScrollLeft(int newLeft)
895 document().updateLayoutIgnorePendingStylesheets();
897 if (RenderBox* renderer = renderBox()) {
898 renderer->setScrollLeft(static_cast<int>(newLeft * renderer->style().effectiveZoom()));
899 if (auto* scrollableArea = renderer->layer())
900 scrollableArea->setScrolledProgrammatically(true);
904 void Element::setScrollTop(int newTop)
906 document().updateLayoutIgnorePendingStylesheets();
908 if (RenderBox* renderer = renderBox()) {
909 renderer->setScrollTop(static_cast<int>(newTop * renderer->style().effectiveZoom()));
910 if (auto* scrollableArea = renderer->layer())
911 scrollableArea->setScrolledProgrammatically(true);
915 int Element::scrollWidth()
917 document().updateLayoutIfDimensionsOutOfDate(*this, WidthDimensionsCheck);
918 if (RenderBox* rend = renderBox())
919 return adjustForAbsoluteZoom(rend->scrollWidth(), *rend);
923 int Element::scrollHeight()
925 document().updateLayoutIfDimensionsOutOfDate(*this, HeightDimensionsCheck);
926 if (RenderBox* rend = renderBox())
927 return adjustForAbsoluteZoom(rend->scrollHeight(), *rend);
931 IntRect Element::boundsInRootViewSpace()
933 document().updateLayoutIgnorePendingStylesheets();
935 FrameView* view = document().view();
939 Vector<FloatQuad> quads;
941 if (isSVGElement() && renderer()) {
942 // Get the bounding rectangle from the SVG model.
943 SVGElement& svgElement = downcast<SVGElement>(*this);
945 if (svgElement.getBoundingBox(localRect))
946 quads.append(renderer()->localToAbsoluteQuad(localRect));
948 // Get the bounding rectangle from the box model.
949 if (renderBoxModelObject())
950 renderBoxModelObject()->absoluteQuads(quads);
956 IntRect result = quads[0].enclosingBoundingBox();
957 for (size_t i = 1; i < quads.size(); ++i)
958 result.unite(quads[i].enclosingBoundingBox());
960 result = view->contentsToRootView(result);
964 static bool layoutOverflowRectContainsAllDescendants(const RenderElement& renderer)
966 if (renderer.isRenderView())
969 if (!renderer.element())
972 // If there are any position:fixed inside of us, game over.
973 if (auto viewPositionedObjects = renderer.view().positionedObjects()) {
974 for (RenderBox* it : *viewPositionedObjects) {
975 if (it != &renderer && it->style().position() == FixedPosition && renderer.element()->contains(it->element()))
980 if (renderer.canContainAbsolutelyPositionedObjects()) {
981 // Our layout overflow will include all descendant positioned elements.
985 // This renderer may have positioned descendants whose containing block is some ancestor.
986 if (auto containingBlock = renderer.containingBlockForAbsolutePosition()) {
987 if (auto positionedObjects = containingBlock->positionedObjects()) {
988 for (RenderBox* it : *positionedObjects) {
989 if (it != &renderer && renderer.element()->contains(it->element()))
998 LayoutRect Element::absoluteEventBounds(bool& boundsIncludeAllDescendantElements, bool& includesFixedPositionElements)
1000 boundsIncludeAllDescendantElements = false;
1001 includesFixedPositionElements = false;
1004 return LayoutRect();
1007 if (isSVGElement()) {
1008 // Get the bounding rectangle from the SVG model.
1009 SVGElement& svgElement = downcast<SVGElement>(*this);
1010 FloatRect localRect;
1011 if (svgElement.getBoundingBox(localRect, SVGLocatable::DisallowStyleUpdate))
1012 result = LayoutRect(renderer()->localToAbsoluteQuad(localRect, UseTransforms, &includesFixedPositionElements).boundingBox());
1014 auto* renderer = this->renderer();
1015 if (is<RenderBox>(renderer)) {
1016 auto& box = downcast<RenderBox>(*renderer);
1018 bool computedBounds = false;
1020 if (RenderFlowThread* flowThread = box.flowThreadContainingBlock()) {
1021 bool wasFixed = false;
1022 Vector<FloatQuad> quads;
1023 FloatRect localRect(0, 0, box.width(), box.height());
1024 if (flowThread->absoluteQuadsForBox(quads, &wasFixed, &box, localRect.y(), localRect.maxY())) {
1025 FloatRect quadBounds = quads[0].boundingBox();
1026 for (size_t i = 1; i < quads.size(); ++i)
1027 quadBounds.unite(quads[i].boundingBox());
1029 result = LayoutRect(quadBounds);
1030 computedBounds = true;
1032 // Probably columns. Just return the bounds of the multicol block for now.
1033 // FIXME: this doesn't handle nested columns.
1034 RenderElement* multicolContainer = flowThread->parent();
1035 if (multicolContainer && is<RenderBox>(multicolContainer)) {
1036 auto overflowRect = downcast<RenderBox>(*multicolContainer).layoutOverflowRect();
1037 result = LayoutRect(multicolContainer->localToAbsoluteQuad(FloatRect(overflowRect), UseTransforms, &includesFixedPositionElements).boundingBox());
1038 computedBounds = true;
1043 if (!computedBounds) {
1044 LayoutRect overflowRect = box.layoutOverflowRect();
1045 result = LayoutRect(box.localToAbsoluteQuad(FloatRect(overflowRect), UseTransforms, &includesFixedPositionElements).boundingBox());
1046 boundsIncludeAllDescendantElements = layoutOverflowRectContainsAllDescendants(box);
1049 result = LayoutRect(renderer->absoluteBoundingBoxRect(true /* useTransforms */, &includesFixedPositionElements));
1055 LayoutRect Element::absoluteEventBoundsOfElementAndDescendants(bool& includesFixedPositionElements)
1057 bool boundsIncludeDescendants;
1058 LayoutRect result = absoluteEventBounds(boundsIncludeDescendants, includesFixedPositionElements);
1059 if (boundsIncludeDescendants)
1062 for (auto& child : childrenOfType<Element>(*this)) {
1063 bool includesFixedPosition = false;
1064 LayoutRect childBounds = child.absoluteEventBoundsOfElementAndDescendants(includesFixedPosition);
1065 includesFixedPositionElements |= includesFixedPosition;
1066 result.unite(childBounds);
1072 LayoutRect Element::absoluteEventHandlerBounds(bool& includesFixedPositionElements)
1074 // This is not web-exposed, so don't call the FOUC-inducing updateLayoutIgnorePendingStylesheets().
1075 FrameView* frameView = document().view();
1077 return LayoutRect();
1079 if (frameView->needsLayout())
1080 frameView->layout();
1082 return absoluteEventBoundsOfElementAndDescendants(includesFixedPositionElements);
1085 Ref<ClientRectList> Element::getClientRects()
1087 document().updateLayoutIgnorePendingStylesheets();
1089 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject();
1090 if (!renderBoxModelObject)
1091 return ClientRectList::create();
1093 // FIXME: Handle SVG elements.
1094 // FIXME: Handle table/inline-table with a caption.
1096 Vector<FloatQuad> quads;
1097 renderBoxModelObject->absoluteQuads(quads);
1098 document().adjustFloatQuadsForScrollAndAbsoluteZoomAndFrameScale(quads, renderBoxModelObject->style());
1099 return ClientRectList::create(quads);
1102 Ref<ClientRect> Element::getBoundingClientRect()
1104 document().updateLayoutIgnorePendingStylesheets();
1106 Vector<FloatQuad> quads;
1107 if (isSVGElement() && renderer() && !renderer()->isSVGRoot()) {
1108 // Get the bounding rectangle from the SVG model.
1109 SVGElement& svgElement = downcast<SVGElement>(*this);
1110 FloatRect localRect;
1111 if (svgElement.getBoundingBox(localRect))
1112 quads.append(renderer()->localToAbsoluteQuad(localRect));
1114 // Get the bounding rectangle from the box model.
1115 if (renderBoxModelObject())
1116 renderBoxModelObject()->absoluteQuads(quads);
1119 if (quads.isEmpty())
1120 return ClientRect::create();
1122 FloatRect result = quads[0].boundingBox();
1123 for (size_t i = 1; i < quads.size(); ++i)
1124 result.unite(quads[i].boundingBox());
1126 document().adjustFloatRectForScrollAndAbsoluteZoomAndFrameScale(result, renderer()->style());
1127 return ClientRect::create(result);
1130 IntRect Element::clientRect() const
1132 if (RenderObject* renderer = this->renderer())
1133 return document().view()->contentsToRootView(renderer->absoluteBoundingBoxRect());
1137 IntRect Element::screenRect() const
1139 if (RenderObject* renderer = this->renderer())
1140 return document().view()->contentsToScreen(renderer->absoluteBoundingBoxRect());
1144 const AtomicString& Element::getAttribute(const AtomicString& localName) const
1148 synchronizeAttribute(localName);
1149 if (const Attribute* attribute = elementData()->findAttributeByName(localName, shouldIgnoreAttributeCase(*this)))
1150 return attribute->value();
1154 const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
1156 return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
1159 void Element::setAttribute(const AtomicString& localName, const AtomicString& value, ExceptionCode& ec)
1161 if (!Document::isValidName(localName)) {
1162 ec = INVALID_CHARACTER_ERR;
1166 synchronizeAttribute(localName);
1167 const AtomicString& caseAdjustedLocalName = shouldIgnoreAttributeCase(*this) ? localName.convertToASCIILowercase() : localName;
1169 unsigned index = elementData() ? elementData()->findAttributeIndexByName(caseAdjustedLocalName, false) : ElementData::attributeNotFound;
1170 const QualifiedName& qName = index != ElementData::attributeNotFound ? attributeAt(index).name() : QualifiedName(nullAtom, caseAdjustedLocalName, nullAtom);
1171 setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute);
1174 void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
1176 synchronizeAttribute(name);
1177 unsigned index = elementData() ? elementData()->findAttributeIndexByName(name) : ElementData::attributeNotFound;
1178 setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute);
1181 void Element::setAttributeWithoutSynchronization(const QualifiedName& name, const AtomicString& value)
1183 unsigned index = elementData() ? elementData()->findAttributeIndexByName(name) : ElementData::attributeNotFound;
1184 setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute);
1187 void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value)
1189 unsigned index = elementData() ? elementData()->findAttributeIndexByName(name) : ElementData::attributeNotFound;
1190 setAttributeInternal(index, name, value, InSynchronizationOfLazyAttribute);
1193 inline void Element::setAttributeInternal(unsigned index, const QualifiedName& name, const AtomicString& newValue, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1195 if (newValue.isNull()) {
1196 if (index != ElementData::attributeNotFound)
1197 removeAttributeInternal(index, inSynchronizationOfLazyAttribute);
1201 if (index == ElementData::attributeNotFound) {
1202 addAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute);
1206 if (inSynchronizationOfLazyAttribute) {
1207 ensureUniqueElementData().attributeAt(index).setValue(newValue);
1211 const Attribute& attribute = attributeAt(index);
1212 QualifiedName attributeName = attribute.name();
1213 AtomicString oldValue = attribute.value();
1215 willModifyAttribute(attributeName, oldValue, newValue);
1217 if (newValue != oldValue) {
1218 // If there is an Attr node hooked to this attribute, the Attr::setValue() call below
1219 // will write into the ElementData.
1220 // FIXME: Refactor this so it makes some sense.
1221 if (RefPtr<Attr> attrNode = attrIfExists(attributeName))
1222 attrNode->setValue(newValue);
1224 Style::AttributeChangeInvalidation styleInvalidation(*this, name, oldValue, newValue);
1225 ensureUniqueElementData().attributeAt(index).setValue(newValue);
1229 didModifyAttribute(attributeName, oldValue, newValue);
1232 static inline AtomicString makeIdForStyleResolution(const AtomicString& value, bool inQuirksMode)
1235 return value.convertToASCIILowercase();
1239 void Element::attributeChanged(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue, AttributeModificationReason)
1241 bool valueIsSameAsBefore = oldValue == newValue;
1243 if (!valueIsSameAsBefore) {
1244 if (name == HTMLNames::idAttr) {
1245 if (!oldValue.isEmpty())
1246 treeScope().idTargetObserverRegistry().notifyObservers(*oldValue.impl());
1247 if (!newValue.isEmpty())
1248 treeScope().idTargetObserverRegistry().notifyObservers(*newValue.impl());
1250 AtomicString oldId = elementData()->idForStyleResolution();
1251 AtomicString newId = makeIdForStyleResolution(newValue, document().inQuirksMode());
1252 if (newId != oldId) {
1253 Style::IdChangeInvalidation styleInvalidation(*this, oldId, newId);
1254 elementData()->setIdForStyleResolution(newId);
1256 } else if (name == classAttr)
1257 classAttributeChanged(newValue);
1258 else if (name == HTMLNames::nameAttr)
1259 elementData()->setHasNameAttribute(!newValue.isNull());
1260 else if (name == HTMLNames::pseudoAttr) {
1261 if (needsStyleInvalidation() && isInShadowTree())
1262 setNeedsStyleRecalc(FullStyleChange);
1264 else if (name == HTMLNames::slotAttr) {
1265 if (auto* parent = parentElement()) {
1266 if (auto* shadowRoot = parent->shadowRoot())
1267 shadowRoot->hostChildElementDidChangeSlotAttribute(oldValue, newValue);
1272 parseAttribute(name, newValue);
1274 document().incDOMTreeVersion();
1276 #if ENABLE(CUSTOM_ELEMENTS)
1277 if (UNLIKELY(isCustomElement())) {
1278 auto* definitions = document().customElementDefinitions();
1279 auto* interface = definitions->findInterface(tagQName());
1280 RELEASE_ASSERT(interface);
1281 LifecycleCallbackQueue::enqueueAttributeChangedCallback(*this, *interface, name, oldValue, newValue);
1285 if (valueIsSameAsBefore)
1288 invalidateNodeListAndCollectionCachesInAncestors(&name, this);
1290 if (AXObjectCache* cache = document().existingAXObjectCache())
1291 cache->handleAttributeChanged(name, this);
1294 template <typename CharacterType>
1295 static inline bool classStringHasClassName(const CharacterType* characters, unsigned length)
1301 if (isNotHTMLSpace(characters[i]))
1304 } while (i < length);
1309 static inline bool classStringHasClassName(const AtomicString& newClassString)
1311 unsigned length = newClassString.length();
1316 if (newClassString.is8Bit())
1317 return classStringHasClassName(newClassString.characters8(), length);
1318 return classStringHasClassName(newClassString.characters16(), length);
1321 void Element::classAttributeChanged(const AtomicString& newClassString)
1323 // Note: We'll need ElementData, but it doesn't have to be UniqueElementData.
1325 ensureUniqueElementData();
1327 bool shouldFoldCase = document().inQuirksMode();
1328 bool newStringHasClasses = classStringHasClassName(newClassString);
1330 auto oldClassNames = elementData()->classNames();
1331 auto newClassNames = newStringHasClasses ? SpaceSplitString(newClassString, shouldFoldCase) : SpaceSplitString();
1333 Style::ClassChangeInvalidation styleInvalidation(*this, oldClassNames, newClassNames);
1334 elementData()->setClassNames(newClassNames);
1337 if (hasRareData()) {
1338 if (auto* classList = elementRareData()->classList())
1339 classList->associatedAttributeValueChanged(newClassString);
1343 URL Element::absoluteLinkURL() const
1348 AtomicString linkAttribute;
1349 if (hasTagName(SVGNames::aTag))
1350 linkAttribute = getAttribute(XLinkNames::hrefAttr);
1352 linkAttribute = getAttribute(HTMLNames::hrefAttr);
1354 if (linkAttribute.isEmpty())
1357 return document().completeURL(stripLeadingAndTrailingHTMLSpaces(linkAttribute));
1360 #if ENABLE(TOUCH_EVENTS)
1361 bool Element::allowsDoubleTapGesture() const
1363 if (renderStyle() && renderStyle()->touchAction() != TouchAction::Auto)
1366 Element* parent = parentElement();
1367 return !parent || parent->allowsDoubleTapGesture();
1371 StyleResolver& Element::styleResolver()
1373 if (auto* shadowRoot = containingShadowRoot())
1374 return shadowRoot->styleResolver();
1376 return document().ensureStyleResolver();
1379 ElementStyle Element::resolveStyle(const RenderStyle* parentStyle)
1381 return styleResolver().styleForElement(*this, parentStyle);
1384 bool Element::hasDisplayContents() const
1386 return hasRareData() && elementRareData()->hasDisplayContents();
1389 void Element::setHasDisplayContents(bool value)
1391 if (hasDisplayContents() == value)
1393 ensureElementRareData().setHasDisplayContents(value);
1396 // Returns true is the given attribute is an event handler.
1397 // We consider an event handler any attribute that begins with "on".
1398 // It is a simple solution that has the advantage of not requiring any
1399 // code or configuration change if a new event handler is defined.
1401 static inline bool isEventHandlerAttribute(const Attribute& attribute)
1403 return attribute.name().namespaceURI().isNull() && attribute.name().localName().startsWith("on");
1406 bool Element::isJavaScriptURLAttribute(const Attribute& attribute) const
1408 return isURLAttribute(attribute) && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(attribute.value()));
1411 void Element::stripScriptingAttributes(Vector<Attribute>& attributeVector) const
1413 size_t destination = 0;
1414 for (size_t source = 0; source < attributeVector.size(); ++source) {
1415 if (isEventHandlerAttribute(attributeVector[source])
1416 || isJavaScriptURLAttribute(attributeVector[source])
1417 || isHTMLContentAttribute(attributeVector[source]))
1420 if (source != destination)
1421 attributeVector[destination] = attributeVector[source];
1425 attributeVector.shrink(destination);
1428 void Element::parserSetAttributes(const Vector<Attribute>& attributeVector)
1430 ASSERT(!inDocument());
1431 ASSERT(!parentNode());
1432 ASSERT(!m_elementData);
1434 if (!attributeVector.isEmpty()) {
1435 if (document().sharedObjectPool())
1436 m_elementData = document().sharedObjectPool()->cachedShareableElementDataWithAttributes(attributeVector);
1438 m_elementData = ShareableElementData::createWithAttributes(attributeVector);
1442 parserDidSetAttributes();
1444 // Use attributeVector instead of m_elementData because attributeChanged might modify m_elementData.
1445 for (const auto& attribute : attributeVector)
1446 attributeChanged(attribute.name(), nullAtom, attribute.value(), ModifiedDirectly);
1449 void Element::parserDidSetAttributes()
1453 bool Element::hasAttributes() const
1455 synchronizeAllAttributes();
1456 return elementData() && elementData()->length();
1459 bool Element::hasEquivalentAttributes(const Element* other) const
1461 synchronizeAllAttributes();
1462 other->synchronizeAllAttributes();
1463 if (elementData() == other->elementData())
1466 return elementData()->isEquivalent(other->elementData());
1467 if (other->elementData())
1468 return other->elementData()->isEquivalent(elementData());
1472 String Element::nodeName() const
1474 return m_tagName.toString();
1477 String Element::nodeNamePreservingCase() const
1479 return m_tagName.toString();
1482 void Element::setPrefix(const AtomicString& prefix, ExceptionCode& ec)
1485 checkSetPrefix(prefix, ec);
1489 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
1492 const AtomicString& Element::imageSourceURL() const
1494 return fastGetAttribute(srcAttr);
1497 bool Element::rendererIsNeeded(const RenderStyle& style)
1499 return style.display() != NONE && style.display() != CONTENTS;
1502 RenderPtr<RenderElement> Element::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
1504 return RenderElement::createFor(*this, WTFMove(style));
1507 Node::InsertionNotificationRequest Element::insertedInto(ContainerNode& insertionPoint)
1509 bool wasInDocument = inDocument();
1510 // need to do superclass processing first so inDocument() is true
1511 // by the time we reach updateId
1512 ContainerNode::insertedInto(insertionPoint);
1513 ASSERT(!wasInDocument || inDocument());
1515 #if ENABLE(FULLSCREEN_API)
1516 if (containsFullScreenElement() && parentElement() && !parentElement()->containsFullScreenElement())
1517 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
1520 if (parentNode() == &insertionPoint) {
1521 if (auto* shadowRoot = parentNode()->shadowRoot())
1522 shadowRoot->hostChildElementDidChange(*this);
1525 if (!insertionPoint.isInTreeScope())
1526 return InsertionDone;
1528 // This function could be called when this element's shadow root's host or its ancestor is inserted.
1529 // This element is new to the shadow tree (and its tree scope) only if the parent into which this element
1530 // or its ancestor is inserted belongs to the same tree scope as this element's.
1531 TreeScope* newScope = &insertionPoint.treeScope();
1532 HTMLDocument* newDocument = !wasInDocument && inDocument() && is<HTMLDocument>(newScope->documentScope()) ? &downcast<HTMLDocument>(newScope->documentScope()) : nullptr;
1533 if (newScope != &treeScope())
1536 const AtomicString& idValue = getIdAttribute();
1537 if (!idValue.isNull()) {
1539 updateIdForTreeScope(*newScope, nullAtom, idValue);
1541 updateIdForDocument(*newDocument, nullAtom, idValue, AlwaysUpdateHTMLDocumentNamedItemMaps);
1544 const AtomicString& nameValue = getNameAttribute();
1545 if (!nameValue.isNull()) {
1547 updateNameForTreeScope(*newScope, nullAtom, nameValue);
1549 updateNameForDocument(*newDocument, nullAtom, nameValue);
1552 if (newScope && hasTagName(labelTag)) {
1553 if (newScope->shouldCacheLabelsByForAttribute())
1554 updateLabel(*newScope, nullAtom, fastGetAttribute(forAttr));
1557 return InsertionDone;
1560 void Element::removedFrom(ContainerNode& insertionPoint)
1562 #if ENABLE(FULLSCREEN_API)
1563 if (containsFullScreenElement())
1564 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
1566 #if ENABLE(POINTER_LOCK)
1567 if (document().page())
1568 document().page()->pointerLockController().elementRemoved(this);
1571 setSavedLayerScrollPosition(ScrollPosition());
1573 if (insertionPoint.isInTreeScope()) {
1574 TreeScope* oldScope = &insertionPoint.treeScope();
1575 HTMLDocument* oldDocument = inDocument() && is<HTMLDocument>(oldScope->documentScope()) ? &downcast<HTMLDocument>(oldScope->documentScope()) : nullptr;
1577 // ContainerNode::removeBetween always sets the removed chid's tree scope to Document's but InTreeScope flag is unset in Node::removedFrom.
1578 // So this element has been removed from the old tree scope only if InTreeScope flag is set and this element's tree scope is Document's.
1579 if (!isInTreeScope() || &treeScope() != &document())
1582 const AtomicString& idValue = getIdAttribute();
1583 if (!idValue.isNull()) {
1585 updateIdForTreeScope(*oldScope, idValue, nullAtom);
1587 updateIdForDocument(*oldDocument, idValue, nullAtom, AlwaysUpdateHTMLDocumentNamedItemMaps);
1590 const AtomicString& nameValue = getNameAttribute();
1591 if (!nameValue.isNull()) {
1593 updateNameForTreeScope(*oldScope, nameValue, nullAtom);
1595 updateNameForDocument(*oldDocument, nameValue, nullAtom);
1598 if (oldScope && hasTagName(labelTag)) {
1599 if (oldScope->shouldCacheLabelsByForAttribute())
1600 updateLabel(*oldScope, fastGetAttribute(forAttr), nullAtom);
1604 if (!parentNode()) {
1605 if (auto* shadowRoot = insertionPoint.shadowRoot())
1606 shadowRoot->hostChildElementDidChange(*this);
1609 ContainerNode::removedFrom(insertionPoint);
1611 if (hasPendingResources())
1612 document().accessSVGExtensions().removeElementFromPendingResources(this);
1616 if (Frame* frame = document().frame())
1617 frame->mainFrame().removeLatchingStateForTarget(*this);
1621 void Element::unregisterNamedFlowContentElement()
1623 if (isNamedFlowContentNode() && document().renderView())
1624 document().renderView()->flowThreadController().unregisterNamedFlowContentElement(*this);
1627 ShadowRoot* Element::shadowRoot() const
1629 return hasRareData() ? elementRareData()->shadowRoot() : nullptr;
1633 void Element::addShadowRoot(Ref<ShadowRoot>&& newShadowRoot)
1635 ASSERT(!shadowRoot());
1637 ShadowRoot& shadowRoot = newShadowRoot.get();
1638 ensureElementRareData().setShadowRoot(WTFMove(newShadowRoot));
1640 shadowRoot.setHost(this);
1641 shadowRoot.setParentTreeScope(&treeScope());
1643 NodeVector postInsertionNotificationTargets;
1644 notifyChildNodeInserted(*this, shadowRoot, postInsertionNotificationTargets);
1645 for (auto& target : postInsertionNotificationTargets)
1646 target->finishedInsertingSubtree();
1648 setNeedsStyleRecalc(ReconstructRenderTree);
1650 InspectorInstrumentation::didPushShadowRoot(*this, shadowRoot);
1652 if (shadowRoot.type() == ShadowRoot::Type::UserAgent)
1653 didAddUserAgentShadowRoot(&shadowRoot);
1656 void Element::removeShadowRoot()
1658 RefPtr<ShadowRoot> oldRoot = shadowRoot();
1661 InspectorInstrumentation::willPopShadowRoot(*this, *oldRoot);
1662 document().removeFocusedNodeOfSubtree(oldRoot.get());
1664 ASSERT(!oldRoot->renderer());
1666 elementRareData()->clearShadowRoot();
1668 oldRoot->setHost(nullptr);
1669 oldRoot->setParentTreeScope(&document());
1671 notifyChildNodeRemoved(*this, *oldRoot);
1674 RefPtr<ShadowRoot> Element::createShadowRoot(ExceptionCode& ec)
1676 if (alwaysCreateUserAgentShadowRoot())
1677 ensureUserAgentShadowRoot();
1679 ec = HIERARCHY_REQUEST_ERR;
1684 static bool canAttachAuthorShadowRoot(const Element& element)
1686 static NeverDestroyed<HashSet<AtomicString>> tagNames = [] {
1687 static const HTMLQualifiedName* const tagList[] = {
1706 HashSet<AtomicString> set;
1707 for (auto& name : tagList)
1708 set.add(name->localName());
1712 if (!is<HTMLElement>(element))
1715 const auto& localName = element.localName();
1716 return tagNames.get().contains(localName) || Document::validateCustomElementName(localName) == CustomElementNameValidationStatus::Valid;
1719 RefPtr<ShadowRoot> Element::attachShadow(const ShadowRootInit& init, ExceptionCode& ec)
1721 if (!canAttachAuthorShadowRoot(*this)) {
1722 ec = NOT_SUPPORTED_ERR;
1727 ec = INVALID_STATE_ERR;
1731 auto shadow = ShadowRoot::create(document(), init.mode == ShadowRootMode::Open ? ShadowRoot::Type::Open : ShadowRoot::Type::Closed);
1732 addShadowRoot(shadow.copyRef());
1733 return WTFMove(shadow);
1736 ShadowRoot* Element::shadowRootForBindings(JSC::ExecState& state) const
1738 ShadowRoot* root = shadowRoot();
1742 if (root->type() != ShadowRoot::Type::Open) {
1743 if (!JSC::jsCast<JSDOMGlobalObject*>(state.lexicalGlobalObject())->world().shadowRootIsAlwaysOpen())
1750 ShadowRoot* Element::userAgentShadowRoot() const
1752 if (ShadowRoot* shadowRoot = this->shadowRoot()) {
1753 ASSERT(shadowRoot->type() == ShadowRoot::Type::UserAgent);
1759 ShadowRoot& Element::ensureUserAgentShadowRoot()
1761 ShadowRoot* shadowRoot = userAgentShadowRoot();
1763 addShadowRoot(ShadowRoot::create(document(), ShadowRoot::Type::UserAgent));
1764 shadowRoot = userAgentShadowRoot();
1769 const AtomicString& Element::shadowPseudoId() const
1774 bool Element::childTypeAllowed(NodeType type) const
1780 case PROCESSING_INSTRUCTION_NODE:
1781 case CDATA_SECTION_NODE:
1789 static void checkForEmptyStyleChange(Element& element)
1791 if (element.styleAffectedByEmpty()) {
1792 auto* style = element.renderStyle();
1793 if (!style || (!style->emptyState() || element.hasChildNodes()))
1794 element.setNeedsStyleRecalc();
1798 enum SiblingCheckType { FinishedParsingChildren, SiblingElementRemoved, Other };
1800 static void checkForSiblingStyleChanges(Element& parent, SiblingCheckType checkType, Element* elementBeforeChange, Element* elementAfterChange)
1803 checkForEmptyStyleChange(parent);
1805 if (parent.styleChangeType() >= FullStyleChange)
1808 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1809 // In the DOM case, we only need to do something if |afterChange| is not 0.
1810 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
1811 if (parent.childrenAffectedByFirstChildRules() && elementAfterChange) {
1812 // Find our new first child.
1813 Element* newFirstElement = ElementTraversal::firstChild(parent);
1814 // Find the first element node following |afterChange|
1816 // This is the insert/append case.
1817 if (newFirstElement != elementAfterChange) {
1818 auto* style = elementAfterChange->renderStyle();
1819 if (!style || style->firstChildState())
1820 elementAfterChange->setNeedsStyleRecalc();
1823 // We also have to handle node removal.
1824 if (checkType == SiblingElementRemoved && newFirstElement == elementAfterChange && newFirstElement) {
1825 auto* style = newFirstElement->renderStyle();
1826 if (!style || !style->firstChildState())
1827 newFirstElement->setNeedsStyleRecalc();
1831 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1832 // In the DOM case, we only need to do something if |afterChange| is not 0.
1833 if (parent.childrenAffectedByLastChildRules() && elementBeforeChange) {
1834 // Find our new last child.
1835 Element* newLastElement = ElementTraversal::lastChild(parent);
1837 if (newLastElement != elementBeforeChange) {
1838 auto* style = elementBeforeChange->renderStyle();
1839 if (!style || style->lastChildState())
1840 elementBeforeChange->setNeedsStyleRecalc();
1843 // 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
1845 if ((checkType == SiblingElementRemoved || checkType == FinishedParsingChildren) && newLastElement == elementBeforeChange && newLastElement) {
1846 auto* style = newLastElement->renderStyle();
1847 if (!style || !style->lastChildState())
1848 newLastElement->setNeedsStyleRecalc();
1852 if (elementAfterChange) {
1853 if (elementAfterChange->styleIsAffectedByPreviousSibling())
1854 elementAfterChange->setNeedsStyleRecalc();
1855 else if (elementAfterChange->affectsNextSiblingElementStyle()) {
1856 Element* elementToInvalidate = elementAfterChange;
1858 elementToInvalidate = elementToInvalidate->nextElementSibling();
1859 } while (elementToInvalidate && !elementToInvalidate->styleIsAffectedByPreviousSibling());
1861 if (elementToInvalidate)
1862 elementToInvalidate->setNeedsStyleRecalc();
1866 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1867 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
1869 // |afterChange| is 0 in the parser callback case, so we won't do any work for the forward case if we don't have to.
1870 // For performance reasons we just mark the parent node as changed, since we don't want to make childrenChanged O(n^2) by crawling all our kids
1871 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
1872 if (parent.childrenAffectedByBackwardPositionalRules() && elementBeforeChange)
1873 parent.setNeedsStyleRecalc();
1876 void Element::childrenChanged(const ChildChange& change)
1878 ContainerNode::childrenChanged(change);
1879 if (change.source == ChildChangeSourceParser)
1880 checkForEmptyStyleChange(*this);
1882 SiblingCheckType checkType = change.type == ElementRemoved ? SiblingElementRemoved : Other;
1883 checkForSiblingStyleChanges(*this, checkType, change.previousSiblingElement, change.nextSiblingElement);
1886 if (ShadowRoot* shadowRoot = this->shadowRoot()) {
1887 switch (change.type) {
1888 case ElementInserted:
1889 case ElementRemoved:
1890 // For elements, we notify shadowRoot in Element::insertedInto and Element::removedFrom.
1892 case AllChildrenRemoved:
1893 shadowRoot->didRemoveAllChildrenOfShadowHost();
1898 shadowRoot->didChangeDefaultSlot();
1900 case NonContentsChildChanged:
1906 void Element::setAttributeEventListener(const AtomicString& eventType, const QualifiedName& attributeName, const AtomicString& attributeValue)
1908 setAttributeEventListener(eventType, JSLazyEventListener::create(*this, attributeName, attributeValue));
1911 void Element::removeAllEventListeners()
1913 ContainerNode::removeAllEventListeners();
1914 if (ShadowRoot* shadowRoot = this->shadowRoot())
1915 shadowRoot->removeAllEventListeners();
1918 void Element::beginParsingChildren()
1920 clearIsParsingChildrenFinished();
1923 void Element::finishParsingChildren()
1925 ContainerNode::finishParsingChildren();
1926 setIsParsingChildrenFinished();
1927 checkForSiblingStyleChanges(*this, FinishedParsingChildren, ElementTraversal::lastChild(*this), nullptr);
1930 #if ENABLE(TREE_DEBUGGING)
1931 void Element::formatForDebugger(char* buffer, unsigned length) const
1933 StringBuilder result;
1936 result.append(nodeName());
1938 s = getIdAttribute();
1939 if (s.length() > 0) {
1940 if (result.length() > 0)
1941 result.appendLiteral("; ");
1942 result.appendLiteral("id=");
1946 s = getAttribute(classAttr);
1947 if (s.length() > 0) {
1948 if (result.length() > 0)
1949 result.appendLiteral("; ");
1950 result.appendLiteral("class=");
1954 strncpy(buffer, result.toString().utf8().data(), length - 1);
1958 const Vector<RefPtr<Attr>>& Element::attrNodeList()
1960 ASSERT(hasSyntheticAttrChildNodes());
1961 return *attrNodeListForElement(*this);
1964 RefPtr<Attr> Element::setAttributeNode(Attr& attrNode, ExceptionCode& ec)
1966 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode.qualifiedName().localName(), shouldIgnoreAttributeCase(*this));
1967 if (oldAttrNode.get() == &attrNode)
1968 return &attrNode; // This Attr is already attached to the element.
1970 // INUSE_ATTRIBUTE_ERR: Raised if node is an Attr that is already an attribute of another Element object.
1971 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
1972 if (attrNode.ownerElement() && attrNode.ownerElement() != this) {
1973 ec = INUSE_ATTRIBUTE_ERR;
1977 synchronizeAllAttributes();
1978 UniqueElementData& elementData = ensureUniqueElementData();
1980 unsigned existingAttributeIndex = elementData.findAttributeIndexByName(attrNode.qualifiedName().localName(), shouldIgnoreAttributeCase(*this));
1981 if (existingAttributeIndex != ElementData::attributeNotFound) {
1982 const Attribute& attribute = attributeAt(existingAttributeIndex);
1984 detachAttrNodeFromElementWithValue(oldAttrNode.get(), attribute.value());
1986 oldAttrNode = Attr::create(document(), attrNode.qualifiedName(), attribute.value());
1988 if (attribute.name().matches(attrNode.qualifiedName()))
1989 setAttributeInternal(existingAttributeIndex, attrNode.qualifiedName(), attrNode.value(), NotInSynchronizationOfLazyAttribute);
1991 removeAttributeInternal(existingAttributeIndex, NotInSynchronizationOfLazyAttribute);
1992 unsigned existingAttributeIndexForFullQualifiedName = elementData.findAttributeIndexByName(attrNode.qualifiedName());
1993 setAttributeInternal(existingAttributeIndexForFullQualifiedName, attrNode.qualifiedName(), attrNode.value(), NotInSynchronizationOfLazyAttribute);
1996 unsigned existingAttributeIndexForFullQualifiedName = elementData.findAttributeIndexByName(attrNode.qualifiedName());
1997 setAttributeInternal(existingAttributeIndexForFullQualifiedName, attrNode.qualifiedName(), attrNode.value(), NotInSynchronizationOfLazyAttribute);
1999 if (attrNode.ownerElement() != this) {
2000 attrNode.attachToElement(this);
2001 treeScope().adoptIfNeeded(&attrNode);
2002 ensureAttrNodeListForElement(*this).append(&attrNode);
2007 RefPtr<Attr> Element::setAttributeNodeNS(Attr& attrNode, ExceptionCode& ec)
2009 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode.qualifiedName());
2010 if (oldAttrNode.get() == &attrNode)
2011 return &attrNode; // This Attr is already attached to the element.
2013 // INUSE_ATTRIBUTE_ERR: Raised if node is an Attr that is already an attribute of another Element object.
2014 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
2015 if (attrNode.ownerElement() && attrNode.ownerElement() != this) {
2016 ec = INUSE_ATTRIBUTE_ERR;
2020 synchronizeAllAttributes();
2021 UniqueElementData& elementData = ensureUniqueElementData();
2023 unsigned index = elementData.findAttributeIndexByName(attrNode.qualifiedName());
2024 if (index != ElementData::attributeNotFound) {
2026 detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData.attributeAt(index).value());
2028 oldAttrNode = Attr::create(document(), attrNode.qualifiedName(), elementData.attributeAt(index).value());
2031 setAttributeInternal(index, attrNode.qualifiedName(), attrNode.value(), NotInSynchronizationOfLazyAttribute);
2033 attrNode.attachToElement(this);
2034 treeScope().adoptIfNeeded(&attrNode);
2035 ensureAttrNodeListForElement(*this).append(&attrNode);
2040 RefPtr<Attr> Element::removeAttributeNode(Attr& attr, ExceptionCode& ec)
2042 if (attr.ownerElement() != this) {
2047 ASSERT(&document() == &attr.document());
2049 synchronizeAllAttributes();
2051 if (!m_elementData) {
2056 unsigned existingAttributeIndex = m_elementData->findAttributeIndexByName(attr.qualifiedName());
2058 if (existingAttributeIndex == ElementData::attributeNotFound) {
2063 RefPtr<Attr> attrNode = &attr;
2064 detachAttrNodeFromElementWithValue(&attr, m_elementData->attributeAt(existingAttributeIndex).value());
2065 removeAttributeInternal(existingAttributeIndex, NotInSynchronizationOfLazyAttribute);
2069 bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionCode& ec)
2071 String prefix, localName;
2072 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec))
2076 QualifiedName qName(prefix, localName, namespaceURI);
2078 if (!Document::hasValidNamespaceForAttributes(qName)) {
2087 void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode& ec)
2089 QualifiedName parsedName = anyName;
2090 if (!parseAttributeName(parsedName, namespaceURI, qualifiedName, ec))
2092 setAttribute(parsedName, value);
2095 void Element::removeAttributeInternal(unsigned index, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
2097 ASSERT_WITH_SECURITY_IMPLICATION(index < attributeCount());
2099 UniqueElementData& elementData = ensureUniqueElementData();
2101 QualifiedName name = elementData.attributeAt(index).name();
2102 AtomicString valueBeingRemoved = elementData.attributeAt(index).value();
2104 if (RefPtr<Attr> attrNode = attrIfExists(name))
2105 detachAttrNodeFromElementWithValue(attrNode.get(), elementData.attributeAt(index).value());
2107 if (inSynchronizationOfLazyAttribute) {
2108 elementData.removeAttribute(index);
2112 if (!valueBeingRemoved.isNull())
2113 willModifyAttribute(name, valueBeingRemoved, nullAtom);
2116 Style::AttributeChangeInvalidation styleInvalidation(*this, name, valueBeingRemoved, nullAtom);
2117 elementData.removeAttribute(index);
2120 didRemoveAttribute(name, valueBeingRemoved);
2123 void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
2125 if (inSynchronizationOfLazyAttribute) {
2126 ensureUniqueElementData().addAttribute(name, value);
2130 willModifyAttribute(name, nullAtom, value);
2132 Style::AttributeChangeInvalidation styleInvalidation(*this, name, nullAtom, value);
2133 ensureUniqueElementData().addAttribute(name, value);
2135 didAddAttribute(name, value);
2138 bool Element::removeAttribute(const AtomicString& name)
2143 AtomicString localName = shouldIgnoreAttributeCase(*this) ? name.convertToASCIILowercase() : name;
2144 unsigned index = elementData()->findAttributeIndexByName(localName, false);
2145 if (index == ElementData::attributeNotFound) {
2146 if (UNLIKELY(localName == styleAttr) && elementData()->styleAttributeIsDirty() && is<StyledElement>(*this))
2147 downcast<StyledElement>(*this).removeAllInlineStyleProperties();
2151 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
2155 bool Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName)
2157 return removeAttribute(QualifiedName(nullAtom, localName, namespaceURI));
2160 RefPtr<Attr> Element::getAttributeNode(const AtomicString& localName)
2164 synchronizeAttribute(localName);
2165 const Attribute* attribute = elementData()->findAttributeByName(localName, shouldIgnoreAttributeCase(*this));
2168 return ensureAttr(attribute->name());
2171 RefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
2175 QualifiedName qName(nullAtom, localName, namespaceURI);
2176 synchronizeAttribute(qName);
2177 const Attribute* attribute = elementData()->findAttributeByName(qName);
2180 return ensureAttr(attribute->name());
2183 bool Element::hasAttribute(const AtomicString& localName) const
2187 synchronizeAttribute(localName);
2188 return elementData()->findAttributeByName(localName, shouldIgnoreAttributeCase(*this));
2191 bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
2195 QualifiedName qName(nullAtom, localName, namespaceURI);
2196 synchronizeAttribute(qName);
2197 return elementData()->findAttributeByName(qName);
2200 CSSStyleDeclaration* Element::cssomStyle()
2205 void Element::focus(bool restorePreviousSelection, FocusDirection direction)
2210 if (document().focusedElement() == this) {
2211 if (document().page())
2212 document().page()->chrome().client().elementDidRefocus(this);
2217 // If the stylesheets have already been loaded we can reliably check isFocusable.
2218 // If not, we continue and set the focused node on the focus controller below so
2219 // that it can be updated soon after attach.
2220 if (document().haveStylesheetsLoaded()) {
2221 document().updateLayoutIgnorePendingStylesheets();
2226 if (!supportsFocus())
2229 RefPtr<Node> protect;
2230 if (Page* page = document().page()) {
2231 // Focus and change event handlers can cause us to lose our last ref.
2232 // If a focus event handler changes the focus to a different node it
2233 // does not make sense to continue and update appearence.
2235 if (!page->focusController().setFocusedElement(this, document().frame(), direction))
2239 // Setting the focused node above might have invalidated the layout due to scripts.
2240 document().updateLayoutIgnorePendingStylesheets();
2242 if (!isFocusable()) {
2243 ensureElementRareData().setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
2247 cancelFocusAppearanceUpdate();
2249 // Focusing a form element triggers animation in UIKit to scroll to the right position.
2250 // Calling updateFocusAppearance() would generate an unnecessary call to ScrollView::setScrollPosition(),
2251 // which would jump us around during this animation. See <rdar://problem/6699741>.
2252 FrameView* view = document().view();
2253 bool isFormControl = view && is<HTMLFormControlElement>(*this);
2255 view->setProhibitsScrolling(true);
2257 updateFocusAppearance(restorePreviousSelection ? SelectionRestorationMode::Restore : SelectionRestorationMode::SetDefault);
2260 view->setProhibitsScrolling(false);
2264 void Element::updateFocusAppearanceAfterAttachIfNeeded()
2268 ElementRareData* data = elementRareData();
2269 if (!data->needsFocusAppearanceUpdateSoonAfterAttach())
2271 if (isFocusable() && document().focusedElement() == this)
2272 document().updateFocusAppearanceSoon(SelectionRestorationMode::SetDefault);
2273 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
2276 void Element::updateFocusAppearance(SelectionRestorationMode, SelectionRevealMode revealMode)
2278 if (isRootEditableElement()) {
2279 // Keep frame alive in this method, since setSelection() may release the last reference to |frame|.
2280 RefPtr<Frame> frame = document().frame();
2284 // When focusing an editable element in an iframe, don't reset the selection if it already contains a selection.
2285 if (this == frame->selection().selection().rootEditableElement())
2288 // FIXME: We should restore the previous selection if there is one.
2289 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
2291 if (frame->selection().shouldChangeSelection(newSelection)) {
2292 frame->selection().setSelection(newSelection, FrameSelection::defaultSetSelectionOptions(), Element::defaultFocusTextStateChangeIntent());
2293 if (revealMode == SelectionRevealMode::Reveal)
2294 frame->selection().revealSelection();
2296 } else if (renderer() && !renderer()->isWidget() && revealMode == SelectionRevealMode::Reveal)
2297 renderer()->scrollRectToVisible(renderer()->anchorRect());
2300 void Element::blur()
2302 cancelFocusAppearanceUpdate();
2303 if (treeScope().focusedElement() == this) {
2304 if (Frame* frame = document().frame())
2305 frame->page()->focusController().setFocusedElement(0, frame);
2307 document().setFocusedElement(nullptr);
2311 void Element::dispatchFocusInEvent(const AtomicString& eventType, RefPtr<Element>&& oldFocusedElement)
2313 ASSERT_WITH_SECURITY_IMPLICATION(!NoEventDispatchAssertion::isEventDispatchForbidden());
2314 ASSERT(eventType == eventNames().focusinEvent || eventType == eventNames().DOMFocusInEvent);
2315 dispatchScopedEvent(FocusEvent::create(eventType, true, false, document().defaultView(), 0, WTFMove(oldFocusedElement)));
2318 void Element::dispatchFocusOutEvent(const AtomicString& eventType, RefPtr<Element>&& newFocusedElement)
2320 ASSERT_WITH_SECURITY_IMPLICATION(!NoEventDispatchAssertion::isEventDispatchForbidden());
2321 ASSERT(eventType == eventNames().focusoutEvent || eventType == eventNames().DOMFocusOutEvent);
2322 dispatchScopedEvent(FocusEvent::create(eventType, true, false, document().defaultView(), 0, WTFMove(newFocusedElement)));
2325 void Element::dispatchFocusEvent(RefPtr<Element>&& oldFocusedElement, FocusDirection)
2327 if (document().page())
2328 document().page()->chrome().client().elementDidFocus(this);
2330 EventDispatcher::dispatchEvent(this, FocusEvent::create(eventNames().focusEvent, false, false, document().defaultView(), 0, WTFMove(oldFocusedElement)));
2333 void Element::dispatchBlurEvent(RefPtr<Element>&& newFocusedElement)
2335 if (document().page())
2336 document().page()->chrome().client().elementDidBlur(this);
2338 EventDispatcher::dispatchEvent(this, FocusEvent::create(eventNames().blurEvent, false, false, document().defaultView(), 0, WTFMove(newFocusedElement)));
2341 #if ENABLE(MOUSE_FORCE_EVENTS)
2342 bool Element::dispatchMouseForceWillBegin()
2344 if (!document().hasListenerType(Document::FORCEWILLBEGIN_LISTENER))
2347 Frame* frame = document().frame();
2351 PlatformMouseEvent platformMouseEvent(frame->eventHandler().lastKnownMousePosition(), frame->eventHandler().lastKnownMouseGlobalPosition(), NoButton, PlatformEvent::NoType, 1, false, false, false, false, WTF::currentTime(), ForceAtClick);
2352 Ref<MouseEvent> mouseForceWillBeginEvent = MouseEvent::create(eventNames().webkitmouseforcewillbeginEvent, document().defaultView(), platformMouseEvent, 0, nullptr);
2353 mouseForceWillBeginEvent->setTarget(this);
2354 dispatchEvent(mouseForceWillBeginEvent);
2356 if (mouseForceWillBeginEvent->defaultHandled() || mouseForceWillBeginEvent->defaultPrevented())
2361 bool Element::dispatchMouseForceWillBegin()
2365 #endif // #if ENABLE(MOUSE_FORCE_EVENTS)
2367 void Element::mergeWithNextTextNode(Text& node, ExceptionCode& ec)
2369 Node* next = node.nextSibling();
2370 if (!is<Text>(next))
2373 Ref<Text> textNode(node);
2374 Ref<Text> textNext(downcast<Text>(*next));
2375 textNode->appendData(textNext->data());
2376 textNext->remove(ec);
2379 String Element::innerHTML() const
2381 return createMarkup(*this, ChildrenOnly);
2384 String Element::outerHTML() const
2386 return createMarkup(*this);
2389 void Element::setOuterHTML(const String& html, ExceptionCode& ec)
2391 Element* p = parentElement();
2392 if (!is<HTMLElement>(p)) {
2393 ec = NO_MODIFICATION_ALLOWED_ERR;
2396 RefPtr<HTMLElement> parent = downcast<HTMLElement>(p);
2397 RefPtr<Node> prev = previousSibling();
2398 RefPtr<Node> next = nextSibling();
2400 RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(*parent, html, AllowScriptingContent, ec);
2404 parent->replaceChild(*fragment, *this, ec);
2405 RefPtr<Node> node = next ? next->previousSibling() : nullptr;
2406 if (!ec && is<Text>(node.get()))
2407 mergeWithNextTextNode(downcast<Text>(*node), ec);
2408 if (!ec && is<Text>(prev.get()))
2409 mergeWithNextTextNode(downcast<Text>(*prev), ec);
2413 void Element::setInnerHTML(const String& html, ExceptionCode& ec)
2415 if (RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(*this, html, AllowScriptingContent, ec)) {
2416 ContainerNode* container = this;
2418 if (is<HTMLTemplateElement>(*this))
2419 container = &downcast<HTMLTemplateElement>(*this).content();
2421 replaceChildrenWithFragment(*container, fragment.releaseNonNull(), ec);
2425 String Element::innerText()
2427 // We need to update layout, since plainText uses line boxes in the render tree.
2428 document().updateLayoutIgnorePendingStylesheets();
2431 return textContent(true);
2433 return plainText(rangeOfContents(*this).ptr());
2436 String Element::outerText()
2438 // Getting outerText is the same as getting innerText, only
2439 // setting is different. You would think this should get the plain
2440 // text for the outer range, but this is wrong, <br> for instance
2441 // would return different values for inner and outer text by such
2442 // a rule, but it doesn't in WinIE, and we want to match that.
2446 String Element::title() const
2451 const AtomicString& Element::pseudo() const
2453 return fastGetAttribute(pseudoAttr);
2456 void Element::setPseudo(const AtomicString& value)
2458 setAttributeWithoutSynchronization(pseudoAttr, value);
2461 LayoutSize Element::minimumSizeForResizing() const
2463 return hasRareData() ? elementRareData()->minimumSizeForResizing() : defaultMinimumSizeForResizing();
2466 void Element::setMinimumSizeForResizing(const LayoutSize& size)
2468 if (!hasRareData() && size == defaultMinimumSizeForResizing())
2470 ensureElementRareData().setMinimumSizeForResizing(size);
2473 void Element::willBecomeFullscreenElement()
2475 for (auto& child : descendantsOfType<Element>(*this))
2476 child.ancestorWillEnterFullscreen();
2479 static PseudoElement* beforeOrAfterPseudoElement(Element& host, PseudoId pseudoElementSpecifier)
2481 switch (pseudoElementSpecifier) {
2483 return host.beforePseudoElement();
2485 return host.afterPseudoElement();
2491 const RenderStyle* Element::existingComputedStyle()
2493 if (auto* renderTreeStyle = renderStyle())
2494 return renderTreeStyle;
2497 return elementRareData()->computedStyle();
2502 const RenderStyle& Element::resolveComputedStyle()
2504 ASSERT(inDocument());
2505 ASSERT(!existingComputedStyle());
2507 Deque<Element*, 32> elementsRequiringComputedStyle({ this });
2508 const RenderStyle* computedStyle = nullptr;
2510 // Collect ancestors until we find one that has style.
2511 auto composedAncestors = composedTreeAncestors(*this);
2512 for (auto& ancestor : composedAncestors) {
2513 elementsRequiringComputedStyle.prepend(&ancestor);
2514 if (auto* existingStyle = ancestor.existingComputedStyle()) {
2515 computedStyle = existingStyle;
2520 // Resolve and cache styles starting from the most distant ancestor.
2521 for (auto* element : elementsRequiringComputedStyle) {
2522 auto style = document().styleForElementIgnoringPendingStylesheets(*element, computedStyle);
2523 computedStyle = style.get();
2524 ElementRareData& rareData = element->ensureElementRareData();
2525 rareData.setComputedStyle(WTFMove(style));
2528 return *computedStyle;
2531 const RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
2533 if (PseudoElement* pseudoElement = beforeOrAfterPseudoElement(*this, pseudoElementSpecifier))
2534 return pseudoElement->computedStyle();
2536 auto* style = existingComputedStyle();
2540 style = &resolveComputedStyle();
2543 if (pseudoElementSpecifier) {
2544 if (auto* cachedPseudoStyle = style->getCachedPseudoStyle(pseudoElementSpecifier))
2545 return cachedPseudoStyle;
2551 bool Element::needsStyleInvalidation() const
2553 if (!inRenderedDocument())
2555 if (styleChangeType() >= FullStyleChange)
2557 if (document().hasPendingForcedStyleRecalc())
2563 void Element::setStyleAffectedByEmpty()
2565 ensureElementRareData().setStyleAffectedByEmpty(true);
2568 void Element::setChildrenAffectedByActive()
2570 ensureElementRareData().setChildrenAffectedByActive(true);
2573 void Element::setChildrenAffectedByDrag()
2575 ensureElementRareData().setChildrenAffectedByDrag(true);
2578 void Element::setChildrenAffectedByBackwardPositionalRules()
2580 ensureElementRareData().setChildrenAffectedByBackwardPositionalRules(true);
2583 void Element::setChildrenAffectedByPropertyBasedBackwardPositionalRules()
2585 ensureElementRareData().setChildrenAffectedByPropertyBasedBackwardPositionalRules(true);
2588 void Element::setChildIndex(unsigned index)
2590 ElementRareData& rareData = ensureElementRareData();
2591 rareData.setChildIndex(index);
2594 bool Element::hasFlagsSetDuringStylingOfChildren() const
2596 if (childrenAffectedByHover() || childrenAffectedByFirstChildRules() || childrenAffectedByLastChildRules())
2601 return rareDataChildrenAffectedByActive()
2602 || rareDataChildrenAffectedByDrag()
2603 || rareDataChildrenAffectedByBackwardPositionalRules()
2604 || rareDataChildrenAffectedByPropertyBasedBackwardPositionalRules();
2607 bool Element::rareDataStyleAffectedByEmpty() const
2609 ASSERT(hasRareData());
2610 return elementRareData()->styleAffectedByEmpty();
2613 bool Element::rareDataChildrenAffectedByActive() const
2615 ASSERT(hasRareData());
2616 return elementRareData()->childrenAffectedByActive();
2619 bool Element::rareDataChildrenAffectedByDrag() const
2621 ASSERT(hasRareData());
2622 return elementRareData()->childrenAffectedByDrag();
2625 bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
2627 ASSERT(hasRareData());
2628 return elementRareData()->childrenAffectedByBackwardPositionalRules();
2631 bool Element::rareDataChildrenAffectedByPropertyBasedBackwardPositionalRules() const
2633 ASSERT(hasRareData());
2634 return elementRareData()->childrenAffectedByPropertyBasedBackwardPositionalRules();
2637 unsigned Element::rareDataChildIndex() const
2639 ASSERT(hasRareData());
2640 return elementRareData()->childIndex();
2643 void Element::setRegionOversetState(RegionOversetState state)
2645 ensureElementRareData().setRegionOversetState(state);
2648 RegionOversetState Element::regionOversetState() const
2650 return hasRareData() ? elementRareData()->regionOversetState() : RegionUndefined;
2653 AtomicString Element::computeInheritedLanguage() const
2655 if (const ElementData* elementData = this->elementData()) {
2656 if (const Attribute* attribute = elementData->findLanguageAttribute())
2657 return attribute->value();
2660 // The language property is inherited, so we iterate over the parents to find the first language.
2661 const Node* currentNode = this;
2662 while ((currentNode = currentNode->parentNode())) {
2663 if (is<Element>(*currentNode)) {
2664 if (const ElementData* elementData = downcast<Element>(*currentNode).elementData()) {
2665 if (const Attribute* attribute = elementData->findLanguageAttribute())
2666 return attribute->value();
2668 } else if (is<Document>(*currentNode)) {
2669 // checking the MIME content-language
2670 return downcast<Document>(*currentNode).contentLanguage();
2677 Locale& Element::locale() const
2679 return document().getCachedLocale(computeInheritedLanguage());
2682 void Element::cancelFocusAppearanceUpdate()
2685 elementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
2686 if (document().focusedElement() == this)
2687 document().cancelFocusAppearanceUpdate();
2690 void Element::normalizeAttributes()
2692 if (!hasAttributes())
2695 auto* attrNodeList = attrNodeListForElement(*this);
2699 // Copy the Attr Vector because Node::normalize() can fire synchronous JS
2700 // events (e.g. DOMSubtreeModified) and a JS listener could add / remove
2701 // attributes while we are iterating.
2702 auto copyOfAttrNodeList = *attrNodeList;
2703 for (auto& attrNode : copyOfAttrNodeList)
2704 attrNode->normalize();
2707 PseudoElement* Element::beforePseudoElement() const
2709 return hasRareData() ? elementRareData()->beforePseudoElement() : nullptr;
2712 PseudoElement* Element::afterPseudoElement() const
2714 return hasRareData() ? elementRareData()->afterPseudoElement() : nullptr;
2717 void Element::setBeforePseudoElement(Ref<PseudoElement>&& element)
2719 ensureElementRareData().setBeforePseudoElement(WTFMove(element));
2722 void Element::setAfterPseudoElement(Ref<PseudoElement>&& element)
2724 ensureElementRareData().setAfterPseudoElement(WTFMove(element));
2727 static void disconnectPseudoElement(PseudoElement* pseudoElement)
2731 if (pseudoElement->renderer())
2732 RenderTreeUpdater::tearDownRenderers(*pseudoElement);
2733 ASSERT(pseudoElement->hostElement());
2734 pseudoElement->clearHostElement();
2737 void Element::clearBeforePseudoElement()
2741 disconnectPseudoElement(elementRareData()->beforePseudoElement());
2742 elementRareData()->setBeforePseudoElement(nullptr);
2745 void Element::clearAfterPseudoElement()
2749 disconnectPseudoElement(elementRareData()->afterPseudoElement());
2750 elementRareData()->setAfterPseudoElement(nullptr);
2753 bool Element::matchesValidPseudoClass() const
2758 bool Element::matchesInvalidPseudoClass() const
2763 bool Element::matchesReadWritePseudoClass() const
2768 bool Element::matchesIndeterminatePseudoClass() const
2770 return shouldAppearIndeterminate();
2773 bool Element::matchesDefaultPseudoClass() const
2778 bool Element::matches(const String& selector, ExceptionCode& ec)
2780 SelectorQuery* selectorQuery = document().selectorQueryForString(selector, ec);
2781 return selectorQuery && selectorQuery->matches(*this);
2784 Element* Element::closest(const String& selector, ExceptionCode& ec)
2786 SelectorQuery* selectorQuery = document().selectorQueryForString(selector, ec);
2788 return selectorQuery->closest(*this);
2792 bool Element::shouldAppearIndeterminate() const
2797 bool Element::mayCauseRepaintInsideViewport(const IntRect* visibleRect) const
2799 return renderer() && renderer()->mayCauseRepaintInsideViewport(visibleRect);
2802 DOMTokenList& Element::classList()
2804 ElementRareData& data = ensureElementRareData();
2805 if (!data.classList())
2806 data.setClassList(std::make_unique<DOMTokenList>(*this, HTMLNames::classAttr));
2807 return *data.classList();
2810 DatasetDOMStringMap& Element::dataset()
2812 ElementRareData& data = ensureElementRareData();
2813 if (!data.dataset())
2814 data.setDataset(std::make_unique<DatasetDOMStringMap>(*this));
2815 return *data.dataset();
2818 URL Element::getURLAttribute(const QualifiedName& name) const
2820 #if !ASSERT_DISABLED
2821 if (elementData()) {
2822 if (const Attribute* attribute = findAttributeByName(name))
2823 ASSERT(isURLAttribute(*attribute));
2826 return document().completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
2829 URL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
2831 #if !ASSERT_DISABLED
2832 if (elementData()) {
2833 if (const Attribute* attribute = findAttributeByName(name))
2834 ASSERT(isURLAttribute(*attribute));
2837 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
2838 if (value.isEmpty())
2840 return document().completeURL(value);
2843 int Element::getIntegralAttribute(const QualifiedName& attributeName) const
2845 return parseHTMLInteger(getAttribute(attributeName)).valueOr(0);
2848 void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
2850 setAttribute(attributeName, AtomicString::number(value));
2853 unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
2855 return parseHTMLNonNegativeInteger(getAttribute(attributeName)).valueOr(0);
2858 void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
2860 setAttribute(attributeName, AtomicString::number(limitToOnlyHTMLNonNegative(value)));
2863 #if ENABLE(INDIE_UI)
2864 void Element::setUIActions(const AtomicString& actions)
2866 setAttribute(uiactionsAttr, actions);
2869 const AtomicString& Element::UIActions() const
2871 return getAttribute(uiactionsAttr);
2875 bool Element::childShouldCreateRenderer(const Node& child) const
2877 // Only create renderers for SVG elements whose parents are SVG elements, or for proper <svg xmlns="svgNS"> subdocuments.
2878 if (child.isSVGElement()) {
2879 ASSERT(!isSVGElement());
2880 const SVGElement& childElement = downcast<SVGElement>(child);
2881 return is<SVGSVGElement>(childElement) && childElement.isValid();
2886 #if ENABLE(FULLSCREEN_API)
2887 void Element::webkitRequestFullscreen()
2889 document().requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, Document::EnforceIFrameAllowFullScreenRequirement);
2892 void Element::webkitRequestFullScreen(unsigned short flags)
2894 document().requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), Document::EnforceIFrameAllowFullScreenRequirement);
2897 bool Element::containsFullScreenElement() const
2899 return hasRareData() && elementRareData()->containsFullScreenElement();
2902 void Element::setContainsFullScreenElement(bool flag)
2904 ensureElementRareData().setContainsFullScreenElement(flag);
2905 setNeedsStyleRecalc(SyntheticStyleChange);
2908 static Element* parentCrossingFrameBoundaries(Element* element)
2911 return element->parentElement() ? element->parentElement() : element->document().ownerElement();
2914 void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool flag)
2916 Element* element = this;
2917 while ((element = parentCrossingFrameBoundaries(element)))
2918 element->setContainsFullScreenElement(flag);
2922 #if ENABLE(POINTER_LOCK)
2923 void Element::requestPointerLock()
2925 if (document().page())
2926 document().page()->pointerLockController().requestPointerLock(this);
2930 SpellcheckAttributeState Element::spellcheckAttributeState() const
2932 const AtomicString& value = fastGetAttribute(HTMLNames::spellcheckAttr);
2934 return SpellcheckAttributeDefault;
2935 if (value.isEmpty() || equalLettersIgnoringASCIICase(value, "true"))
2936 return SpellcheckAttributeTrue;
2937 if (equalLettersIgnoringASCIICase(value, "false"))
2938 return SpellcheckAttributeFalse;
2939 return SpellcheckAttributeDefault;
2942 bool Element::isSpellCheckingEnabled() const
2944 for (const Element* element = this; element; element = element->parentOrShadowHostElement()) {
2945 switch (element->spellcheckAttributeState()) {
2946 case SpellcheckAttributeTrue:
2948 case SpellcheckAttributeFalse:
2950 case SpellcheckAttributeDefault:
2958 RenderNamedFlowFragment* Element::renderNamedFlowFragment() const
2960 if (renderer() && renderer()->isRenderNamedFlowFragmentContainer())
2961 return downcast<RenderBlockFlow>(*renderer()).renderNamedFlowFragment();
2966 #if ENABLE(CSS_REGIONS)
2968 bool Element::shouldMoveToFlowThread(const RenderStyle& styleToUse) const
2970 #if ENABLE(FULLSCREEN_API)
2971 if (document().webkitIsFullScreen() && document().webkitCurrentFullScreenElement() == this)
2975 if (isInShadowTree())
2978 if (!styleToUse.hasFlowInto())
2984 const AtomicString& Element::webkitRegionOverset() const
2986 document().updateLayoutIgnorePendingStylesheets();
2988 static NeverDestroyed<AtomicString> undefinedState("undefined", AtomicString::ConstructFromLiteral);
2989 if (!renderNamedFlowFragment())
2990 return undefinedState;
2992 switch (regionOversetState()) {
2994 static NeverDestroyed<AtomicString> fitState("fit", AtomicString::ConstructFromLiteral);
2998 static NeverDestroyed<AtomicString> emptyState("empty", AtomicString::ConstructFromLiteral);
3001 case RegionOverset: {
3002 static NeverDestroyed<AtomicString> overflowState("overset", AtomicString::ConstructFromLiteral);
3003 return overflowState;
3005 case RegionUndefined:
3006 return undefinedState;
3009 ASSERT_NOT_REACHED();
3010 return undefinedState;
3013 Vector<RefPtr<Range>> Element::webkitGetRegionFlowRanges() const
3015 Vector<RefPtr<Range>> rangeObjects;
3016 document().updateLayoutIgnorePendingStylesheets();
3017 auto* renderer = this->renderer();
3018 if (renderer && renderer->isRenderNamedFlowFragmentContainer()) {
3019 auto& namedFlowFragment = *downcast<RenderBlockFlow>(*renderer).renderNamedFlowFragment();
3020 if (namedFlowFragment.isValid())
3021 namedFlowFragment.getRanges(rangeObjects);
3023 return rangeObjects;
3029 bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
3031 if (name == HTMLNames::styleAttr)
3035 return !downcast<SVGElement>(*this).isAnimatableAttribute(name);
3041 #ifdef DUMP_NODE_STATISTICS
3042 bool Element::hasNamedNodeMap() const
3044 return hasRareData() && elementRareData()->attributeMap();
3048 inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName)
3050 if (!isInTreeScope())
3053 if (oldName == newName)
3056 updateNameForTreeScope(treeScope(), oldName, newName);
3060 if (!is<HTMLDocument>(document()))
3062 updateNameForDocument(downcast<HTMLDocument>(document()), oldName, newName);
3065 void Element::updateNameForTreeScope(TreeScope& scope, const AtomicString& oldName, const AtomicString& newName)
3067 ASSERT(oldName != newName);
3069 if (!oldName.isEmpty())
3070 scope.removeElementByName(*oldName.impl(), *this);
3071 if (!newName.isEmpty())
3072 scope.addElementByName(*newName.impl(), *this);
3075 void Element::updateNameForDocument(HTMLDocument& document, const AtomicString& oldName, const AtomicString& newName)
3077 ASSERT(oldName != newName);
3079 if (WindowNameCollection::elementMatchesIfNameAttributeMatch(*this)) {
3080 const AtomicString& id = WindowNameCollection::elementMatchesIfIdAttributeMatch(*this) ? getIdAttribute() : nullAtom;
3081 if (!oldName.isEmpty() && oldName != id)
3082 document.removeWindowNamedItem(*oldName.impl(), *this);
3083 if (!newName.isEmpty() && newName != id)
3084 document.addWindowNamedItem(*newName.impl(), *this);
3087 if (DocumentNameCollection::elementMatchesIfNameAttributeMatch(*this)) {
3088 const AtomicString& id = DocumentNameCollection::elementMatchesIfIdAttributeMatch(*this) ? getIdAttribute() : nullAtom;
3089 if (!oldName.isEmpty() && oldName != id)
3090 document.removeDocumentNamedItem(*oldName.impl(), *this);
3091 if (!newName.isEmpty() && newName != id)
3092 document.addDocumentNamedItem(*newName.impl(), *this);
3096 inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId, NotifyObservers notifyObservers)
3098 if (!isInTreeScope())
3104 updateIdForTreeScope(treeScope(), oldId, newId, notifyObservers);
3108 if (!is<HTMLDocument>(document()))
3110 updateIdForDocument(downcast<HTMLDocument>(document()), oldId, newId, UpdateHTMLDocumentNamedItemMapsOnlyIfDiffersFromNameAttribute);
3113 void Element::updateIdForTreeScope(TreeScope& scope, const AtomicString& oldId, const AtomicString& newId, NotifyObservers notifyObservers)
3115 ASSERT(isInTreeScope());
3116 ASSERT(oldId != newId);
3118 if (!oldId.isEmpty())
3119 scope.removeElementById(*oldId.impl(), *this, notifyObservers == NotifyObservers::Yes);
3120 if (!newId.isEmpty())
3121 scope.addElementById(*newId.impl(), *this, notifyObservers == NotifyObservers::Yes);
3124 void Element::updateIdForDocument(HTMLDocument& document, const AtomicString& oldId, const AtomicString& newId, HTMLDocumentNamedItemMapsUpdatingCondition condition)
3126 ASSERT(inDocument());
3127 ASSERT(oldId != newId);
3129 if (WindowNameCollection::elementMatchesIfIdAttributeMatch(*this)) {
3130 const AtomicString& name = condition == UpdateHTMLDocumentNamedItemMapsOnlyIfDiffersFromNameAttribute && WindowNameCollection::elementMatchesIfNameAttributeMatch(*this) ? getNameAttribute() : nullAtom;
3131 if (!oldId.isEmpty() && oldId != name)
3132 document.removeWindowNamedItem(*oldId.impl(), *this);
3133 if (!newId.isEmpty() && newId != name)
3134 document.addWindowNamedItem(*newId.impl(), *this);
3137 if (DocumentNameCollection::elementMatchesIfIdAttributeMatch(*this)) {
3138 const AtomicString& name = condition == UpdateHTMLDocumentNamedItemMapsOnlyIfDiffersFromNameAttribute && DocumentNameCollection::elementMatchesIfNameAttributeMatch(*this) ? getNameAttribute() : nullAtom;
3139 if (!oldId.isEmpty() && oldId != name)
3140 document.removeDocumentNamedItem(*oldId.impl(), *this);
3141 if (!newId.isEmpty() && newId != name)
3142 document.addDocumentNamedItem(*newId.impl(), *this);
3146 void Element::updateLabel(TreeScope& scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
3148 ASSERT(hasTagName(labelTag));
3153 if (oldForAttributeValue == newForAttributeValue)
3156 if (!oldForAttributeValue.isEmpty())
3157 scope.removeLabel(*oldForAttributeValue.impl(), downcast<HTMLLabelElement>(*this));
3158 if (!newForAttributeValue.isEmpty())
3159 scope.addLabel(*newForAttributeValue.impl(), downcast<HTMLLabelElement>(*this));
3162 void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
3164 if (name == HTMLNames::idAttr)
3165 updateId(oldValue, newValue, NotifyObservers::No); // Will notify observers after the attribute is actually changed.
3166 else if (name == HTMLNames::nameAttr)
3167 updateName(oldValue, newValue);
3168 else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
3169 if (treeScope().shouldCacheLabelsByForAttribute())
3170 updateLabel(treeScope(), oldValue, newValue);
3173 if (std::unique_ptr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(*this, name))
3174 recipients->enqueueMutationRecord(MutationRecord::createAttributes(*this, name, oldValue));
3176 InspectorInstrumentation::willModifyDOMAttr(document(), *this, oldValue, newValue);
3179 void Element::didAddAttribute(const QualifiedName& name, const AtomicString& value)
3181 attributeChanged(name, nullAtom, value);
3182 InspectorInstrumentation::didModifyDOMAttr(document(), *this, name.localName(), value);
3183 dispatchSubtreeModifiedEvent();
3186 void Element::didModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
3188 attributeChanged(name, oldValue, newValue);
3189 InspectorInstrumentation::didModifyDOMAttr(document(), *this, name.localName(), newValue);
3190 // Do not dispatch a DOMSubtreeModified event here; see bug 81141.
3193 void Element::didRemoveAttribute(const QualifiedName& name, const AtomicString& oldValue)
3195 attributeChanged(name, oldValue, nullAtom);
3196 InspectorInstrumentation::didRemoveDOMAttr(document(), *this, name.localName());
3197 dispatchSubtreeModifiedEvent();
3200 IntPoint Element::savedLayerScrollPosition() const
3202 return hasRareData() ? elementRareData()->savedLayerScrollPosition() : IntPoint();
3205 void Element::setSavedLayerScrollPosition(const IntPoint& position)
3207 if (position.isZero() && !hasRareData())
3209 ensureElementRareData().setSavedLayerScrollPosition(position);
3212 RefPtr<Attr> Element::attrIfExists(const AtomicString& localName, bool shouldIgnoreAttributeCase)
3214 if (auto* attrNodeList = attrNodeListForElement(*this))
3215 return findAttrNodeInList(*attrNodeList, localName, shouldIgnoreAttributeCase);
3219 RefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
3221 if (auto* attrNodeList = attrNodeListForElement(*this))
3222 return findAttrNodeInList(*attrNodeList, name);
3226 Ref<Attr> Element::ensureAttr(const QualifiedName& name)
3228 auto& attrNodeList = ensureAttrNodeListForElement(*this);
3229 RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
3231 attrNode = Attr::create(this, name);
3232 treeScope().adoptIfNeeded(attrNode.get());
3233 attrNodeList.append(attrNode);
3235 return attrNode.releaseNonNull();
3238 void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value)
3240 ASSERT(hasSyntheticAttrChildNodes());
3241 attrNode->detachFromElementWithValue(value);
3243 auto& attrNodeList = *attrNodeListForElement(*this);
3244 bool found = attrNodeList.removeFirstMatching([attrNode](auto& attribute) {
3245 return attribute->qualifiedName() == attrNode->qualifiedName();
3247 ASSERT_UNUSED(found, found);
3248 if (attrNodeList.isEmpty())
3249 removeAttrNodeListForElement(*this);
3252 void Element::detachAllAttrNodesFromElement()
3254 auto* attrNodeList = attrNodeListForElement(*this);
3255 ASSERT(attrNodeList);
3257 for (const Attribute& attribute : attributesIterator()) {
3258 if (RefPtr<Attr> attrNode = findAttrNodeInList(*attrNodeList, attribute.name()))
3259 attrNode->detachFromElementWithValue(attribute.value());
3262 removeAttrNodeListForElement(*this);
3265 void Element::resetComputedStyle()
3267 if (!hasRareData() || !elementRareData()->computedStyle())
3270 auto reset = [](Element& element) {
3271 if (!element.hasRareData() || !element.elementRareData()->computedStyle())
3273 if (element.hasCustomStyleResolveCallbacks())
3274 element.willResetComputedStyle();
3275 element.elementRareData()->resetComputedStyle();
3278 for (auto& child : descendantsOfType<Element>(*this))
3282 void Element::clearStyleDerivedDataBeforeDetachingRenderer()
3284 unregisterNamedFlowContentElement();
3285 cancelFocusAppearanceUpdate();
3286 clearBeforePseudoElement();
3287 clearAfterPseudoElement();
3290 ElementRareData* data = elementRareData();
3291 data->resetComputedStyle();
3292 data->resetDynamicRestyleObservations();
3295 void Element::clearHoverAndActiveStatusBeforeDetachingRenderer()
3297 if (!isUserActionElement())
3300 document().hoveredElementDidDetach(this);
3301 if (inActiveChain())
3302 document().elementInActiveChainDidDetach(this);
3303 document().userActionElements().didDetach(this);
3306 bool Element::willRecalcStyle(Style::Change)
3308 ASSERT(hasCustomStyleResolveCallbacks());
3312 void Element::didRecalcStyle(Style::Change)
3314 ASSERT(hasCustomStyleResolveCallbacks());
3317 void Element::willResetComputedStyle()
3319 ASSERT(hasCustomStyleResolveCallbacks());
3322 void Element::willAttachRenderers()
3324 ASSERT(hasCustomStyleResolveCallbacks());
3327 void Element::didAttachRenderers()
3329 ASSERT(hasCustomStyleResolveCallbacks());
3332 void Element::willDetachRenderers()
3334 ASSERT(hasCustomStyleResolveCallbacks());
3337 void Element::didDetachRenderers()
3339 ASSERT(hasCustomStyleResolveCallbacks());
3342 Optional<ElementStyle> Element::resolveCustomStyle(const RenderStyle&, const RenderStyle*)
3344 ASSERT(hasCustomStyleResolveCallbacks());
3348 void Element::cloneAttributesFromElement(const Element& other)
3350 if (hasSyntheticAttrChildNodes())
3351 detachAllAttrNodesFromElement();
3353 other.synchronizeAllAttributes();
3354 if (!other.m_elementData) {
3355 m_elementData = nullptr;
3359 // 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.
3360 // Fortunately, those named item maps are only updated when this element is in the document, which should never be the case.
3361 ASSERT(!inDocument());
3363 const AtomicString& oldID = getIdAttribute();
3364 const AtomicString& newID = other.getIdAttribute();
3366 if (!oldID.isNull() || !newID.isNull())
3367 updateId(oldID, newID, NotifyObservers::No); // Will notify observers after the attribute is actually changed.
3369 const AtomicString& oldName = getNameAttribute();
3370 const AtomicString& newName = other.getNameAttribute();
3372 if (!oldName.isNull() || !newName.isNull())
3373 updateName(oldName, newName);
3375 // If 'other' has a mutable ElementData, convert it to an immutable one so we can share it between both elements.
3376 // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes.
3377 if (is<UniqueElementData>(*other.m_elementData)
3378 && !other.m_elementData->presentationAttributeStyle()
3379 && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper()))
3380 const_cast<Element&>(other).m_elementData = downcast<UniqueElementData>(*other.m_elementData).makeShareableCopy();
3382 if (!other.m_elementData->isUnique())
3383 m_elementData = other.m_elementData;
3385 m_elementData = other.m_elementData->makeUniqueCopy();
3387 for (const Attribute& attribute : attributesIterator())
3388 attributeChanged(attribute.name(), nullAtom, attribute.value(), ModifiedByCloning);
3391 void Element::cloneDataFromElement(const Element& other)
3393 cloneAttributesFromElement(other);
3394 copyNonAttributePropertiesFromElement(other);
3397 void Element::createUniqueElementData()
3400 m_elementData = UniqueElementData::create();
3402 m_elementData = downcast<ShareableElementData>(*m_elementData).makeUniqueCopy();
3405 bool Element::hasPendingResources() const
3407 return hasRareData() && elementRareData()->hasPendingResources();
3410 void Element::setHasPendingResources()
3412 ensureElementRareData().setHasPendingResources(true);
3415 void Element::clearHasPendingResources()
3417 ensureElementRareData().setHasPendingResources(false);
3420 bool Element::canContainRangeEndPoint() const
3422 return !equalLettersIgnoringASCIICase(fastGetAttribute(roleAttr), "img");
3425 String Element::completeURLsInAttributeValue(const URL& base, const Attribute& attribute) const
3427 return URL(base, attribute.value()).string();
3430 } // namespace WebCore