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, 2005, 2006, 2007, 2008, 2009, 2010, 2012 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 "CSSParser.h"
32 #include "CSSSelectorList.h"
33 #include "ClassList.h"
34 #include "ClientRect.h"
35 #include "ClientRectList.h"
36 #include "DOMTokenList.h"
37 #include "DatasetDOMStringMap.h"
39 #include "DocumentFragment.h"
40 #include "ElementRareData.h"
41 #include "ExceptionCode.h"
42 #include "FlowThreadController.h"
43 #include "FocusController.h"
45 #include "FrameView.h"
46 #include "HTMLCollection.h"
47 #include "HTMLDocument.h"
48 #include "HTMLElement.h"
49 #include "HTMLFormControlsCollection.h"
50 #include "HTMLFrameOwnerElement.h"
51 #include "HTMLLabelElement.h"
52 #include "HTMLNames.h"
53 #include "HTMLOptionsCollection.h"
54 #include "HTMLParserIdioms.h"
55 #include "HTMLTableRowsCollection.h"
56 #include "InsertionPoint.h"
57 #include "InspectorInstrumentation.h"
58 #include "MutationObserverInterestGroup.h"
59 #include "MutationRecord.h"
60 #include "NamedNodeMap.h"
62 #include "NodeRenderStyle.h"
63 #include "NodeRenderingContext.h"
65 #include "PointerLockController.h"
66 #include "RenderRegion.h"
67 #include "RenderView.h"
68 #include "RenderWidget.h"
69 #include "SelectorQuery.h"
71 #include "ShadowRoot.h"
72 #include "StyleResolver.h"
74 #include "TextIterator.h"
75 #include "VoidCallback.h"
76 #include "WebCoreMemoryInstrumentation.h"
77 #include "WebKitAnimationList.h"
78 #include "XMLNSNames.h"
80 #include "htmlediting.h"
81 #include <wtf/BitVector.h>
82 #include <wtf/text/CString.h>
85 #include "SVGElement.h"
91 using namespace HTMLNames;
92 using namespace XMLNames;
94 class StyleResolverParentPusher {
96 StyleResolverParentPusher(Element* parent)
98 , m_pushedStyleResolver(0)
103 if (m_pushedStyleResolver)
105 m_pushedStyleResolver = m_parent->document()->styleResolver();
106 m_pushedStyleResolver->pushParentElement(m_parent);
108 ~StyleResolverParentPusher()
111 if (!m_pushedStyleResolver)
114 // This tells us that our pushed style selector is in a bad state,
115 // so we should just bail out in that scenario.
116 ASSERT(m_pushedStyleResolver == m_parent->document()->styleResolver());
117 if (m_pushedStyleResolver != m_parent->document()->styleResolver())
120 m_pushedStyleResolver->popParentElement(m_parent);
125 StyleResolver* m_pushedStyleResolver;
128 typedef Vector<RefPtr<Attr> > AttrNodeList;
129 typedef HashMap<Element*, OwnPtr<AttrNodeList> > AttrNodeListMap;
131 static AttrNodeListMap& attrNodeListMap()
133 DEFINE_STATIC_LOCAL(AttrNodeListMap, map, ());
137 static AttrNodeList* attrNodeListForElement(Element* element)
139 if (!element->hasSyntheticAttrChildNodes())
141 ASSERT(attrNodeListMap().contains(element));
142 return attrNodeListMap().get(element);
145 static AttrNodeList* ensureAttrNodeListForElement(Element* element)
147 if (element->hasSyntheticAttrChildNodes()) {
148 ASSERT(attrNodeListMap().contains(element));
149 return attrNodeListMap().get(element);
151 ASSERT(!attrNodeListMap().contains(element));
152 element->setHasSyntheticAttrChildNodes(true);
153 AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList));
154 return result.iterator->value.get();
157 static void removeAttrNodeListForElement(Element* element)
159 ASSERT(element->hasSyntheticAttrChildNodes());
160 ASSERT(attrNodeListMap().contains(element));
161 attrNodeListMap().remove(element);
162 element->setHasSyntheticAttrChildNodes(false);
165 static Attr* findAttrNodeInList(AttrNodeList* attrNodeList, const QualifiedName& name)
167 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
168 if (attrNodeList->at(i)->qualifiedName() == name)
169 return attrNodeList->at(i).get();
174 PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document)
176 return adoptRef(new Element(tagName, document, CreateElement));
182 if (document() && document()->renderer()) {
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 inNamedFlow flag reset.
186 ASSERT(!inNamedFlow());
190 if (ElementShadow* elementShadow = shadow()) {
191 elementShadow->removeAllShadowRoots();
192 elementRareData()->m_shadow.clear();
195 if (hasSyntheticAttrChildNodes())
196 detachAllAttrNodesFromElement();
199 inline ElementRareData* Element::elementRareData() const
201 ASSERT(hasRareData());
202 return static_cast<ElementRareData*>(rareData());
205 inline ElementRareData* Element::ensureElementRareData()
207 return static_cast<ElementRareData*>(ensureRareData());
210 OwnPtr<NodeRareData> Element::createRareData()
212 return adoptPtr(new ElementRareData(documentInternal()));
215 DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, blur);
216 DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, error);
217 DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, focus);
218 DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, load);
220 PassRefPtr<Node> Element::cloneNode(bool deep)
222 return deep ? cloneElementWithChildren() : cloneElementWithoutChildren();
225 PassRefPtr<Element> Element::cloneElementWithChildren()
227 RefPtr<Element> clone = cloneElementWithoutChildren();
228 cloneChildNodes(clone.get());
229 return clone.release();
232 PassRefPtr<Element> Element::cloneElementWithoutChildren()
234 RefPtr<Element> clone = cloneElementWithoutAttributesAndChildren();
235 // This will catch HTML elements in the wrong namespace that are not correctly copied.
236 // This is a sanity check as HTML overloads some of the DOM methods.
237 ASSERT(isHTMLElement() == clone->isHTMLElement());
239 clone->cloneDataFromElement(*this);
240 return clone.release();
243 PassRefPtr<Element> Element::cloneElementWithoutAttributesAndChildren()
245 return document()->createElement(tagQName(), false);
248 PassRefPtr<Attr> Element::detachAttribute(size_t index)
250 ASSERT(attributeData());
252 const Attribute* attribute = attributeData()->attributeItem(index);
255 RefPtr<Attr> attrNode = attrIfExists(attribute->name());
257 detachAttrNodeFromElementWithValue(attrNode.get(), attribute->value());
259 attrNode = Attr::create(document(), attribute->name(), attribute->value());
261 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
262 return attrNode.release();
265 void Element::removeAttribute(const QualifiedName& name)
267 if (!attributeData())
270 size_t index = attributeData()->getAttributeItemIndex(name);
271 if (index == notFound)
274 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
277 void Element::setBooleanAttribute(const QualifiedName& name, bool value)
280 setAttribute(name, emptyAtom);
282 removeAttribute(name);
285 NamedNodeMap* Element::attributes() const
287 ensureUpdatedAttributeData();
288 ElementRareData* rareData = const_cast<Element*>(this)->ensureElementRareData();
289 if (NamedNodeMap* attributeMap = rareData->m_attributeMap.get())
292 rareData->m_attributeMap = NamedNodeMap::create(const_cast<Element*>(this));
293 return rareData->m_attributeMap.get();
296 Node::NodeType Element::nodeType() const
301 bool Element::hasAttribute(const QualifiedName& name) const
303 return hasAttributeNS(name.namespaceURI(), name.localName());
306 const AtomicString& Element::getAttribute(const QualifiedName& name) const
308 if (!attributeData())
311 if (UNLIKELY(name == styleAttr && attributeData()->m_styleAttributeIsDirty))
312 updateStyleAttribute();
315 if (UNLIKELY(attributeData()->m_animatedSVGAttributesAreDirty))
316 updateAnimatedSVGAttribute(name);
319 if (const Attribute* attribute = getAttributeItem(name))
320 return attribute->value();
324 void Element::scrollIntoView(bool alignToTop)
326 document()->updateLayoutIgnorePendingStylesheets();
331 LayoutRect bounds = boundingBox();
332 // Align to the top / bottom and to the closest edge.
334 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
336 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
339 void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
341 document()->updateLayoutIgnorePendingStylesheets();
346 LayoutRect bounds = boundingBox();
348 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
350 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
353 void Element::scrollByUnits(int units, ScrollGranularity granularity)
355 document()->updateLayoutIgnorePendingStylesheets();
360 if (!renderer()->hasOverflowClip())
363 ScrollDirection direction = ScrollDown;
365 direction = ScrollUp;
368 Node* stopNode = this;
369 toRenderBox(renderer())->scroll(direction, granularity, units, &stopNode);
372 void Element::scrollByLines(int lines)
374 scrollByUnits(lines, ScrollByLine);
377 void Element::scrollByPages(int pages)
379 scrollByUnits(pages, ScrollByPage);
382 static float localZoomForRenderer(RenderObject* renderer)
384 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
385 // other out, but the alternative is that we'd have to crawl up the whole render tree every
386 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
387 float zoomFactor = 1;
388 if (renderer->style()->effectiveZoom() != 1) {
389 // Need to find the nearest enclosing RenderObject that set up
390 // a differing zoom, and then we divide our result by it to eliminate the zoom.
391 RenderObject* prev = renderer;
392 for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) {
393 if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) {
394 zoomFactor = prev->style()->zoom();
399 if (prev->isRenderView())
400 zoomFactor = prev->style()->zoom();
405 static int adjustForLocalZoom(LayoutUnit value, RenderObject* renderer)
407 float zoomFactor = localZoomForRenderer(renderer);
410 #if ENABLE(SUBPIXEL_LAYOUT)
411 return lroundf(value / zoomFactor);
413 // Needed because computeLengthInt truncates (rather than rounds) when scaling up.
416 return static_cast<int>(value / zoomFactor);
420 int Element::offsetLeft()
422 document()->updateLayoutIgnorePendingStylesheets();
423 if (RenderBoxModelObject* renderer = renderBoxModelObject())
424 return adjustForLocalZoom(renderer->pixelSnappedOffsetLeft(), renderer);
428 int Element::offsetTop()
430 document()->updateLayoutIgnorePendingStylesheets();
431 if (RenderBoxModelObject* renderer = renderBoxModelObject())
432 return adjustForLocalZoom(renderer->pixelSnappedOffsetTop(), renderer);
436 int Element::offsetWidth()
438 document()->updateLayoutIgnorePendingStylesheets();
439 if (RenderBoxModelObject* renderer = renderBoxModelObject())
440 return adjustForAbsoluteZoom(renderer->pixelSnappedOffsetWidth(), renderer);
444 int Element::offsetHeight()
446 document()->updateLayoutIgnorePendingStylesheets();
447 if (RenderBoxModelObject* renderer = renderBoxModelObject())
448 return adjustForAbsoluteZoom(renderer->pixelSnappedOffsetHeight(), renderer);
452 Element* Element::offsetParent()
454 document()->updateLayoutIgnorePendingStylesheets();
455 if (RenderObject* rend = renderer())
456 if (RenderObject* offsetParent = rend->offsetParent())
457 return static_cast<Element*>(offsetParent->node());
461 int Element::clientLeft()
463 document()->updateLayoutIgnorePendingStylesheets();
465 if (RenderBox* renderer = renderBox())
466 return adjustForAbsoluteZoom(roundToInt(renderer->clientLeft()), renderer);
470 int Element::clientTop()
472 document()->updateLayoutIgnorePendingStylesheets();
474 if (RenderBox* renderer = renderBox())
475 return adjustForAbsoluteZoom(roundToInt(renderer->clientTop()), renderer);
479 int Element::clientWidth()
481 document()->updateLayoutIgnorePendingStylesheets();
483 // When in strict mode, clientWidth for the document element should return the width of the containing frame.
484 // When in quirks mode, clientWidth for the body element should return the width of the containing frame.
485 bool inQuirksMode = document()->inQuirksMode();
486 if ((!inQuirksMode && document()->documentElement() == this) ||
487 (inQuirksMode && isHTMLElement() && document()->body() == this)) {
488 if (FrameView* view = document()->view()) {
489 if (RenderView* renderView = document()->renderView())
490 return adjustForAbsoluteZoom(view->layoutWidth(), renderView);
494 if (RenderBox* renderer = renderBox())
495 return adjustForAbsoluteZoom(renderer->pixelSnappedClientWidth(), renderer);
499 int Element::clientHeight()
501 document()->updateLayoutIgnorePendingStylesheets();
503 // When in strict mode, clientHeight for the document element should return the height of the containing frame.
504 // When in quirks mode, clientHeight for the body element should return the height of the containing frame.
505 bool inQuirksMode = document()->inQuirksMode();
507 if ((!inQuirksMode && document()->documentElement() == this) ||
508 (inQuirksMode && isHTMLElement() && document()->body() == this)) {
509 if (FrameView* view = document()->view()) {
510 if (RenderView* renderView = document()->renderView())
511 return adjustForAbsoluteZoom(view->layoutHeight(), renderView);
515 if (RenderBox* renderer = renderBox())
516 return adjustForAbsoluteZoom(renderer->pixelSnappedClientHeight(), renderer);
520 int Element::scrollLeft()
522 document()->updateLayoutIgnorePendingStylesheets();
523 if (RenderBox* rend = renderBox())
524 return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
528 int Element::scrollTop()
530 document()->updateLayoutIgnorePendingStylesheets();
531 if (RenderBox* rend = renderBox())
532 return adjustForAbsoluteZoom(rend->scrollTop(), rend);
536 void Element::setScrollLeft(int newLeft)
538 document()->updateLayoutIgnorePendingStylesheets();
539 if (RenderBox* rend = renderBox())
540 rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
543 void Element::setScrollTop(int newTop)
545 document()->updateLayoutIgnorePendingStylesheets();
546 if (RenderBox* rend = renderBox())
547 rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
550 int Element::scrollWidth()
552 document()->updateLayoutIgnorePendingStylesheets();
553 if (RenderBox* rend = renderBox())
554 return adjustForAbsoluteZoom(rend->scrollWidth(), rend);
558 int Element::scrollHeight()
560 document()->updateLayoutIgnorePendingStylesheets();
561 if (RenderBox* rend = renderBox())
562 return adjustForAbsoluteZoom(rend->scrollHeight(), rend);
566 IntRect Element::boundsInRootViewSpace()
568 document()->updateLayoutIgnorePendingStylesheets();
570 FrameView* view = document()->view();
574 Vector<FloatQuad> quads;
576 if (isSVGElement() && renderer()) {
577 // Get the bounding rectangle from the SVG model.
578 SVGElement* svgElement = static_cast<SVGElement*>(this);
580 if (svgElement->getBoundingBox(localRect))
581 quads.append(renderer()->localToAbsoluteQuad(localRect));
585 // Get the bounding rectangle from the box model.
586 if (renderBoxModelObject())
587 renderBoxModelObject()->absoluteQuads(quads);
593 IntRect result = quads[0].enclosingBoundingBox();
594 for (size_t i = 1; i < quads.size(); ++i)
595 result.unite(quads[i].enclosingBoundingBox());
597 result = view->contentsToRootView(result);
601 PassRefPtr<ClientRectList> Element::getClientRects()
603 document()->updateLayoutIgnorePendingStylesheets();
605 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject();
606 if (!renderBoxModelObject)
607 return ClientRectList::create();
609 // FIXME: Handle SVG elements.
610 // FIXME: Handle table/inline-table with a caption.
612 Vector<FloatQuad> quads;
613 renderBoxModelObject->absoluteQuads(quads);
614 document()->adjustFloatQuadsForScrollAndAbsoluteZoomAndFrameScale(quads, renderBoxModelObject);
615 return ClientRectList::create(quads);
618 PassRefPtr<ClientRect> Element::getBoundingClientRect()
620 document()->updateLayoutIgnorePendingStylesheets();
622 Vector<FloatQuad> quads;
624 if (isSVGElement() && renderer() && !renderer()->isSVGRoot()) {
625 // Get the bounding rectangle from the SVG model.
626 SVGElement* svgElement = static_cast<SVGElement*>(this);
628 if (svgElement->getBoundingBox(localRect))
629 quads.append(renderer()->localToAbsoluteQuad(localRect));
633 // Get the bounding rectangle from the box model.
634 if (renderBoxModelObject())
635 renderBoxModelObject()->absoluteQuads(quads);
639 return ClientRect::create();
641 FloatRect result = quads[0].boundingBox();
642 for (size_t i = 1; i < quads.size(); ++i)
643 result.unite(quads[i].boundingBox());
645 document()->adjustFloatRectForScrollAndAbsoluteZoomAndFrameScale(result, renderer());
646 return ClientRect::create(result);
649 IntRect Element::screenRect() const
653 // FIXME: this should probably respect transforms
654 return document()->view()->contentsToScreen(renderer()->absoluteBoundingBoxRectIgnoringTransforms());
657 static inline bool shouldIgnoreAttributeCase(const Element* e)
659 return e && e->document()->isHTMLDocument() && e->isHTMLElement();
662 const AtomicString& Element::getAttribute(const AtomicString& name) const
664 if (!attributeData())
667 bool ignoreCase = shouldIgnoreAttributeCase(this);
669 // Update the 'style' attribute if it's invalid and being requested:
670 if (attributeData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(name, styleAttr.localName(), ignoreCase))
671 updateStyleAttribute();
674 if (attributeData()->m_animatedSVGAttributesAreDirty) {
675 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
676 updateAnimatedSVGAttribute(QualifiedName(nullAtom, name, nullAtom));
680 if (const Attribute* attribute = attributeData()->getAttributeItem(name, ignoreCase))
681 return attribute->value();
685 const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
687 return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
690 void Element::setAttribute(const AtomicString& name, const AtomicString& value, ExceptionCode& ec)
692 if (!Document::isValidName(name)) {
693 ec = INVALID_CHARACTER_ERR;
697 const AtomicString& localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
699 size_t index = ensureUpdatedAttributeData()->getAttributeItemIndex(localName, false);
700 const QualifiedName& qName = index != notFound ? attributeItem(index)->name() : QualifiedName(nullAtom, localName, nullAtom);
701 setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute);
704 void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
706 setAttributeInternal(ensureUpdatedAttributeData()->getAttributeItemIndex(name), name, value, NotInSynchronizationOfLazyAttribute);
709 void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value)
711 setAttributeInternal(mutableAttributeData()->getAttributeItemIndex(name), name, value, InSynchronizationOfLazyAttribute);
714 inline void Element::setAttributeInternal(size_t index, const QualifiedName& name, const AtomicString& newValue, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
716 if (newValue.isNull()) {
717 if (index != notFound)
718 removeAttributeInternal(index, inSynchronizationOfLazyAttribute);
722 if (index == notFound) {
723 addAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute);
727 if (!inSynchronizationOfLazyAttribute)
728 willModifyAttribute(name, attributeItem(index)->value(), newValue);
730 if (newValue != attributeItem(index)->value()) {
731 // If there is an Attr node hooked to this attribute, the Attr::setValue() call below
732 // will write into the ElementAttributeData.
733 // FIXME: Refactor this so it makes some sense.
734 if (RefPtr<Attr> attrNode = attrIfExists(name))
735 attrNode->setValue(newValue);
737 mutableAttributeData()->attributeItem(index)->setValue(newValue);
740 if (!inSynchronizationOfLazyAttribute)
741 didModifyAttribute(name, newValue);
744 static inline AtomicString makeIdForStyleResolution(const AtomicString& value, bool inQuirksMode)
747 return value.lower();
751 static bool checkNeedsStyleInvalidationForIdChange(const AtomicString& oldId, const AtomicString& newId, StyleResolver* styleResolver)
753 ASSERT(newId != oldId);
754 if (!oldId.isEmpty() && styleResolver->hasSelectorForId(oldId))
756 if (!newId.isEmpty() && styleResolver->hasSelectorForId(newId))
761 void Element::attributeChanged(const QualifiedName& name, const AtomicString& newValue)
763 if (ElementShadow* parentElementShadow = shadowOfParentForDistribution(this)) {
764 if (shouldInvalidateDistributionWhenAttributeChanged(parentElementShadow, name, newValue))
765 parentElementShadow->invalidateDistribution();
768 parseAttribute(name, newValue);
770 document()->incDOMTreeVersion();
772 StyleResolver* styleResolver = document()->styleResolverIfExists();
773 bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < FullStyleChange;
774 bool shouldInvalidateStyle = false;
776 if (isIdAttributeName(name)) {
777 AtomicString oldId = attributeData()->idForStyleResolution();
778 AtomicString newId = makeIdForStyleResolution(newValue, document()->inQuirksMode());
779 if (newId != oldId) {
780 attributeData()->setIdForStyleResolution(newId);
781 shouldInvalidateStyle = testShouldInvalidateStyle && checkNeedsStyleInvalidationForIdChange(oldId, newId, styleResolver);
783 } else if (name == classAttr)
784 classAttributeChanged(newValue);
785 else if (name == HTMLNames::nameAttr)
786 setHasName(!newValue.isNull());
787 else if (name == HTMLNames::pseudoAttr)
788 shouldInvalidateStyle |= testShouldInvalidateStyle && isInShadowTree();
790 shouldInvalidateStyle |= testShouldInvalidateStyle && styleResolver->hasSelectorForAttribute(name.localName());
792 invalidateNodeListCachesInAncestors(&name, this);
794 if (shouldInvalidateStyle)
795 setNeedsStyleRecalc();
797 if (AXObjectCache::accessibilityEnabled())
798 document()->axObjectCache()->handleAttributeChanged(name, this);
801 template <typename CharacterType>
802 static inline bool classStringHasClassName(const CharacterType* characters, unsigned length)
808 if (isNotHTMLSpace(characters[i]))
811 } while (i < length);
816 static inline bool classStringHasClassName(const AtomicString& newClassString)
818 unsigned length = newClassString.length();
823 if (newClassString.is8Bit())
824 return classStringHasClassName(newClassString.characters8(), length);
825 return classStringHasClassName(newClassString.characters16(), length);
828 template<typename Checker>
829 static bool checkSelectorForClassChange(const SpaceSplitString& changedClasses, const Checker& checker)
831 unsigned changedSize = changedClasses.size();
832 for (unsigned i = 0; i < changedSize; ++i) {
833 if (checker.hasSelectorForClass(changedClasses[i]))
839 template<typename Checker>
840 static bool checkSelectorForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, const Checker& checker)
842 unsigned oldSize = oldClasses.size();
844 return checkSelectorForClassChange(newClasses, checker);
845 BitVector remainingClassBits;
846 remainingClassBits.ensureSize(oldSize);
847 // Class vectors tend to be very short. This is faster than using a hash table.
848 unsigned newSize = newClasses.size();
849 for (unsigned i = 0; i < newSize; ++i) {
850 for (unsigned j = 0; j < oldSize; ++j) {
851 if (newClasses[i] == oldClasses[j]) {
852 remainingClassBits.quickSet(j);
856 if (checker.hasSelectorForClass(newClasses[i]))
859 for (unsigned i = 0; i < oldSize; ++i) {
860 // If the bit is not set the the corresponding class has been removed.
861 if (remainingClassBits.quickGet(i))
863 if (checker.hasSelectorForClass(oldClasses[i]))
869 void Element::classAttributeChanged(const AtomicString& newClassString)
871 StyleResolver* styleResolver = document()->styleResolverIfExists();
872 bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < FullStyleChange;
873 bool shouldInvalidateStyle = false;
875 if (classStringHasClassName(newClassString)) {
876 const ElementAttributeData* attributeData = ensureAttributeData();
877 const bool shouldFoldCase = document()->inQuirksMode();
878 const SpaceSplitString oldClasses = attributeData->classNames();
880 attributeData->setClass(newClassString, shouldFoldCase);
882 const SpaceSplitString& newClasses = attributeData->classNames();
883 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, newClasses, *styleResolver);
884 } else if (const ElementAttributeData* attributeData = this->attributeData()) {
885 const SpaceSplitString& oldClasses = attributeData->classNames();
886 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, *styleResolver);
888 attributeData->clearClass();
891 if (DOMTokenList* classList = optionalClassList())
892 static_cast<ClassList*>(classList)->reset(newClassString);
894 if (shouldInvalidateStyle)
895 setNeedsStyleRecalc();
898 bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
900 ASSERT(elementShadow);
901 elementShadow->ensureSelectFeatureSetCollected();
903 if (isIdAttributeName(name)) {
904 AtomicString oldId = attributeData()->idForStyleResolution();
905 AtomicString newId = makeIdForStyleResolution(newValue, document()->inQuirksMode());
906 if (newId != oldId) {
907 if (!oldId.isEmpty() && elementShadow->selectRuleFeatureSet().hasSelectorForId(oldId))
909 if (!newId.isEmpty() && elementShadow->selectRuleFeatureSet().hasSelectorForId(newId))
914 if (name == HTMLNames::classAttr) {
915 const AtomicString& newClassString = newValue;
916 if (classStringHasClassName(newClassString)) {
917 const ElementAttributeData* attributeData = ensureAttributeData();
918 const bool shouldFoldCase = document()->inQuirksMode();
919 const SpaceSplitString& oldClasses = attributeData->classNames();
920 const SpaceSplitString newClasses(newClassString, shouldFoldCase);
921 if (checkSelectorForClassChange(oldClasses, newClasses, elementShadow->selectRuleFeatureSet()))
923 } else if (const ElementAttributeData* attributeData = this->attributeData()) {
924 const SpaceSplitString& oldClasses = attributeData->classNames();
925 if (checkSelectorForClassChange(oldClasses, elementShadow->selectRuleFeatureSet()))
930 return elementShadow->selectRuleFeatureSet().hasSelectorForAttribute(name.localName());
933 // Returns true is the given attribute is an event handler.
934 // We consider an event handler any attribute that begins with "on".
935 // It is a simple solution that has the advantage of not requiring any
936 // code or configuration change if a new event handler is defined.
938 static bool isEventHandlerAttribute(const QualifiedName& name)
940 return name.namespaceURI().isNull() && name.localName().startsWith("on");
943 // FIXME: Share code with Element::isURLAttribute.
944 static bool isAttributeToRemove(const QualifiedName& name, const AtomicString& value)
946 return (name.localName() == hrefAttr.localName() || name.localName() == nohrefAttr.localName()
947 || name == srcAttr || name == actionAttr || name == formactionAttr) && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(value));
950 void Element::parserSetAttributes(const Vector<Attribute>& attributeVector, FragmentScriptingPermission scriptingPermission)
952 ASSERT(!inDocument());
953 ASSERT(!parentNode());
955 ASSERT(!m_attributeData);
957 if (attributeVector.isEmpty())
960 Vector<Attribute> filteredAttributes = attributeVector;
962 // If the element is created as result of a paste or drag-n-drop operation
963 // we want to remove all the script and event handlers.
964 if (scriptingPermission == DisallowScriptingContent) {
966 while (i < filteredAttributes.size()) {
967 Attribute& attribute = filteredAttributes[i];
968 if (isEventHandlerAttribute(attribute.name())) {
969 filteredAttributes.remove(i);
973 if (isAttributeToRemove(attribute.name(), attribute.value()))
974 attribute.setValue(emptyAtom);
979 // When the document is in parsing state, we cache immutable ElementAttributeData objects with the
980 // input attribute vector as key. (This cache is held by Document.)
981 if (!document() || !document()->parsing())
982 m_attributeData = ElementAttributeData::createImmutable(filteredAttributes);
984 m_attributeData = document()->cachedImmutableAttributeData(filteredAttributes);
986 // Iterate over the set of attributes we already have on the stack in case
987 // attributeChanged mutates m_attributeData.
988 // FIXME: Find a way so we don't have to do this.
989 for (unsigned i = 0; i < filteredAttributes.size(); ++i)
990 attributeChanged(filteredAttributes[i].name(), filteredAttributes[i].value());
993 bool Element::hasAttributes() const
995 updateInvalidAttributes();
996 return attributeData() && attributeData()->length();
999 bool Element::hasEquivalentAttributes(const Element* other) const
1001 const ElementAttributeData* attributeData = updatedAttributeData();
1002 const ElementAttributeData* otherAttributeData = other->updatedAttributeData();
1003 if (attributeData == otherAttributeData)
1006 return attributeData->isEquivalent(otherAttributeData);
1007 if (otherAttributeData)
1008 return otherAttributeData->isEquivalent(attributeData);
1012 String Element::nodeName() const
1014 return m_tagName.toString();
1017 String Element::nodeNamePreservingCase() const
1019 return m_tagName.toString();
1022 void Element::setPrefix(const AtomicString& prefix, ExceptionCode& ec)
1025 checkSetPrefix(prefix, ec);
1029 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
1032 KURL Element::baseURI() const
1034 const AtomicString& baseAttribute = getAttribute(baseAttr);
1035 KURL base(KURL(), baseAttribute);
1036 if (!base.protocol().isEmpty())
1039 ContainerNode* parent = parentNode();
1043 const KURL& parentBase = parent->baseURI();
1044 if (parentBase.isNull())
1047 return KURL(parentBase, baseAttribute);
1050 const QualifiedName& Element::imageSourceAttributeName() const
1055 bool Element::rendererIsNeeded(const NodeRenderingContext& context)
1057 return context.style()->display() != NONE;
1060 RenderObject* Element::createRenderer(RenderArena*, RenderStyle* style)
1062 return RenderObject::createObject(this, style);
1065 bool Element::wasChangedSinceLastFormControlChangeEvent() const
1070 void Element::setChangedSinceLastFormControlChangeEvent(bool)
1074 Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertionPoint)
1076 // need to do superclass processing first so inDocument() is true
1077 // by the time we reach updateId
1078 ContainerNode::insertedInto(insertionPoint);
1080 #if ENABLE(FULLSCREEN_API)
1081 if (containsFullScreenElement() && parentElement() && !parentElement()->containsFullScreenElement())
1082 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
1085 if (!insertionPoint->inDocument())
1086 return InsertionDone;
1088 const AtomicString& idValue = getIdAttribute();
1089 if (!idValue.isNull())
1090 updateId(nullAtom, idValue);
1092 const AtomicString& nameValue = getNameAttribute();
1093 if (!nameValue.isNull())
1094 updateName(nullAtom, nameValue);
1096 if (hasTagName(labelTag)) {
1097 TreeScope* scope = treeScope();
1098 if (scope->shouldCacheLabelsByForAttribute())
1099 updateLabel(scope, nullAtom, fastGetAttribute(forAttr));
1102 return InsertionDone;
1105 void Element::removedFrom(ContainerNode* insertionPoint)
1107 #if ENABLE(DIALOG_ELEMENT)
1108 setIsInTopLayer(false);
1110 #if ENABLE(FULLSCREEN_API)
1111 if (containsFullScreenElement())
1112 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
1114 #if ENABLE(POINTER_LOCK)
1115 if (document()->page())
1116 document()->page()->pointerLockController()->elementRemoved(this);
1119 setSavedLayerScrollOffset(IntSize());
1121 if (insertionPoint->inDocument()) {
1122 const AtomicString& idValue = getIdAttribute();
1123 if (!idValue.isNull() && inDocument())
1124 updateId(insertionPoint->treeScope(), idValue, nullAtom);
1126 const AtomicString& nameValue = getNameAttribute();
1127 if (!nameValue.isNull())
1128 updateName(nameValue, nullAtom);
1130 if (hasTagName(labelTag)) {
1131 TreeScope* treeScope = insertionPoint->treeScope();
1132 if (treeScope->shouldCacheLabelsByForAttribute())
1133 updateLabel(treeScope, fastGetAttribute(forAttr), nullAtom);
1137 ContainerNode::removedFrom(insertionPoint);
1140 void Element::createRendererIfNeeded()
1142 NodeRenderingContext(this).createRendererForElementIfNeeded();
1145 void Element::attach()
1147 suspendPostAttachCallbacks();
1149 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1150 createRendererIfNeeded();
1152 StyleResolverParentPusher parentPusher(this);
1154 if (parentElement() && parentElement()->isInCanvasSubtree())
1155 setIsInCanvasSubtree(true);
1157 // When a shadow root exists, it does the work of attaching the children.
1158 if (ElementShadow* shadow = this->shadow()) {
1159 parentPusher.push();
1163 parentPusher.push();
1165 ContainerNode::attach();
1167 if (hasRareData()) {
1168 ElementRareData* data = elementRareData();
1169 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
1170 if (isFocusable() && document()->focusedNode() == this)
1171 document()->updateFocusAppearanceSoon(false /* don't restore selection */);
1172 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1176 resumePostAttachCallbacks();
1179 void Element::unregisterNamedFlowContentNode()
1181 if (document()->cssRegionsEnabled() && inNamedFlow() && document()->renderView())
1182 document()->renderView()->flowThreadController()->unregisterNamedFlowContentNode(this);
1185 void Element::detach()
1187 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1188 unregisterNamedFlowContentNode();
1189 cancelFocusAppearanceUpdate();
1190 if (hasRareData()) {
1191 ElementRareData* data = elementRareData();
1192 data->setIsInCanvasSubtree(false);
1193 data->resetComputedStyle();
1194 data->resetDynamicRestyleObservations();
1197 if (ElementShadow* shadow = this->shadow()) {
1198 detachChildrenIfNeeded();
1201 ContainerNode::detach();
1204 bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle)
1206 ASSERT(currentStyle == renderStyle());
1212 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles();
1213 if (!pseudoStyleCache)
1216 size_t cacheSize = pseudoStyleCache->size();
1217 for (size_t i = 0; i < cacheSize; ++i) {
1218 RefPtr<RenderStyle> newPseudoStyle;
1219 PseudoId pseudoId = pseudoStyleCache->at(i)->styleType();
1220 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
1221 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle);
1223 newPseudoStyle = renderer()->getUncachedPseudoStyle(pseudoId, newStyle, newStyle);
1224 if (!newPseudoStyle)
1226 if (*newPseudoStyle != *pseudoStyleCache->at(i)) {
1227 if (pseudoId < FIRST_INTERNAL_PSEUDOID)
1228 newStyle->setHasPseudoStyle(pseudoId);
1229 newStyle->addCachedPseudoStyle(newPseudoStyle);
1230 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
1231 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
1232 // is needed, but for now just assume a layout will be required. The diff code
1233 // in RenderObject::setStyle would need to be factored out so that it could be reused.
1234 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
1242 PassRefPtr<RenderStyle> Element::styleForRenderer()
1244 if (hasCustomCallbacks()) {
1245 if (RefPtr<RenderStyle> style = customStyleForRenderer())
1246 return style.release();
1249 return document()->styleResolver()->styleForElement(this);
1252 void Element::recalcStyle(StyleChange change)
1254 if (hasCustomCallbacks()) {
1255 if (!willRecalcStyle(change))
1259 // Ref currentStyle in case it would otherwise be deleted when setting the new style in the renderer.
1260 RefPtr<RenderStyle> currentStyle(renderStyle());
1261 bool hasParentStyle = parentNodeForRenderingAndStyle() ? static_cast<bool>(parentNodeForRenderingAndStyle()->renderStyle()) : false;
1262 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
1263 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
1265 if ((change > NoChange || needsStyleRecalc())) {
1267 elementRareData()->resetComputedStyle();
1269 if (hasParentStyle && (change >= Inherit || needsStyleRecalc())) {
1270 RefPtr<RenderStyle> newStyle = styleForRenderer();
1271 StyleChange ch = Node::diff(currentStyle.get(), newStyle.get(), document());
1272 if (ch == Detach || !currentStyle) {
1273 // FIXME: The style gets computed twice by calling attach. We could do better if we passed the style along.
1275 // attach recalculates the style for all children. No need to do it twice.
1276 clearNeedsStyleRecalc();
1277 clearChildNeedsStyleRecalc();
1279 if (hasCustomCallbacks())
1280 didRecalcStyle(change);
1284 if (RenderObject* renderer = this->renderer()) {
1285 if (ch != NoChange || pseudoStyleCacheIsInvalid(currentStyle.get(), newStyle.get()) || (change == Force && renderer->requiresForcedStyleRecalcPropagation()) || styleChangeType() == SyntheticStyleChange)
1286 renderer->setAnimatableStyle(newStyle.get());
1287 else if (needsStyleRecalc()) {
1288 // Although no change occurred, we use the new style so that the cousin style sharing code won't get
1289 // fooled into believing this style is the same.
1290 renderer->setStyleInternal(newStyle.get());
1294 // If "rem" units are used anywhere in the document, and if the document element's font size changes, then go ahead and force font updating
1295 // all the way down the tree. This is simpler than having to maintain a cache of objects (and such font size changes should be rare anyway).
1296 if (document()->styleSheetCollection()->usesRemUnits() && document()->documentElement() == this && ch != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize()) {
1297 // Cached RenderStyles may depend on the rem units.
1298 document()->styleResolver()->invalidateMatchedPropertiesCache();
1302 if (change != Force) {
1303 if (styleChangeType() >= FullStyleChange)
1309 StyleResolverParentPusher parentPusher(this);
1311 // FIXME: This does not care about sibling combinators. Will be necessary in XBL2 world.
1312 if (ElementShadow* shadow = this->shadow()) {
1313 if (change >= Inherit || shadow->childNeedsStyleRecalc() || shadow->needsStyleRecalc()) {
1314 parentPusher.push();
1315 shadow->recalcStyle(change);
1319 // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
1320 // For now we will just worry about the common case, since it's a lot trickier to get the second case right
1321 // without doing way too much re-resolution.
1322 bool forceCheckOfNextElementSibling = false;
1323 bool forceCheckOfAnyElementSibling = false;
1324 for (Node *n = firstChild(); n; n = n->nextSibling()) {
1325 if (n->isTextNode()) {
1326 toText(n)->recalcTextStyle(change);
1329 if (!n->isElementNode())
1331 Element* element = static_cast<Element*>(n);
1332 bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() == FullStyleChange;
1333 if ((forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling))
1334 element->setNeedsStyleRecalc();
1335 if (change >= Inherit || element->childNeedsStyleRecalc() || element->needsStyleRecalc()) {
1336 parentPusher.push();
1337 element->recalcStyle(change);
1339 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
1340 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
1343 clearNeedsStyleRecalc();
1344 clearChildNeedsStyleRecalc();
1346 if (hasCustomCallbacks())
1347 didRecalcStyle(change);
1350 ElementShadow* Element::shadow() const
1355 return elementRareData()->m_shadow.get();
1358 ElementShadow* Element::ensureShadow()
1360 if (ElementShadow* shadow = ensureElementRareData()->m_shadow.get())
1363 ElementRareData* data = elementRareData();
1364 data->m_shadow = adoptPtr(new ElementShadow());
1365 return data->m_shadow.get();
1368 PassRefPtr<ShadowRoot> Element::createShadowRoot(ExceptionCode& ec)
1370 return ShadowRoot::create(this, ec);
1373 ShadowRoot* Element::userAgentShadowRoot() const
1375 if (ElementShadow* elementShadow = shadow()) {
1376 if (ShadowRoot* shadowRoot = elementShadow->oldestShadowRoot()) {
1377 ASSERT(shadowRoot->type() == ShadowRoot::UserAgentShadowRoot);
1385 const AtomicString& Element::shadowPseudoId() const
1390 bool Element::childTypeAllowed(NodeType type) const
1396 case PROCESSING_INSTRUCTION_NODE:
1397 case CDATA_SECTION_NODE:
1398 case ENTITY_REFERENCE_NODE:
1406 static void checkForEmptyStyleChange(Element* element, RenderStyle* style)
1408 if (!style && !element->styleAffectedByEmpty())
1411 if (!style || (element->styleAffectedByEmpty() && (!style->emptyState() || element->hasChildNodes())))
1412 element->setNeedsStyleRecalc();
1415 static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
1416 Node* beforeChange, Node* afterChange, int childCountDelta)
1419 checkForEmptyStyleChange(e, style);
1421 if (!style || (e->needsStyleRecalc() && e->childrenAffectedByPositionalRules()))
1424 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1425 // In the DOM case, we only need to do something if |afterChange| is not 0.
1426 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
1427 if (e->childrenAffectedByFirstChildRules() && afterChange) {
1428 // Find our new first child.
1429 Node* newFirstChild = 0;
1430 for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {};
1432 // Find the first element node following |afterChange|
1433 Node* firstElementAfterInsertion = 0;
1434 for (firstElementAfterInsertion = afterChange;
1435 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
1436 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
1438 // This is the insert/append case.
1439 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertion && firstElementAfterInsertion->attached() &&
1440 firstElementAfterInsertion->renderStyle() && firstElementAfterInsertion->renderStyle()->firstChildState())
1441 firstElementAfterInsertion->setNeedsStyleRecalc();
1443 // We also have to handle node removal.
1444 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChild->renderStyle() || !newFirstChild->renderStyle()->firstChildState()))
1445 newFirstChild->setNeedsStyleRecalc();
1448 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1449 // In the DOM case, we only need to do something if |afterChange| is not 0.
1450 if (e->childrenAffectedByLastChildRules() && beforeChange) {
1451 // Find our new last child.
1452 Node* newLastChild = 0;
1453 for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {};
1455 // Find the last element node going backwards from |beforeChange|
1456 Node* lastElementBeforeInsertion = 0;
1457 for (lastElementBeforeInsertion = beforeChange;
1458 lastElementBeforeInsertion && !lastElementBeforeInsertion->isElementNode();
1459 lastElementBeforeInsertion = lastElementBeforeInsertion->previousSibling()) {};
1461 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertion && lastElementBeforeInsertion->attached() &&
1462 lastElementBeforeInsertion->renderStyle() && lastElementBeforeInsertion->renderStyle()->lastChildState())
1463 lastElementBeforeInsertion->setNeedsStyleRecalc();
1465 // 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
1467 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChild->renderStyle() || !newLastChild->renderStyle()->lastChildState()))
1468 newLastChild->setNeedsStyleRecalc();
1471 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
1472 // that could be affected by this DOM change.
1473 if (e->childrenAffectedByDirectAdjacentRules() && afterChange) {
1474 Node* firstElementAfterInsertion = 0;
1475 for (firstElementAfterInsertion = afterChange;
1476 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
1477 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
1478 if (firstElementAfterInsertion && firstElementAfterInsertion->attached())
1479 firstElementAfterInsertion->setNeedsStyleRecalc();
1482 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
1483 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1484 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
1486 // |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.
1487 // 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
1488 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
1489 if ((e->childrenAffectedByForwardPositionalRules() && afterChange)
1490 || (e->childrenAffectedByBackwardPositionalRules() && beforeChange))
1491 e->setNeedsStyleRecalc();
1494 void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
1496 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
1497 if (changedByParser)
1498 checkForEmptyStyleChange(this, renderStyle());
1500 checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
1502 if (ElementShadow * shadow = this->shadow())
1503 shadow->invalidateDistribution();
1506 void Element::beginParsingChildren()
1508 clearIsParsingChildrenFinished();
1509 StyleResolver* styleResolver = document()->styleResolverIfExists();
1510 if (styleResolver && attached())
1511 styleResolver->pushParentElement(this);
1514 void Element::finishParsingChildren()
1516 ContainerNode::finishParsingChildren();
1517 setIsParsingChildrenFinished();
1518 checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
1519 if (StyleResolver* styleResolver = document()->styleResolverIfExists())
1520 styleResolver->popParentElement(this);
1524 void Element::formatForDebugger(char* buffer, unsigned length) const
1526 StringBuilder result;
1529 result.append(nodeName());
1531 s = getIdAttribute();
1532 if (s.length() > 0) {
1533 if (result.length() > 0)
1534 result.appendLiteral("; ");
1535 result.appendLiteral("id=");
1539 s = getAttribute(classAttr);
1540 if (s.length() > 0) {
1541 if (result.length() > 0)
1542 result.appendLiteral("; ");
1543 result.appendLiteral("class=");
1547 strncpy(buffer, result.toString().utf8().data(), length - 1);
1551 PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionCode& ec)
1554 ec = TYPE_MISMATCH_ERR;
1558 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName());
1559 if (oldAttrNode.get() == attrNode)
1560 return attrNode; // This Attr is already attached to the element.
1562 // INUSE_ATTRIBUTE_ERR: Raised if node is an Attr that is already an attribute of another Element object.
1563 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
1564 if (attrNode->ownerElement()) {
1565 ec = INUSE_ATTRIBUTE_ERR;
1569 updateInvalidAttributes();
1570 ElementAttributeData* attributeData = mutableAttributeData();
1572 size_t index = attributeData->getAttributeItemIndex(attrNode->qualifiedName());
1573 if (index != notFound) {
1575 detachAttrNodeFromElementWithValue(oldAttrNode.get(), attributeData->attributeItem(index)->value());
1577 oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), attributeData->attributeItem(index)->value());
1580 setAttributeInternal(index, attrNode->qualifiedName(), attrNode->value(), NotInSynchronizationOfLazyAttribute);
1582 attrNode->attachToElement(this);
1583 ensureAttrNodeListForElement(this)->append(attrNode);
1585 return oldAttrNode.release();
1588 PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionCode& ec)
1590 return setAttributeNode(attr, ec);
1593 PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec)
1596 ec = TYPE_MISMATCH_ERR;
1599 if (attr->ownerElement() != this) {
1604 ASSERT(document() == attr->document());
1606 const ElementAttributeData* attributeData = updatedAttributeData();
1607 ASSERT(attributeData);
1609 size_t index = attributeData->getAttributeItemIndex(attr->qualifiedName());
1610 if (index == notFound) {
1615 return detachAttribute(index);
1618 bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionCode& ec)
1620 String prefix, localName;
1621 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec))
1625 QualifiedName qName(prefix, localName, namespaceURI);
1627 if (!Document::hasValidNamespaceForAttributes(qName)) {
1636 void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode& ec)
1638 QualifiedName parsedName = anyName;
1639 if (!parseAttributeName(parsedName, namespaceURI, qualifiedName, ec))
1641 setAttribute(parsedName, value);
1644 void Element::removeAttributeInternal(size_t index, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1646 ASSERT(index < attributeCount());
1648 ElementAttributeData* attributeData = mutableAttributeData();
1650 QualifiedName name = attributeData->attributeItem(index)->name();
1651 AtomicString valueBeingRemoved = attributeData->attributeItem(index)->value();
1653 if (!inSynchronizationOfLazyAttribute) {
1654 if (!valueBeingRemoved.isNull())
1655 willModifyAttribute(name, valueBeingRemoved, nullAtom);
1658 if (RefPtr<Attr> attrNode = attrIfExists(name))
1659 detachAttrNodeFromElementWithValue(attrNode.get(), attributeData->attributeItem(index)->value());
1661 attributeData->removeAttribute(index);
1663 if (!inSynchronizationOfLazyAttribute)
1664 didRemoveAttribute(name);
1667 void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1669 if (!inSynchronizationOfLazyAttribute)
1670 willModifyAttribute(name, nullAtom, value);
1671 mutableAttributeData()->addAttribute(Attribute(name, value));
1672 if (!inSynchronizationOfLazyAttribute)
1673 didAddAttribute(name, value);
1676 void Element::removeAttribute(const AtomicString& name)
1678 if (!attributeData())
1681 AtomicString localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1682 size_t index = attributeData()->getAttributeItemIndex(localName, false);
1683 if (index == notFound) {
1684 if (UNLIKELY(localName == styleAttr) && attributeData()->m_styleAttributeIsDirty && isStyledElement())
1685 static_cast<StyledElement*>(this)->removeAllInlineStyleProperties();
1689 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
1692 void Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName)
1694 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI));
1697 PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& name)
1699 const ElementAttributeData* attributeData = updatedAttributeData();
1702 const Attribute* attribute = attributeData->getAttributeItem(name, shouldIgnoreAttributeCase(this));
1705 return ensureAttr(attribute->name());
1708 PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
1710 const ElementAttributeData* attributeData = updatedAttributeData();
1713 const Attribute* attribute = attributeData->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI));
1716 return ensureAttr(attribute->name());
1719 bool Element::hasAttribute(const AtomicString& name) const
1721 if (!attributeData())
1724 // This call to String::lower() seems to be required but
1725 // there may be a way to remove it.
1726 AtomicString localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1727 return updatedAttributeData()->getAttributeItem(localName, false);
1730 bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
1732 const ElementAttributeData* attributeData = updatedAttributeData();
1735 return attributeData->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI));
1738 CSSStyleDeclaration *Element::style()
1743 void Element::focus(bool restorePreviousSelection)
1748 Document* doc = document();
1749 if (doc->focusedNode() == this)
1752 // If the stylesheets have already been loaded we can reliably check isFocusable.
1753 // If not, we continue and set the focused node on the focus controller below so
1754 // that it can be updated soon after attach.
1755 if (doc->haveStylesheetsLoaded()) {
1756 doc->updateLayoutIgnorePendingStylesheets();
1761 if (!supportsFocus())
1764 RefPtr<Node> protect;
1765 if (Page* page = doc->page()) {
1766 // Focus and change event handlers can cause us to lose our last ref.
1767 // If a focus event handler changes the focus to a different node it
1768 // does not make sense to continue and update appearence.
1770 if (!page->focusController()->setFocusedNode(this, doc->frame()))
1774 // Setting the focused node above might have invalidated the layout due to scripts.
1775 doc->updateLayoutIgnorePendingStylesheets();
1777 if (!isFocusable()) {
1778 ensureElementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
1782 cancelFocusAppearanceUpdate();
1783 updateFocusAppearance(restorePreviousSelection);
1786 void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
1788 if (isRootEditableElement()) {
1789 Frame* frame = document()->frame();
1793 // When focusing an editable element in an iframe, don't reset the selection if it already contains a selection.
1794 if (this == frame->selection()->rootEditableElement())
1797 // FIXME: We should restore the previous selection if there is one.
1798 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
1800 if (frame->selection()->shouldChangeSelection(newSelection)) {
1801 frame->selection()->setSelection(newSelection);
1802 frame->selection()->revealSelection();
1804 } else if (renderer() && !renderer()->isWidget())
1805 renderer()->scrollRectToVisible(boundingBox());
1808 void Element::blur()
1810 cancelFocusAppearanceUpdate();
1811 Document* doc = document();
1812 if (treeScope()->focusedNode() == this) {
1814 doc->frame()->page()->focusController()->setFocusedNode(0, doc->frame());
1816 doc->setFocusedNode(0);
1820 String Element::innerText()
1822 // We need to update layout, since plainText uses line boxes in the render tree.
1823 document()->updateLayoutIgnorePendingStylesheets();
1826 return textContent(true);
1828 return plainText(rangeOfContents(const_cast<Element*>(this)).get());
1831 String Element::outerText()
1833 // Getting outerText is the same as getting innerText, only
1834 // setting is different. You would think this should get the plain
1835 // text for the outer range, but this is wrong, <br> for instance
1836 // would return different values for inner and outer text by such
1837 // a rule, but it doesn't in WinIE, and we want to match that.
1841 String Element::title() const
1846 const AtomicString& Element::pseudo() const
1848 return getAttribute(pseudoAttr);
1851 void Element::setPseudo(const AtomicString& value)
1853 setAttribute(pseudoAttr, value);
1856 LayoutSize Element::minimumSizeForResizing() const
1858 return hasRareData() ? elementRareData()->m_minimumSizeForResizing : defaultMinimumSizeForResizing();
1861 void Element::setMinimumSizeForResizing(const LayoutSize& size)
1863 if (size == defaultMinimumSizeForResizing() && !hasRareData())
1865 ensureElementRareData()->m_minimumSizeForResizing = size;
1868 RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
1870 // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
1871 // properties, which are only known by the renderer because it did the layout, will be correct and so that the
1872 // values returned for the ":selection" pseudo-element will be correct.
1873 if (RenderStyle* usedStyle = renderStyle()) {
1874 if (pseudoElementSpecifier) {
1875 RenderStyle* cachedPseudoStyle = usedStyle->getCachedPseudoStyle(pseudoElementSpecifier);
1876 return cachedPseudoStyle ? cachedPseudoStyle : usedStyle;
1882 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
1883 // document tree and figure out when to destroy the computed style for such elements.
1886 ElementRareData* data = ensureElementRareData();
1887 if (!data->m_computedStyle)
1888 data->m_computedStyle = document()->styleForElementIgnoringPendingStylesheets(this);
1889 return pseudoElementSpecifier ? data->m_computedStyle->getCachedPseudoStyle(pseudoElementSpecifier) : data->m_computedStyle.get();
1892 void Element::setStyleAffectedByEmpty()
1894 ensureElementRareData()->setStyleAffectedByEmpty(true);
1897 void Element::setChildrenAffectedByHover(bool value)
1899 if (value || hasRareData())
1900 ensureElementRareData()->setChildrenAffectedByHover(value);
1903 void Element::setChildrenAffectedByActive(bool value)
1905 if (value || hasRareData())
1906 ensureElementRareData()->setChildrenAffectedByActive(value);
1909 void Element::setChildrenAffectedByDrag(bool value)
1911 if (value || hasRareData())
1912 ensureElementRareData()->setChildrenAffectedByDrag(value);
1915 void Element::setChildrenAffectedByFirstChildRules()
1917 ensureElementRareData()->setChildrenAffectedByFirstChildRules(true);
1920 void Element::setChildrenAffectedByLastChildRules()
1922 ensureElementRareData()->setChildrenAffectedByLastChildRules(true);
1925 void Element::setChildrenAffectedByDirectAdjacentRules()
1927 ensureElementRareData()->setChildrenAffectedByDirectAdjacentRules(true);
1930 void Element::setChildrenAffectedByForwardPositionalRules()
1932 ensureElementRareData()->setChildrenAffectedByForwardPositionalRules(true);
1935 void Element::setChildrenAffectedByBackwardPositionalRules()
1937 ensureElementRareData()->setChildrenAffectedByBackwardPositionalRules(true);
1940 void Element::setChildIndex(unsigned index)
1942 ElementRareData* rareData = ensureElementRareData();
1943 if (RenderStyle* style = renderStyle())
1945 rareData->setChildIndex(index);
1948 bool Element::rareDataStyleAffectedByEmpty() const
1950 ASSERT(hasRareData());
1951 return elementRareData()->styleAffectedByEmpty();
1954 bool Element::rareDataChildrenAffectedByHover() const
1956 ASSERT(hasRareData());
1957 return elementRareData()->childrenAffectedByHover();
1960 bool Element::rareDataChildrenAffectedByActive() const
1962 ASSERT(hasRareData());
1963 return elementRareData()->childrenAffectedByActive();
1966 bool Element::rareDataChildrenAffectedByDrag() const
1968 ASSERT(hasRareData());
1969 return elementRareData()->childrenAffectedByDrag();
1972 bool Element::rareDataChildrenAffectedByFirstChildRules() const
1974 ASSERT(hasRareData());
1975 return elementRareData()->childrenAffectedByFirstChildRules();
1978 bool Element::rareDataChildrenAffectedByLastChildRules() const
1980 ASSERT(hasRareData());
1981 return elementRareData()->childrenAffectedByLastChildRules();
1984 bool Element::rareDataChildrenAffectedByDirectAdjacentRules() const
1986 ASSERT(hasRareData());
1987 return elementRareData()->childrenAffectedByDirectAdjacentRules();
1990 bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
1992 ASSERT(hasRareData());
1993 return elementRareData()->childrenAffectedByForwardPositionalRules();
1996 bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
1998 ASSERT(hasRareData());
1999 return elementRareData()->childrenAffectedByBackwardPositionalRules();
2002 unsigned Element::rareDataChildIndex() const
2004 ASSERT(hasRareData());
2005 return elementRareData()->childIndex();
2008 void Element::setIsInCanvasSubtree(bool isInCanvasSubtree)
2010 ensureElementRareData()->setIsInCanvasSubtree(isInCanvasSubtree);
2013 bool Element::isInCanvasSubtree() const
2015 return hasRareData() && elementRareData()->isInCanvasSubtree();
2018 AtomicString Element::computeInheritedLanguage() const
2020 const Node* n = this;
2022 // The language property is inherited, so we iterate over the parents to find the first language.
2024 if (n->isElementNode()) {
2025 if (const ElementAttributeData* attributeData = static_cast<const Element*>(n)->attributeData()) {
2026 // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7
2027 if (const Attribute* attribute = attributeData->getAttributeItem(XMLNames::langAttr))
2028 value = attribute->value();
2029 else if (const Attribute* attribute = attributeData->getAttributeItem(HTMLNames::langAttr))
2030 value = attribute->value();
2032 } else if (n->isDocumentNode()) {
2033 // checking the MIME content-language
2034 value = static_cast<const Document*>(n)->contentLanguage();
2037 n = n->parentNode();
2038 } while (n && value.isNull());
2043 Locale& Element::locale() const
2045 return document()->getCachedLocale(computeInheritedLanguage());
2048 void Element::cancelFocusAppearanceUpdate()
2051 elementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
2052 if (document()->focusedNode() == this)
2053 document()->cancelFocusAppearanceUpdate();
2056 void Element::normalizeAttributes()
2058 updateInvalidAttributes();
2059 if (AttrNodeList* attrNodeList = attrNodeListForElement(this)) {
2060 for (unsigned i = 0; i < attrNodeList->size(); ++i)
2061 attrNodeList->at(i)->normalize();
2065 // ElementTraversal API
2066 Element* Element::firstElementChild() const
2068 return WebCore::firstElementChild(this);
2071 Element* Element::lastElementChild() const
2073 Node* n = lastChild();
2074 while (n && !n->isElementNode())
2075 n = n->previousSibling();
2076 return static_cast<Element*>(n);
2079 unsigned Element::childElementCount() const
2082 Node* n = firstChild();
2084 count += n->isElementNode();
2085 n = n->nextSibling();
2090 bool Element::shouldMatchReadOnlySelector() const
2095 bool Element::shouldMatchReadWriteSelector() const
2100 bool Element::webkitMatchesSelector(const String& selector, ExceptionCode& ec)
2102 if (selector.isEmpty()) {
2107 SelectorQuery* selectorQuery = document()->selectorQueryCache()->add(selector, document(), ec);
2110 return selectorQuery->matches(this);
2113 DOMTokenList* Element::classList()
2115 ElementRareData* data = ensureElementRareData();
2116 if (!data->m_classList)
2117 data->m_classList = ClassList::create(this);
2118 return data->m_classList.get();
2121 DOMTokenList* Element::optionalClassList() const
2125 return elementRareData()->m_classList.get();
2128 DOMStringMap* Element::dataset()
2130 ElementRareData* data = ensureElementRareData();
2131 if (!data->m_datasetDOMStringMap)
2132 data->m_datasetDOMStringMap = DatasetDOMStringMap::create(this);
2133 return data->m_datasetDOMStringMap.get();
2136 KURL Element::getURLAttribute(const QualifiedName& name) const
2138 #if !ASSERT_DISABLED
2139 if (attributeData()) {
2140 if (const Attribute* attribute = getAttributeItem(name))
2141 ASSERT(isURLAttribute(*attribute));
2144 return document()->completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
2147 KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
2149 #if !ASSERT_DISABLED
2150 if (attributeData()) {
2151 if (const Attribute* attribute = getAttributeItem(name))
2152 ASSERT(isURLAttribute(*attribute));
2155 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
2156 if (value.isEmpty())
2158 return document()->completeURL(value);
2161 int Element::getIntegralAttribute(const QualifiedName& attributeName) const
2163 return getAttribute(attributeName).string().toInt();
2166 void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
2168 // FIXME: Need an AtomicString version of String::number.
2169 setAttribute(attributeName, String::number(value));
2172 unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
2174 return getAttribute(attributeName).string().toUInt();
2177 void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
2179 // FIXME: Need an AtomicString version of String::number.
2180 setAttribute(attributeName, String::number(value));
2184 bool Element::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
2186 // Only create renderers for SVG elements whose parents are SVG elements, or for proper <svg xmlns="svgNS"> subdocuments.
2187 if (childContext.node()->isSVGElement())
2188 return childContext.node()->hasTagName(SVGNames::svgTag) || isSVGElement();
2190 return ContainerNode::childShouldCreateRenderer(childContext);
2194 #if ENABLE(FULLSCREEN_API)
2195 void Element::webkitRequestFullscreen()
2197 document()->requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, Document::EnforceIFrameAllowFullScreenRequirement);
2200 void Element::webkitRequestFullScreen(unsigned short flags)
2202 document()->requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), Document::EnforceIFrameAllowFullScreenRequirement);
2205 bool Element::containsFullScreenElement() const
2207 return hasRareData() && elementRareData()->containsFullScreenElement();
2210 void Element::setContainsFullScreenElement(bool flag)
2212 ensureElementRareData()->setContainsFullScreenElement(flag);
2213 setNeedsStyleRecalc(SyntheticStyleChange);
2216 static Element* parentCrossingFrameBoundaries(Element* element)
2219 return element->parentElement() ? element->parentElement() : element->document()->ownerElement();
2222 void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool flag)
2224 Element* element = this;
2225 while ((element = parentCrossingFrameBoundaries(element)))
2226 element->setContainsFullScreenElement(flag);
2230 #if ENABLE(DIALOG_ELEMENT)
2231 bool Element::isInTopLayer() const
2233 return hasRareData() && elementRareData()->isInTopLayer();
2236 void Element::setIsInTopLayer(bool inTopLayer)
2238 if (isInTopLayer() == inTopLayer)
2241 ensureElementRareData()->setIsInTopLayer(inTopLayer);
2244 document()->addToTopLayer(this);
2246 document()->removeFromTopLayer(this);
2247 setNeedsStyleRecalc(SyntheticStyleChange);
2251 #if ENABLE(POINTER_LOCK)
2252 void Element::webkitRequestPointerLock()
2254 if (document()->page())
2255 document()->page()->pointerLockController()->requestPointerLock(this);
2259 SpellcheckAttributeState Element::spellcheckAttributeState() const
2261 const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
2262 if (value == nullAtom)
2263 return SpellcheckAttributeDefault;
2264 if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
2265 return SpellcheckAttributeTrue;
2266 if (equalIgnoringCase(value, "false"))
2267 return SpellcheckAttributeFalse;
2269 return SpellcheckAttributeDefault;
2272 bool Element::isSpellCheckingEnabled() const
2274 for (const Element* element = this; element; element = element->parentOrHostElement()) {
2275 switch (element->spellcheckAttributeState()) {
2276 case SpellcheckAttributeTrue:
2278 case SpellcheckAttributeFalse:
2280 case SpellcheckAttributeDefault:
2288 PassRefPtr<WebKitAnimationList> Element::webkitGetAnimations() const
2293 AnimationController* animController = renderer()->animation();
2295 if (!animController)
2298 return animController->animationsForRenderer(renderer());
2301 RenderRegion* Element::renderRegion() const
2303 if (renderer() && renderer()->isRenderRegion())
2304 return toRenderRegion(renderer());
2309 #if ENABLE(CSS_REGIONS)
2311 const AtomicString& Element::webkitRegionOverset() const
2313 document()->updateLayoutIgnorePendingStylesheets();
2315 DEFINE_STATIC_LOCAL(AtomicString, undefinedState, ("undefined", AtomicString::ConstructFromLiteral));
2316 if (!document()->cssRegionsEnabled() || !renderRegion())
2317 return undefinedState;
2319 switch (renderRegion()->regionState()) {
2320 case RenderRegion::RegionFit: {
2321 DEFINE_STATIC_LOCAL(AtomicString, fitState, ("fit", AtomicString::ConstructFromLiteral));
2324 case RenderRegion::RegionEmpty: {
2325 DEFINE_STATIC_LOCAL(AtomicString, emptyState, ("empty", AtomicString::ConstructFromLiteral));
2328 case RenderRegion::RegionOverset: {
2329 DEFINE_STATIC_LOCAL(AtomicString, overflowState, ("overset", AtomicString::ConstructFromLiteral));
2330 return overflowState;
2332 case RenderRegion::RegionUndefined:
2333 return undefinedState;
2336 ASSERT_NOT_REACHED();
2337 return undefinedState;
2340 Vector<RefPtr<Range> > Element::webkitGetRegionFlowRanges() const
2342 document()->updateLayoutIgnorePendingStylesheets();
2344 Vector<RefPtr<Range> > rangeObjects;
2345 if (document()->cssRegionsEnabled() && renderer() && renderer()->isRenderRegion()) {
2346 RenderRegion* region = toRenderRegion(renderer());
2347 if (region->isValid())
2348 region->getRanges(rangeObjects);
2351 return rangeObjects;
2357 bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
2359 if (name == HTMLNames::styleAttr)
2364 return !SVGElement::isAnimatableAttribute(name);
2371 #ifdef DUMP_NODE_STATISTICS
2372 bool Element::hasNamedNodeMap() const
2374 return hasRareData() && elementRareData()->m_attributeMap;
2378 void Element::updateLabel(TreeScope* scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
2380 ASSERT(hasTagName(labelTag));
2385 if (oldForAttributeValue == newForAttributeValue)
2388 if (!oldForAttributeValue.isEmpty())
2389 scope->removeLabel(oldForAttributeValue, static_cast<HTMLLabelElement*>(this));
2390 if (!newForAttributeValue.isEmpty())
2391 scope->addLabel(newForAttributeValue, static_cast<HTMLLabelElement*>(this));
2394 void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
2396 if (isIdAttributeName(name))
2397 updateId(oldValue, newValue);
2398 else if (name == HTMLNames::nameAttr)
2399 updateName(oldValue, newValue);
2400 else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
2401 TreeScope* scope = treeScope();
2402 if (scope->shouldCacheLabelsByForAttribute())
2403 updateLabel(scope, oldValue, newValue);
2406 #if ENABLE(MUTATION_OBSERVERS)
2407 if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(this, name))
2408 recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue));
2411 #if ENABLE(INSPECTOR)
2412 InspectorInstrumentation::willModifyDOMAttr(document(), this, oldValue, newValue);
2416 void Element::didAddAttribute(const QualifiedName& name, const AtomicString& value)
2418 attributeChanged(name, value);
2419 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value);
2420 dispatchSubtreeModifiedEvent();
2423 void Element::didModifyAttribute(const QualifiedName& name, const AtomicString& value)
2425 attributeChanged(name, value);
2426 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value);
2427 // Do not dispatch a DOMSubtreeModified event here; see bug 81141.
2430 void Element::didRemoveAttribute(const QualifiedName& name)
2432 attributeChanged(name, nullAtom);
2433 InspectorInstrumentation::didRemoveDOMAttr(document(), this, name.localName());
2434 dispatchSubtreeModifiedEvent();
2438 void Element::updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName)
2440 if (!document()->isHTMLDocument())
2443 if (!oldName.isEmpty())
2444 static_cast<HTMLDocument*>(document())->removeNamedItem(oldName);
2446 if (!newName.isEmpty())
2447 static_cast<HTMLDocument*>(document())->addNamedItem(newName);
2450 void Element::updateExtraNamedItemRegistration(const AtomicString& oldId, const AtomicString& newId)
2452 if (!document()->isHTMLDocument())
2455 if (!oldId.isEmpty())
2456 static_cast<HTMLDocument*>(document())->removeExtraNamedItem(oldId);
2458 if (!newId.isEmpty())
2459 static_cast<HTMLDocument*>(document())->addExtraNamedItem(newId);
2462 PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
2464 if (HTMLCollection* collection = cachedHTMLCollection(type))
2467 RefPtr<HTMLCollection> collection;
2468 if (type == TableRows) {
2469 ASSERT(hasTagName(tableTag));
2470 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
2471 } else if (type == SelectOptions) {
2472 ASSERT(hasTagName(selectTag));
2473 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
2474 } else if (type == FormControls) {
2475 ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
2476 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
2477 #if ENABLE(MICRODATA)
2478 } else if (type == ItemProperties) {
2479 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLPropertiesCollection>(this, type);
2482 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLCollection>(this, type);
2485 HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
2487 return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0;
2490 IntSize Element::savedLayerScrollOffset() const
2492 return hasRareData() ? elementRareData()->m_savedLayerScrollOffset : IntSize();
2495 void Element::setSavedLayerScrollOffset(const IntSize& size)
2497 if (size.isZero() && !hasRareData())
2499 ensureElementRareData()->m_savedLayerScrollOffset = size;
2502 PassRefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
2504 if (AttrNodeList* attrNodeList = attrNodeListForElement(this))
2505 return findAttrNodeInList(attrNodeList, name);
2509 PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name)
2511 AttrNodeList* attrNodeList = ensureAttrNodeListForElement(this);
2512 RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
2514 attrNode = Attr::create(this, name);
2515 attrNodeList->append(attrNode);
2517 return attrNode.release();
2520 void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value)
2522 ASSERT(hasSyntheticAttrChildNodes());
2523 attrNode->detachFromElementWithValue(value);
2525 AttrNodeList* attrNodeList = attrNodeListForElement(this);
2526 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
2527 if (attrNodeList->at(i)->qualifiedName() == attrNode->qualifiedName()) {
2528 attrNodeList->remove(i);
2529 if (attrNodeList->isEmpty())
2530 removeAttrNodeListForElement(this);
2534 ASSERT_NOT_REACHED();
2537 void Element::detachAllAttrNodesFromElement()
2539 AttrNodeList* attrNodeList = attrNodeListForElement(this);
2540 ASSERT(attrNodeList);
2542 for (unsigned i = 0; i < attributeCount(); ++i) {
2543 const Attribute* attribute = attributeItem(i);
2544 if (RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, attribute->name()))
2545 attrNode->detachFromElementWithValue(attribute->value());
2548 removeAttrNodeListForElement(this);
2551 bool Element::willRecalcStyle(StyleChange)
2553 ASSERT(hasCustomCallbacks());
2557 void Element::didRecalcStyle(StyleChange)
2559 ASSERT(hasCustomCallbacks());
2563 PassRefPtr<RenderStyle> Element::customStyleForRenderer()
2565 ASSERT(hasCustomCallbacks());
2569 void Element::cloneAttributesFromElement(const Element& other)
2571 if (hasSyntheticAttrChildNodes())
2572 detachAllAttrNodesFromElement();
2574 other.updateInvalidAttributes();
2575 if (!other.m_attributeData) {
2576 m_attributeData.clear();
2580 const AtomicString& oldID = getIdAttribute();
2581 const AtomicString& newID = other.getIdAttribute();
2583 if (!oldID.isNull() || !newID.isNull())
2584 updateId(oldID, newID);
2586 const AtomicString& oldName = getNameAttribute();
2587 const AtomicString& newName = other.getNameAttribute();
2589 if (!oldName.isNull() || !newName.isNull())
2590 updateName(oldName, newName);
2592 // If 'other' has a mutable ElementAttributeData, convert it to an immutable one so we can share it between both elements.
2593 // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes.
2594 if (other.m_attributeData->isMutable()
2595 && !other.m_attributeData->presentationAttributeStyle()
2596 && (!other.m_attributeData->inlineStyle() || !other.m_attributeData->inlineStyle()->hasCSSOMWrapper()))
2597 const_cast<Element&>(other).m_attributeData = other.m_attributeData->makeImmutableCopy();
2599 if (!other.m_attributeData->isMutable())
2600 m_attributeData = other.m_attributeData;
2602 m_attributeData = other.m_attributeData->makeMutableCopy();
2604 for (unsigned i = 0; i < m_attributeData->length(); ++i) {
2605 const Attribute* attribute = const_cast<const ElementAttributeData*>(m_attributeData.get())->attributeItem(i);
2606 attributeChanged(attribute->name(), attribute->value());
2610 void Element::cloneDataFromElement(const Element& other)
2612 cloneAttributesFromElement(other);
2613 copyNonAttributePropertiesFromElement(other);
2616 void Element::createMutableAttributeData()
2618 if (!m_attributeData)
2619 m_attributeData = ElementAttributeData::create();
2621 m_attributeData = m_attributeData->makeMutableCopy();
2624 void Element::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
2626 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
2627 ContainerNode::reportMemoryUsage(memoryObjectInfo);
2628 info.addMember(m_tagName);
2629 info.addMember(m_attributeData);
2632 } // namespace WebCore