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 "DocumentSharedObjectPool.h"
41 #include "ElementRareData.h"
42 #include "ExceptionCode.h"
43 #include "FlowThreadController.h"
44 #include "FocusController.h"
46 #include "FrameView.h"
47 #include "HTMLCollection.h"
48 #include "HTMLDocument.h"
49 #include "HTMLElement.h"
50 #include "HTMLFormControlsCollection.h"
51 #include "HTMLFrameOwnerElement.h"
52 #include "HTMLLabelElement.h"
53 #include "HTMLNames.h"
54 #include "HTMLOptionsCollection.h"
55 #include "HTMLParserIdioms.h"
56 #include "HTMLTableRowsCollection.h"
57 #include "InsertionPoint.h"
58 #include "InspectorInstrumentation.h"
59 #include "MutationObserverInterestGroup.h"
60 #include "MutationRecord.h"
61 #include "NamedNodeMap.h"
63 #include "NodeRenderStyle.h"
64 #include "NodeRenderingContext.h"
66 #include "PointerLockController.h"
67 #include "RenderRegion.h"
68 #include "RenderView.h"
69 #include "RenderWidget.h"
70 #include "SelectorQuery.h"
72 #include "ShadowRoot.h"
73 #include "StyleResolver.h"
75 #include "TextIterator.h"
76 #include "VoidCallback.h"
77 #include "WebCoreMemoryInstrumentation.h"
78 #include "WebKitAnimationList.h"
79 #include "XMLNSNames.h"
81 #include "htmlediting.h"
82 #include <wtf/BitVector.h>
83 #include <wtf/text/CString.h>
86 #include "SVGElement.h"
92 using namespace HTMLNames;
93 using namespace XMLNames;
95 class StyleResolverParentPusher {
97 StyleResolverParentPusher(Element* parent)
99 , m_pushedStyleResolver(0)
104 if (m_pushedStyleResolver)
106 m_pushedStyleResolver = m_parent->document()->styleResolver();
107 m_pushedStyleResolver->pushParentElement(m_parent);
109 ~StyleResolverParentPusher()
112 if (!m_pushedStyleResolver)
115 // This tells us that our pushed style selector is in a bad state,
116 // so we should just bail out in that scenario.
117 ASSERT(m_pushedStyleResolver == m_parent->document()->styleResolver());
118 if (m_pushedStyleResolver != m_parent->document()->styleResolver())
121 m_pushedStyleResolver->popParentElement(m_parent);
126 StyleResolver* m_pushedStyleResolver;
129 typedef Vector<RefPtr<Attr> > AttrNodeList;
130 typedef HashMap<Element*, OwnPtr<AttrNodeList> > AttrNodeListMap;
132 static AttrNodeListMap& attrNodeListMap()
134 DEFINE_STATIC_LOCAL(AttrNodeListMap, map, ());
138 static AttrNodeList* attrNodeListForElement(Element* element)
140 if (!element->hasSyntheticAttrChildNodes())
142 ASSERT(attrNodeListMap().contains(element));
143 return attrNodeListMap().get(element);
146 static AttrNodeList* ensureAttrNodeListForElement(Element* element)
148 if (element->hasSyntheticAttrChildNodes()) {
149 ASSERT(attrNodeListMap().contains(element));
150 return attrNodeListMap().get(element);
152 ASSERT(!attrNodeListMap().contains(element));
153 element->setHasSyntheticAttrChildNodes(true);
154 AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList));
155 return result.iterator->value.get();
158 static void removeAttrNodeListForElement(Element* element)
160 ASSERT(element->hasSyntheticAttrChildNodes());
161 ASSERT(attrNodeListMap().contains(element));
162 attrNodeListMap().remove(element);
163 element->setHasSyntheticAttrChildNodes(false);
166 static Attr* findAttrNodeInList(AttrNodeList* attrNodeList, const QualifiedName& name)
168 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
169 if (attrNodeList->at(i)->qualifiedName() == name)
170 return attrNodeList->at(i).get();
175 PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document)
177 return adoptRef(new Element(tagName, document, CreateElement));
183 if (document() && document()->renderer()) {
184 // When the document is not destroyed, an element that was part of a named flow
185 // content nodes should have been removed from the content nodes collection
186 // and the inNamedFlow flag reset.
187 ASSERT(!inNamedFlow());
191 if (ElementShadow* elementShadow = shadow()) {
192 elementShadow->removeAllShadowRoots();
193 elementRareData()->m_shadow.clear();
196 if (hasSyntheticAttrChildNodes())
197 detachAllAttrNodesFromElement();
200 inline ElementRareData* Element::elementRareData() const
202 ASSERT(hasRareData());
203 return static_cast<ElementRareData*>(rareData());
206 inline ElementRareData* Element::ensureElementRareData()
208 return static_cast<ElementRareData*>(ensureRareData());
211 OwnPtr<NodeRareData> Element::createRareData()
213 return adoptPtr(new ElementRareData(documentInternal()));
216 DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, blur);
217 DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, error);
218 DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, focus);
219 DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, load);
221 PassRefPtr<Node> Element::cloneNode(bool deep)
223 return deep ? cloneElementWithChildren() : cloneElementWithoutChildren();
226 PassRefPtr<Element> Element::cloneElementWithChildren()
228 RefPtr<Element> clone = cloneElementWithoutChildren();
229 cloneChildNodes(clone.get());
230 return clone.release();
233 PassRefPtr<Element> Element::cloneElementWithoutChildren()
235 RefPtr<Element> clone = cloneElementWithoutAttributesAndChildren();
236 // This will catch HTML elements in the wrong namespace that are not correctly copied.
237 // This is a sanity check as HTML overloads some of the DOM methods.
238 ASSERT(isHTMLElement() == clone->isHTMLElement());
240 clone->cloneDataFromElement(*this);
241 return clone.release();
244 PassRefPtr<Element> Element::cloneElementWithoutAttributesAndChildren()
246 return document()->createElement(tagQName(), false);
249 PassRefPtr<Attr> Element::detachAttribute(size_t index)
251 ASSERT(attributeData());
253 const Attribute* attribute = attributeData()->attributeItem(index);
256 RefPtr<Attr> attrNode = attrIfExists(attribute->name());
258 detachAttrNodeFromElementWithValue(attrNode.get(), attribute->value());
260 attrNode = Attr::create(document(), attribute->name(), attribute->value());
262 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
263 return attrNode.release();
266 void Element::removeAttribute(const QualifiedName& name)
268 if (!attributeData())
271 size_t index = attributeData()->getAttributeItemIndex(name);
272 if (index == notFound)
275 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
278 void Element::setBooleanAttribute(const QualifiedName& name, bool value)
281 setAttribute(name, emptyAtom);
283 removeAttribute(name);
286 NamedNodeMap* Element::attributes() const
288 ensureUpdatedAttributeData();
289 ElementRareData* rareData = const_cast<Element*>(this)->ensureElementRareData();
290 if (NamedNodeMap* attributeMap = rareData->m_attributeMap.get())
293 rareData->m_attributeMap = NamedNodeMap::create(const_cast<Element*>(this));
294 return rareData->m_attributeMap.get();
297 Node::NodeType Element::nodeType() const
302 bool Element::hasAttribute(const QualifiedName& name) const
304 return hasAttributeNS(name.namespaceURI(), name.localName());
307 const AtomicString& Element::getAttribute(const QualifiedName& name) const
309 if (!attributeData())
312 if (UNLIKELY(name == styleAttr && attributeData()->m_styleAttributeIsDirty))
313 updateStyleAttribute();
316 if (UNLIKELY(attributeData()->m_animatedSVGAttributesAreDirty))
317 updateAnimatedSVGAttribute(name);
320 if (const Attribute* attribute = getAttributeItem(name))
321 return attribute->value();
325 void Element::scrollIntoView(bool alignToTop)
327 document()->updateLayoutIgnorePendingStylesheets();
332 LayoutRect bounds = boundingBox();
333 // Align to the top / bottom and to the closest edge.
335 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
337 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
340 void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
342 document()->updateLayoutIgnorePendingStylesheets();
347 LayoutRect bounds = boundingBox();
349 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
351 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
354 void Element::scrollByUnits(int units, ScrollGranularity granularity)
356 document()->updateLayoutIgnorePendingStylesheets();
361 if (!renderer()->hasOverflowClip())
364 ScrollDirection direction = ScrollDown;
366 direction = ScrollUp;
369 Node* stopNode = this;
370 toRenderBox(renderer())->scroll(direction, granularity, units, &stopNode);
373 void Element::scrollByLines(int lines)
375 scrollByUnits(lines, ScrollByLine);
378 void Element::scrollByPages(int pages)
380 scrollByUnits(pages, ScrollByPage);
383 static float localZoomForRenderer(RenderObject* renderer)
385 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
386 // other out, but the alternative is that we'd have to crawl up the whole render tree every
387 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
388 float zoomFactor = 1;
389 if (renderer->style()->effectiveZoom() != 1) {
390 // Need to find the nearest enclosing RenderObject that set up
391 // a differing zoom, and then we divide our result by it to eliminate the zoom.
392 RenderObject* prev = renderer;
393 for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) {
394 if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) {
395 zoomFactor = prev->style()->zoom();
400 if (prev->isRenderView())
401 zoomFactor = prev->style()->zoom();
406 static int adjustForLocalZoom(LayoutUnit value, RenderObject* renderer)
408 float zoomFactor = localZoomForRenderer(renderer);
411 #if ENABLE(SUBPIXEL_LAYOUT)
412 return lroundf(value / zoomFactor);
414 // Needed because computeLengthInt truncates (rather than rounds) when scaling up.
417 return static_cast<int>(value / zoomFactor);
421 int Element::offsetLeft()
423 document()->updateLayoutIgnorePendingStylesheets();
424 if (RenderBoxModelObject* renderer = renderBoxModelObject())
425 return adjustForLocalZoom(renderer->pixelSnappedOffsetLeft(), renderer);
429 int Element::offsetTop()
431 document()->updateLayoutIgnorePendingStylesheets();
432 if (RenderBoxModelObject* renderer = renderBoxModelObject())
433 return adjustForLocalZoom(renderer->pixelSnappedOffsetTop(), renderer);
437 int Element::offsetWidth()
439 document()->updateLayoutIgnorePendingStylesheets();
440 if (RenderBoxModelObject* renderer = renderBoxModelObject())
441 return adjustForAbsoluteZoom(renderer->pixelSnappedOffsetWidth(), renderer);
445 int Element::offsetHeight()
447 document()->updateLayoutIgnorePendingStylesheets();
448 if (RenderBoxModelObject* renderer = renderBoxModelObject())
449 return adjustForAbsoluteZoom(renderer->pixelSnappedOffsetHeight(), renderer);
453 Element* Element::offsetParent()
455 document()->updateLayoutIgnorePendingStylesheets();
456 if (RenderObject* rend = renderer())
457 if (RenderObject* offsetParent = rend->offsetParent())
458 return static_cast<Element*>(offsetParent->node());
462 int Element::clientLeft()
464 document()->updateLayoutIgnorePendingStylesheets();
466 if (RenderBox* renderer = renderBox())
467 return adjustForAbsoluteZoom(roundToInt(renderer->clientLeft()), renderer);
471 int Element::clientTop()
473 document()->updateLayoutIgnorePendingStylesheets();
475 if (RenderBox* renderer = renderBox())
476 return adjustForAbsoluteZoom(roundToInt(renderer->clientTop()), renderer);
480 int Element::clientWidth()
482 document()->updateLayoutIgnorePendingStylesheets();
484 // When in strict mode, clientWidth for the document element should return the width of the containing frame.
485 // When in quirks mode, clientWidth for the body element should return the width of the containing frame.
486 bool inQuirksMode = document()->inQuirksMode();
487 if ((!inQuirksMode && document()->documentElement() == this) ||
488 (inQuirksMode && isHTMLElement() && document()->body() == this)) {
489 if (FrameView* view = document()->view()) {
490 if (RenderView* renderView = document()->renderView())
491 return adjustForAbsoluteZoom(view->layoutWidth(), renderView);
495 if (RenderBox* renderer = renderBox())
496 return adjustForAbsoluteZoom(renderer->pixelSnappedClientWidth(), renderer);
500 int Element::clientHeight()
502 document()->updateLayoutIgnorePendingStylesheets();
504 // When in strict mode, clientHeight for the document element should return the height of the containing frame.
505 // When in quirks mode, clientHeight for the body element should return the height of the containing frame.
506 bool inQuirksMode = document()->inQuirksMode();
508 if ((!inQuirksMode && document()->documentElement() == this) ||
509 (inQuirksMode && isHTMLElement() && document()->body() == this)) {
510 if (FrameView* view = document()->view()) {
511 if (RenderView* renderView = document()->renderView())
512 return adjustForAbsoluteZoom(view->layoutHeight(), renderView);
516 if (RenderBox* renderer = renderBox())
517 return adjustForAbsoluteZoom(renderer->pixelSnappedClientHeight(), renderer);
521 int Element::scrollLeft()
523 document()->updateLayoutIgnorePendingStylesheets();
524 if (RenderBox* rend = renderBox())
525 return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
529 int Element::scrollTop()
531 document()->updateLayoutIgnorePendingStylesheets();
532 if (RenderBox* rend = renderBox())
533 return adjustForAbsoluteZoom(rend->scrollTop(), rend);
537 void Element::setScrollLeft(int newLeft)
539 document()->updateLayoutIgnorePendingStylesheets();
540 if (RenderBox* rend = renderBox())
541 rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
544 void Element::setScrollTop(int newTop)
546 document()->updateLayoutIgnorePendingStylesheets();
547 if (RenderBox* rend = renderBox())
548 rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
551 int Element::scrollWidth()
553 document()->updateLayoutIgnorePendingStylesheets();
554 if (RenderBox* rend = renderBox())
555 return adjustForAbsoluteZoom(rend->scrollWidth(), rend);
559 int Element::scrollHeight()
561 document()->updateLayoutIgnorePendingStylesheets();
562 if (RenderBox* rend = renderBox())
563 return adjustForAbsoluteZoom(rend->scrollHeight(), rend);
567 IntRect Element::boundsInRootViewSpace()
569 document()->updateLayoutIgnorePendingStylesheets();
571 FrameView* view = document()->view();
575 Vector<FloatQuad> quads;
577 if (isSVGElement() && renderer()) {
578 // Get the bounding rectangle from the SVG model.
579 SVGElement* svgElement = static_cast<SVGElement*>(this);
581 if (svgElement->getBoundingBox(localRect))
582 quads.append(renderer()->localToAbsoluteQuad(localRect));
586 // Get the bounding rectangle from the box model.
587 if (renderBoxModelObject())
588 renderBoxModelObject()->absoluteQuads(quads);
594 IntRect result = quads[0].enclosingBoundingBox();
595 for (size_t i = 1; i < quads.size(); ++i)
596 result.unite(quads[i].enclosingBoundingBox());
598 result = view->contentsToRootView(result);
602 PassRefPtr<ClientRectList> Element::getClientRects()
604 document()->updateLayoutIgnorePendingStylesheets();
606 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject();
607 if (!renderBoxModelObject)
608 return ClientRectList::create();
610 // FIXME: Handle SVG elements.
611 // FIXME: Handle table/inline-table with a caption.
613 Vector<FloatQuad> quads;
614 renderBoxModelObject->absoluteQuads(quads);
615 document()->adjustFloatQuadsForScrollAndAbsoluteZoomAndFrameScale(quads, renderBoxModelObject);
616 return ClientRectList::create(quads);
619 PassRefPtr<ClientRect> Element::getBoundingClientRect()
621 document()->updateLayoutIgnorePendingStylesheets();
623 Vector<FloatQuad> quads;
625 if (isSVGElement() && renderer() && !renderer()->isSVGRoot()) {
626 // Get the bounding rectangle from the SVG model.
627 SVGElement* svgElement = static_cast<SVGElement*>(this);
629 if (svgElement->getBoundingBox(localRect))
630 quads.append(renderer()->localToAbsoluteQuad(localRect));
634 // Get the bounding rectangle from the box model.
635 if (renderBoxModelObject())
636 renderBoxModelObject()->absoluteQuads(quads);
640 return ClientRect::create();
642 FloatRect result = quads[0].boundingBox();
643 for (size_t i = 1; i < quads.size(); ++i)
644 result.unite(quads[i].boundingBox());
646 document()->adjustFloatRectForScrollAndAbsoluteZoomAndFrameScale(result, renderer());
647 return ClientRect::create(result);
650 IntRect Element::screenRect() const
654 // FIXME: this should probably respect transforms
655 return document()->view()->contentsToScreen(renderer()->absoluteBoundingBoxRectIgnoringTransforms());
658 static inline bool shouldIgnoreAttributeCase(const Element* e)
660 return e && e->document()->isHTMLDocument() && e->isHTMLElement();
663 const AtomicString& Element::getAttribute(const AtomicString& name) const
665 if (!attributeData())
668 bool ignoreCase = shouldIgnoreAttributeCase(this);
670 // Update the 'style' attribute if it's invalid and being requested:
671 if (attributeData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(name, styleAttr.localName(), ignoreCase))
672 updateStyleAttribute();
675 if (attributeData()->m_animatedSVGAttributesAreDirty) {
676 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
677 updateAnimatedSVGAttribute(QualifiedName(nullAtom, name, nullAtom));
681 if (const Attribute* attribute = attributeData()->getAttributeItem(name, ignoreCase))
682 return attribute->value();
686 const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
688 return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
691 void Element::setAttribute(const AtomicString& name, const AtomicString& value, ExceptionCode& ec)
693 if (!Document::isValidName(name)) {
694 ec = INVALID_CHARACTER_ERR;
698 const AtomicString& localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
700 size_t index = ensureUpdatedAttributeData()->getAttributeItemIndex(localName, false);
701 const QualifiedName& qName = index != notFound ? attributeItem(index)->name() : QualifiedName(nullAtom, localName, nullAtom);
702 setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute);
705 void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
707 setAttributeInternal(ensureUpdatedAttributeData()->getAttributeItemIndex(name), name, value, NotInSynchronizationOfLazyAttribute);
710 void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value)
712 setAttributeInternal(mutableAttributeData()->getAttributeItemIndex(name), name, value, InSynchronizationOfLazyAttribute);
715 inline void Element::setAttributeInternal(size_t index, const QualifiedName& name, const AtomicString& newValue, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
717 if (newValue.isNull()) {
718 if (index != notFound)
719 removeAttributeInternal(index, inSynchronizationOfLazyAttribute);
723 if (index == notFound) {
724 addAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute);
728 if (!inSynchronizationOfLazyAttribute)
729 willModifyAttribute(name, attributeItem(index)->value(), newValue);
731 if (newValue != attributeItem(index)->value()) {
732 // If there is an Attr node hooked to this attribute, the Attr::setValue() call below
733 // will write into the ElementAttributeData.
734 // FIXME: Refactor this so it makes some sense.
735 if (RefPtr<Attr> attrNode = attrIfExists(name))
736 attrNode->setValue(newValue);
738 mutableAttributeData()->attributeItem(index)->setValue(newValue);
741 if (!inSynchronizationOfLazyAttribute)
742 didModifyAttribute(name, newValue);
745 static inline AtomicString makeIdForStyleResolution(const AtomicString& value, bool inQuirksMode)
748 return value.lower();
752 static bool checkNeedsStyleInvalidationForIdChange(const AtomicString& oldId, const AtomicString& newId, StyleResolver* styleResolver)
754 ASSERT(newId != oldId);
755 if (!oldId.isEmpty() && styleResolver->hasSelectorForId(oldId))
757 if (!newId.isEmpty() && styleResolver->hasSelectorForId(newId))
762 void Element::attributeChanged(const QualifiedName& name, const AtomicString& newValue)
764 if (ElementShadow* parentElementShadow = shadowOfParentForDistribution(this)) {
765 if (shouldInvalidateDistributionWhenAttributeChanged(parentElementShadow, name, newValue))
766 parentElementShadow->invalidateDistribution();
769 parseAttribute(name, newValue);
771 document()->incDOMTreeVersion();
773 StyleResolver* styleResolver = document()->styleResolverIfExists();
774 bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < FullStyleChange;
775 bool shouldInvalidateStyle = false;
777 if (isIdAttributeName(name)) {
778 AtomicString oldId = attributeData()->idForStyleResolution();
779 AtomicString newId = makeIdForStyleResolution(newValue, document()->inQuirksMode());
780 if (newId != oldId) {
781 attributeData()->setIdForStyleResolution(newId);
782 shouldInvalidateStyle = testShouldInvalidateStyle && checkNeedsStyleInvalidationForIdChange(oldId, newId, styleResolver);
784 } else if (name == classAttr)
785 classAttributeChanged(newValue);
786 else if (name == HTMLNames::nameAttr)
787 setHasName(!newValue.isNull());
788 else if (name == HTMLNames::pseudoAttr)
789 shouldInvalidateStyle |= testShouldInvalidateStyle && isInShadowTree();
791 shouldInvalidateStyle |= testShouldInvalidateStyle && styleResolver->hasSelectorForAttribute(name.localName());
793 invalidateNodeListCachesInAncestors(&name, this);
795 if (shouldInvalidateStyle)
796 setNeedsStyleRecalc();
798 if (AXObjectCache::accessibilityEnabled())
799 document()->axObjectCache()->handleAttributeChanged(name, this);
802 template <typename CharacterType>
803 static inline bool classStringHasClassName(const CharacterType* characters, unsigned length)
809 if (isNotHTMLSpace(characters[i]))
812 } while (i < length);
817 static inline bool classStringHasClassName(const AtomicString& newClassString)
819 unsigned length = newClassString.length();
824 if (newClassString.is8Bit())
825 return classStringHasClassName(newClassString.characters8(), length);
826 return classStringHasClassName(newClassString.characters16(), length);
829 template<typename Checker>
830 static bool checkSelectorForClassChange(const SpaceSplitString& changedClasses, const Checker& checker)
832 unsigned changedSize = changedClasses.size();
833 for (unsigned i = 0; i < changedSize; ++i) {
834 if (checker.hasSelectorForClass(changedClasses[i]))
840 template<typename Checker>
841 static bool checkSelectorForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, const Checker& checker)
843 unsigned oldSize = oldClasses.size();
845 return checkSelectorForClassChange(newClasses, checker);
846 BitVector remainingClassBits;
847 remainingClassBits.ensureSize(oldSize);
848 // Class vectors tend to be very short. This is faster than using a hash table.
849 unsigned newSize = newClasses.size();
850 for (unsigned i = 0; i < newSize; ++i) {
851 for (unsigned j = 0; j < oldSize; ++j) {
852 if (newClasses[i] == oldClasses[j]) {
853 remainingClassBits.quickSet(j);
857 if (checker.hasSelectorForClass(newClasses[i]))
860 for (unsigned i = 0; i < oldSize; ++i) {
861 // If the bit is not set the the corresponding class has been removed.
862 if (remainingClassBits.quickGet(i))
864 if (checker.hasSelectorForClass(oldClasses[i]))
870 void Element::classAttributeChanged(const AtomicString& newClassString)
872 StyleResolver* styleResolver = document()->styleResolverIfExists();
873 bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < FullStyleChange;
874 bool shouldInvalidateStyle = false;
876 if (classStringHasClassName(newClassString)) {
877 const ElementAttributeData* attributeData = ensureAttributeData();
878 const bool shouldFoldCase = document()->inQuirksMode();
879 const SpaceSplitString oldClasses = attributeData->classNames();
881 attributeData->setClass(newClassString, shouldFoldCase);
883 const SpaceSplitString& newClasses = attributeData->classNames();
884 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, newClasses, *styleResolver);
885 } else if (const ElementAttributeData* attributeData = this->attributeData()) {
886 const SpaceSplitString& oldClasses = attributeData->classNames();
887 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, *styleResolver);
889 attributeData->clearClass();
892 if (DOMTokenList* classList = optionalClassList())
893 static_cast<ClassList*>(classList)->reset(newClassString);
895 if (shouldInvalidateStyle)
896 setNeedsStyleRecalc();
899 bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
901 ASSERT(elementShadow);
902 elementShadow->ensureSelectFeatureSetCollected();
904 if (isIdAttributeName(name)) {
905 AtomicString oldId = attributeData()->idForStyleResolution();
906 AtomicString newId = makeIdForStyleResolution(newValue, document()->inQuirksMode());
907 if (newId != oldId) {
908 if (!oldId.isEmpty() && elementShadow->selectRuleFeatureSet().hasSelectorForId(oldId))
910 if (!newId.isEmpty() && elementShadow->selectRuleFeatureSet().hasSelectorForId(newId))
915 if (name == HTMLNames::classAttr) {
916 const AtomicString& newClassString = newValue;
917 if (classStringHasClassName(newClassString)) {
918 const ElementAttributeData* attributeData = ensureAttributeData();
919 const bool shouldFoldCase = document()->inQuirksMode();
920 const SpaceSplitString& oldClasses = attributeData->classNames();
921 const SpaceSplitString newClasses(newClassString, shouldFoldCase);
922 if (checkSelectorForClassChange(oldClasses, newClasses, elementShadow->selectRuleFeatureSet()))
924 } else if (const ElementAttributeData* attributeData = this->attributeData()) {
925 const SpaceSplitString& oldClasses = attributeData->classNames();
926 if (checkSelectorForClassChange(oldClasses, elementShadow->selectRuleFeatureSet()))
931 return elementShadow->selectRuleFeatureSet().hasSelectorForAttribute(name.localName());
934 // Returns true is the given attribute is an event handler.
935 // We consider an event handler any attribute that begins with "on".
936 // It is a simple solution that has the advantage of not requiring any
937 // code or configuration change if a new event handler is defined.
939 static bool isEventHandlerAttribute(const QualifiedName& name)
941 return name.namespaceURI().isNull() && name.localName().startsWith("on");
944 // FIXME: Share code with Element::isURLAttribute.
945 static bool isAttributeToRemove(const QualifiedName& name, const AtomicString& value)
947 return (name.localName() == hrefAttr.localName() || name.localName() == nohrefAttr.localName()
948 || name == srcAttr || name == actionAttr || name == formactionAttr) && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(value));
951 void Element::parserSetAttributes(const Vector<Attribute>& attributeVector, FragmentScriptingPermission scriptingPermission)
953 ASSERT(!inDocument());
954 ASSERT(!parentNode());
956 ASSERT(!m_attributeData);
958 if (attributeVector.isEmpty())
961 Vector<Attribute> filteredAttributes = attributeVector;
963 // If the element is created as result of a paste or drag-n-drop operation
964 // we want to remove all the script and event handlers.
965 if (scriptingPermission == DisallowScriptingContent) {
967 while (i < filteredAttributes.size()) {
968 Attribute& attribute = filteredAttributes[i];
969 if (isEventHandlerAttribute(attribute.name())) {
970 filteredAttributes.remove(i);
974 if (isAttributeToRemove(attribute.name(), attribute.value()))
975 attribute.setValue(emptyAtom);
980 if (document() && document()->sharedObjectPool())
981 m_attributeData = document()->sharedObjectPool()->cachedImmutableElementAttributeData(filteredAttributes);
983 m_attributeData = ElementAttributeData::createImmutable(filteredAttributes);
985 // Iterate over the set of attributes we already have on the stack in case
986 // attributeChanged mutates m_attributeData.
987 // FIXME: Find a way so we don't have to do this.
988 for (unsigned i = 0; i < filteredAttributes.size(); ++i)
989 attributeChanged(filteredAttributes[i].name(), filteredAttributes[i].value());
992 bool Element::hasAttributes() const
994 updateInvalidAttributes();
995 return attributeData() && attributeData()->length();
998 bool Element::hasEquivalentAttributes(const Element* other) const
1000 const ElementAttributeData* attributeData = updatedAttributeData();
1001 const ElementAttributeData* otherAttributeData = other->updatedAttributeData();
1002 if (attributeData == otherAttributeData)
1005 return attributeData->isEquivalent(otherAttributeData);
1006 if (otherAttributeData)
1007 return otherAttributeData->isEquivalent(attributeData);
1011 String Element::nodeName() const
1013 return m_tagName.toString();
1016 String Element::nodeNamePreservingCase() const
1018 return m_tagName.toString();
1021 void Element::setPrefix(const AtomicString& prefix, ExceptionCode& ec)
1024 checkSetPrefix(prefix, ec);
1028 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
1031 KURL Element::baseURI() const
1033 const AtomicString& baseAttribute = getAttribute(baseAttr);
1034 KURL base(KURL(), baseAttribute);
1035 if (!base.protocol().isEmpty())
1038 ContainerNode* parent = parentNode();
1042 const KURL& parentBase = parent->baseURI();
1043 if (parentBase.isNull())
1046 return KURL(parentBase, baseAttribute);
1049 const QualifiedName& Element::imageSourceAttributeName() const
1054 bool Element::rendererIsNeeded(const NodeRenderingContext& context)
1056 return context.style()->display() != NONE;
1059 RenderObject* Element::createRenderer(RenderArena*, RenderStyle* style)
1061 return RenderObject::createObject(this, style);
1064 bool Element::wasChangedSinceLastFormControlChangeEvent() const
1069 void Element::setChangedSinceLastFormControlChangeEvent(bool)
1073 Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertionPoint)
1075 // need to do superclass processing first so inDocument() is true
1076 // by the time we reach updateId
1077 ContainerNode::insertedInto(insertionPoint);
1079 #if ENABLE(FULLSCREEN_API)
1080 if (containsFullScreenElement() && parentElement() && !parentElement()->containsFullScreenElement())
1081 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
1084 if (!insertionPoint->inDocument())
1085 return InsertionDone;
1087 const AtomicString& idValue = getIdAttribute();
1088 if (!idValue.isNull())
1089 updateId(nullAtom, idValue);
1091 const AtomicString& nameValue = getNameAttribute();
1092 if (!nameValue.isNull())
1093 updateName(nullAtom, nameValue);
1095 if (hasTagName(labelTag)) {
1096 TreeScope* scope = treeScope();
1097 if (scope->shouldCacheLabelsByForAttribute())
1098 updateLabel(scope, nullAtom, fastGetAttribute(forAttr));
1101 return InsertionDone;
1104 void Element::removedFrom(ContainerNode* insertionPoint)
1106 #if ENABLE(DIALOG_ELEMENT)
1107 setIsInTopLayer(false);
1109 #if ENABLE(FULLSCREEN_API)
1110 if (containsFullScreenElement())
1111 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
1113 #if ENABLE(POINTER_LOCK)
1114 if (document()->page())
1115 document()->page()->pointerLockController()->elementRemoved(this);
1118 setSavedLayerScrollOffset(IntSize());
1120 if (insertionPoint->inDocument()) {
1121 const AtomicString& idValue = getIdAttribute();
1122 if (!idValue.isNull() && inDocument())
1123 updateId(insertionPoint->treeScope(), idValue, nullAtom);
1125 const AtomicString& nameValue = getNameAttribute();
1126 if (!nameValue.isNull())
1127 updateName(nameValue, nullAtom);
1129 if (hasTagName(labelTag)) {
1130 TreeScope* treeScope = insertionPoint->treeScope();
1131 if (treeScope->shouldCacheLabelsByForAttribute())
1132 updateLabel(treeScope, fastGetAttribute(forAttr), nullAtom);
1136 ContainerNode::removedFrom(insertionPoint);
1139 void Element::createRendererIfNeeded()
1141 NodeRenderingContext(this).createRendererForElementIfNeeded();
1144 void Element::attach()
1146 suspendPostAttachCallbacks();
1148 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1149 createRendererIfNeeded();
1151 StyleResolverParentPusher parentPusher(this);
1153 if (parentElement() && parentElement()->isInCanvasSubtree())
1154 setIsInCanvasSubtree(true);
1156 // When a shadow root exists, it does the work of attaching the children.
1157 if (ElementShadow* shadow = this->shadow()) {
1158 parentPusher.push();
1162 parentPusher.push();
1164 ContainerNode::attach();
1166 if (hasRareData()) {
1167 ElementRareData* data = elementRareData();
1168 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
1169 if (isFocusable() && document()->focusedNode() == this)
1170 document()->updateFocusAppearanceSoon(false /* don't restore selection */);
1171 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1175 resumePostAttachCallbacks();
1178 void Element::unregisterNamedFlowContentNode()
1180 if (document()->cssRegionsEnabled() && inNamedFlow() && document()->renderView())
1181 document()->renderView()->flowThreadController()->unregisterNamedFlowContentNode(this);
1184 void Element::detach()
1186 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1187 unregisterNamedFlowContentNode();
1188 cancelFocusAppearanceUpdate();
1189 if (hasRareData()) {
1190 ElementRareData* data = elementRareData();
1191 data->setIsInCanvasSubtree(false);
1192 data->resetComputedStyle();
1193 data->resetDynamicRestyleObservations();
1196 if (ElementShadow* shadow = this->shadow()) {
1197 detachChildrenIfNeeded();
1200 ContainerNode::detach();
1203 bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle)
1205 ASSERT(currentStyle == renderStyle());
1211 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles();
1212 if (!pseudoStyleCache)
1215 size_t cacheSize = pseudoStyleCache->size();
1216 for (size_t i = 0; i < cacheSize; ++i) {
1217 RefPtr<RenderStyle> newPseudoStyle;
1218 PseudoId pseudoId = pseudoStyleCache->at(i)->styleType();
1219 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
1220 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle);
1222 newPseudoStyle = renderer()->getUncachedPseudoStyle(pseudoId, newStyle, newStyle);
1223 if (!newPseudoStyle)
1225 if (*newPseudoStyle != *pseudoStyleCache->at(i)) {
1226 if (pseudoId < FIRST_INTERNAL_PSEUDOID)
1227 newStyle->setHasPseudoStyle(pseudoId);
1228 newStyle->addCachedPseudoStyle(newPseudoStyle);
1229 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
1230 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
1231 // is needed, but for now just assume a layout will be required. The diff code
1232 // in RenderObject::setStyle would need to be factored out so that it could be reused.
1233 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
1241 PassRefPtr<RenderStyle> Element::styleForRenderer()
1243 if (hasCustomCallbacks()) {
1244 if (RefPtr<RenderStyle> style = customStyleForRenderer())
1245 return style.release();
1248 return document()->styleResolver()->styleForElement(this);
1251 void Element::recalcStyle(StyleChange change)
1253 if (hasCustomCallbacks()) {
1254 if (!willRecalcStyle(change))
1258 // Ref currentStyle in case it would otherwise be deleted when setting the new style in the renderer.
1259 RefPtr<RenderStyle> currentStyle(renderStyle());
1260 bool hasParentStyle = parentNodeForRenderingAndStyle() ? static_cast<bool>(parentNodeForRenderingAndStyle()->renderStyle()) : false;
1261 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
1262 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
1264 if ((change > NoChange || needsStyleRecalc())) {
1266 elementRareData()->resetComputedStyle();
1268 if (hasParentStyle && (change >= Inherit || needsStyleRecalc())) {
1269 RefPtr<RenderStyle> newStyle = styleForRenderer();
1270 StyleChange ch = Node::diff(currentStyle.get(), newStyle.get(), document());
1271 if (ch == Detach || !currentStyle) {
1272 // FIXME: The style gets computed twice by calling attach. We could do better if we passed the style along.
1274 // attach recalculates the style for all children. No need to do it twice.
1275 clearNeedsStyleRecalc();
1276 clearChildNeedsStyleRecalc();
1278 if (hasCustomCallbacks())
1279 didRecalcStyle(change);
1283 if (RenderObject* renderer = this->renderer()) {
1284 if (ch != NoChange || pseudoStyleCacheIsInvalid(currentStyle.get(), newStyle.get()) || (change == Force && renderer->requiresForcedStyleRecalcPropagation()) || styleChangeType() == SyntheticStyleChange)
1285 renderer->setAnimatableStyle(newStyle.get());
1286 else if (needsStyleRecalc()) {
1287 // Although no change occurred, we use the new style so that the cousin style sharing code won't get
1288 // fooled into believing this style is the same.
1289 renderer->setStyleInternal(newStyle.get());
1293 // 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
1294 // 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).
1295 if (document()->styleSheetCollection()->usesRemUnits() && document()->documentElement() == this && ch != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize()) {
1296 // Cached RenderStyles may depend on the rem units.
1297 document()->styleResolver()->invalidateMatchedPropertiesCache();
1301 if (change != Force) {
1302 if (styleChangeType() >= FullStyleChange)
1308 StyleResolverParentPusher parentPusher(this);
1310 // FIXME: This does not care about sibling combinators. Will be necessary in XBL2 world.
1311 if (ElementShadow* shadow = this->shadow()) {
1312 if (change >= Inherit || shadow->childNeedsStyleRecalc() || shadow->needsStyleRecalc()) {
1313 parentPusher.push();
1314 shadow->recalcStyle(change);
1318 // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
1319 // For now we will just worry about the common case, since it's a lot trickier to get the second case right
1320 // without doing way too much re-resolution.
1321 bool forceCheckOfNextElementSibling = false;
1322 bool forceCheckOfAnyElementSibling = false;
1323 for (Node *n = firstChild(); n; n = n->nextSibling()) {
1324 if (n->isTextNode()) {
1325 toText(n)->recalcTextStyle(change);
1328 if (!n->isElementNode())
1330 Element* element = static_cast<Element*>(n);
1331 bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() == FullStyleChange;
1332 if ((forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling))
1333 element->setNeedsStyleRecalc();
1334 if (change >= Inherit || element->childNeedsStyleRecalc() || element->needsStyleRecalc()) {
1335 parentPusher.push();
1336 element->recalcStyle(change);
1338 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
1339 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
1342 clearNeedsStyleRecalc();
1343 clearChildNeedsStyleRecalc();
1345 if (hasCustomCallbacks())
1346 didRecalcStyle(change);
1349 ElementShadow* Element::shadow() const
1354 return elementRareData()->m_shadow.get();
1357 ElementShadow* Element::ensureShadow()
1359 if (ElementShadow* shadow = ensureElementRareData()->m_shadow.get())
1362 ElementRareData* data = elementRareData();
1363 data->m_shadow = adoptPtr(new ElementShadow());
1364 return data->m_shadow.get();
1367 PassRefPtr<ShadowRoot> Element::createShadowRoot(ExceptionCode& ec)
1369 return ShadowRoot::create(this, ec);
1372 ShadowRoot* Element::userAgentShadowRoot() const
1374 if (ElementShadow* elementShadow = shadow()) {
1375 if (ShadowRoot* shadowRoot = elementShadow->oldestShadowRoot()) {
1376 ASSERT(shadowRoot->type() == ShadowRoot::UserAgentShadowRoot);
1384 const AtomicString& Element::shadowPseudoId() const
1389 bool Element::childTypeAllowed(NodeType type) const
1395 case PROCESSING_INSTRUCTION_NODE:
1396 case CDATA_SECTION_NODE:
1397 case ENTITY_REFERENCE_NODE:
1405 static void checkForEmptyStyleChange(Element* element, RenderStyle* style)
1407 if (!style && !element->styleAffectedByEmpty())
1410 if (!style || (element->styleAffectedByEmpty() && (!style->emptyState() || element->hasChildNodes())))
1411 element->setNeedsStyleRecalc();
1414 static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
1415 Node* beforeChange, Node* afterChange, int childCountDelta)
1418 checkForEmptyStyleChange(e, style);
1420 if (!style || (e->needsStyleRecalc() && e->childrenAffectedByPositionalRules()))
1423 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1424 // In the DOM case, we only need to do something if |afterChange| is not 0.
1425 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
1426 if (e->childrenAffectedByFirstChildRules() && afterChange) {
1427 // Find our new first child.
1428 Node* newFirstChild = 0;
1429 for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {};
1431 // Find the first element node following |afterChange|
1432 Node* firstElementAfterInsertion = 0;
1433 for (firstElementAfterInsertion = afterChange;
1434 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
1435 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
1437 // This is the insert/append case.
1438 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertion && firstElementAfterInsertion->attached() &&
1439 firstElementAfterInsertion->renderStyle() && firstElementAfterInsertion->renderStyle()->firstChildState())
1440 firstElementAfterInsertion->setNeedsStyleRecalc();
1442 // We also have to handle node removal.
1443 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChild->renderStyle() || !newFirstChild->renderStyle()->firstChildState()))
1444 newFirstChild->setNeedsStyleRecalc();
1447 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1448 // In the DOM case, we only need to do something if |afterChange| is not 0.
1449 if (e->childrenAffectedByLastChildRules() && beforeChange) {
1450 // Find our new last child.
1451 Node* newLastChild = 0;
1452 for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {};
1454 // Find the last element node going backwards from |beforeChange|
1455 Node* lastElementBeforeInsertion = 0;
1456 for (lastElementBeforeInsertion = beforeChange;
1457 lastElementBeforeInsertion && !lastElementBeforeInsertion->isElementNode();
1458 lastElementBeforeInsertion = lastElementBeforeInsertion->previousSibling()) {};
1460 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertion && lastElementBeforeInsertion->attached() &&
1461 lastElementBeforeInsertion->renderStyle() && lastElementBeforeInsertion->renderStyle()->lastChildState())
1462 lastElementBeforeInsertion->setNeedsStyleRecalc();
1464 // 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
1466 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChild->renderStyle() || !newLastChild->renderStyle()->lastChildState()))
1467 newLastChild->setNeedsStyleRecalc();
1470 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
1471 // that could be affected by this DOM change.
1472 if (e->childrenAffectedByDirectAdjacentRules() && afterChange) {
1473 Node* firstElementAfterInsertion = 0;
1474 for (firstElementAfterInsertion = afterChange;
1475 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
1476 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
1477 if (firstElementAfterInsertion && firstElementAfterInsertion->attached())
1478 firstElementAfterInsertion->setNeedsStyleRecalc();
1481 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
1482 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1483 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
1485 // |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.
1486 // 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
1487 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
1488 if ((e->childrenAffectedByForwardPositionalRules() && afterChange)
1489 || (e->childrenAffectedByBackwardPositionalRules() && beforeChange))
1490 e->setNeedsStyleRecalc();
1493 void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
1495 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
1496 if (changedByParser)
1497 checkForEmptyStyleChange(this, renderStyle());
1499 checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
1501 if (ElementShadow * shadow = this->shadow())
1502 shadow->invalidateDistribution();
1505 void Element::beginParsingChildren()
1507 clearIsParsingChildrenFinished();
1508 StyleResolver* styleResolver = document()->styleResolverIfExists();
1509 if (styleResolver && attached())
1510 styleResolver->pushParentElement(this);
1513 void Element::finishParsingChildren()
1515 ContainerNode::finishParsingChildren();
1516 setIsParsingChildrenFinished();
1517 checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
1518 if (StyleResolver* styleResolver = document()->styleResolverIfExists())
1519 styleResolver->popParentElement(this);
1523 void Element::formatForDebugger(char* buffer, unsigned length) const
1525 StringBuilder result;
1528 result.append(nodeName());
1530 s = getIdAttribute();
1531 if (s.length() > 0) {
1532 if (result.length() > 0)
1533 result.appendLiteral("; ");
1534 result.appendLiteral("id=");
1538 s = getAttribute(classAttr);
1539 if (s.length() > 0) {
1540 if (result.length() > 0)
1541 result.appendLiteral("; ");
1542 result.appendLiteral("class=");
1546 strncpy(buffer, result.toString().utf8().data(), length - 1);
1550 PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionCode& ec)
1553 ec = TYPE_MISMATCH_ERR;
1557 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName());
1558 if (oldAttrNode.get() == attrNode)
1559 return attrNode; // This Attr is already attached to the element.
1561 // INUSE_ATTRIBUTE_ERR: Raised if node is an Attr that is already an attribute of another Element object.
1562 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
1563 if (attrNode->ownerElement()) {
1564 ec = INUSE_ATTRIBUTE_ERR;
1568 updateInvalidAttributes();
1569 ElementAttributeData* attributeData = mutableAttributeData();
1571 size_t index = attributeData->getAttributeItemIndex(attrNode->qualifiedName());
1572 if (index != notFound) {
1574 detachAttrNodeFromElementWithValue(oldAttrNode.get(), attributeData->attributeItem(index)->value());
1576 oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), attributeData->attributeItem(index)->value());
1579 setAttributeInternal(index, attrNode->qualifiedName(), attrNode->value(), NotInSynchronizationOfLazyAttribute);
1581 attrNode->attachToElement(this);
1582 ensureAttrNodeListForElement(this)->append(attrNode);
1584 return oldAttrNode.release();
1587 PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionCode& ec)
1589 return setAttributeNode(attr, ec);
1592 PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec)
1595 ec = TYPE_MISMATCH_ERR;
1598 if (attr->ownerElement() != this) {
1603 ASSERT(document() == attr->document());
1605 const ElementAttributeData* attributeData = updatedAttributeData();
1606 ASSERT(attributeData);
1608 size_t index = attributeData->getAttributeItemIndex(attr->qualifiedName());
1609 if (index == notFound) {
1614 return detachAttribute(index);
1617 bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionCode& ec)
1619 String prefix, localName;
1620 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec))
1624 QualifiedName qName(prefix, localName, namespaceURI);
1626 if (!Document::hasValidNamespaceForAttributes(qName)) {
1635 void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode& ec)
1637 QualifiedName parsedName = anyName;
1638 if (!parseAttributeName(parsedName, namespaceURI, qualifiedName, ec))
1640 setAttribute(parsedName, value);
1643 void Element::removeAttributeInternal(size_t index, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1645 ASSERT(index < attributeCount());
1647 ElementAttributeData* attributeData = mutableAttributeData();
1649 QualifiedName name = attributeData->attributeItem(index)->name();
1650 AtomicString valueBeingRemoved = attributeData->attributeItem(index)->value();
1652 if (!inSynchronizationOfLazyAttribute) {
1653 if (!valueBeingRemoved.isNull())
1654 willModifyAttribute(name, valueBeingRemoved, nullAtom);
1657 if (RefPtr<Attr> attrNode = attrIfExists(name))
1658 detachAttrNodeFromElementWithValue(attrNode.get(), attributeData->attributeItem(index)->value());
1660 attributeData->removeAttribute(index);
1662 if (!inSynchronizationOfLazyAttribute)
1663 didRemoveAttribute(name);
1666 void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1668 if (!inSynchronizationOfLazyAttribute)
1669 willModifyAttribute(name, nullAtom, value);
1670 mutableAttributeData()->addAttribute(Attribute(name, value));
1671 if (!inSynchronizationOfLazyAttribute)
1672 didAddAttribute(name, value);
1675 void Element::removeAttribute(const AtomicString& name)
1677 if (!attributeData())
1680 AtomicString localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1681 size_t index = attributeData()->getAttributeItemIndex(localName, false);
1682 if (index == notFound) {
1683 if (UNLIKELY(localName == styleAttr) && attributeData()->m_styleAttributeIsDirty && isStyledElement())
1684 static_cast<StyledElement*>(this)->removeAllInlineStyleProperties();
1688 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
1691 void Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName)
1693 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI));
1696 PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& name)
1698 const ElementAttributeData* attributeData = updatedAttributeData();
1701 const Attribute* attribute = attributeData->getAttributeItem(name, shouldIgnoreAttributeCase(this));
1704 return ensureAttr(attribute->name());
1707 PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
1709 const ElementAttributeData* attributeData = updatedAttributeData();
1712 const Attribute* attribute = attributeData->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI));
1715 return ensureAttr(attribute->name());
1718 bool Element::hasAttribute(const AtomicString& name) const
1720 if (!attributeData())
1723 // This call to String::lower() seems to be required but
1724 // there may be a way to remove it.
1725 AtomicString localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1726 return updatedAttributeData()->getAttributeItem(localName, false);
1729 bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
1731 const ElementAttributeData* attributeData = updatedAttributeData();
1734 return attributeData->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI));
1737 CSSStyleDeclaration *Element::style()
1742 void Element::focus(bool restorePreviousSelection)
1747 Document* doc = document();
1748 if (doc->focusedNode() == this)
1751 // If the stylesheets have already been loaded we can reliably check isFocusable.
1752 // If not, we continue and set the focused node on the focus controller below so
1753 // that it can be updated soon after attach.
1754 if (doc->haveStylesheetsLoaded()) {
1755 doc->updateLayoutIgnorePendingStylesheets();
1760 if (!supportsFocus())
1763 RefPtr<Node> protect;
1764 if (Page* page = doc->page()) {
1765 // Focus and change event handlers can cause us to lose our last ref.
1766 // If a focus event handler changes the focus to a different node it
1767 // does not make sense to continue and update appearence.
1769 if (!page->focusController()->setFocusedNode(this, doc->frame()))
1773 // Setting the focused node above might have invalidated the layout due to scripts.
1774 doc->updateLayoutIgnorePendingStylesheets();
1776 if (!isFocusable()) {
1777 ensureElementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
1781 cancelFocusAppearanceUpdate();
1782 updateFocusAppearance(restorePreviousSelection);
1785 void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
1787 if (isRootEditableElement()) {
1788 Frame* frame = document()->frame();
1792 // When focusing an editable element in an iframe, don't reset the selection if it already contains a selection.
1793 if (this == frame->selection()->rootEditableElement())
1796 // FIXME: We should restore the previous selection if there is one.
1797 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
1799 if (frame->selection()->shouldChangeSelection(newSelection)) {
1800 frame->selection()->setSelection(newSelection);
1801 frame->selection()->revealSelection();
1803 } else if (renderer() && !renderer()->isWidget())
1804 renderer()->scrollRectToVisible(boundingBox());
1807 void Element::blur()
1809 cancelFocusAppearanceUpdate();
1810 Document* doc = document();
1811 if (treeScope()->focusedNode() == this) {
1813 doc->frame()->page()->focusController()->setFocusedNode(0, doc->frame());
1815 doc->setFocusedNode(0);
1819 String Element::innerText()
1821 // We need to update layout, since plainText uses line boxes in the render tree.
1822 document()->updateLayoutIgnorePendingStylesheets();
1825 return textContent(true);
1827 return plainText(rangeOfContents(const_cast<Element*>(this)).get());
1830 String Element::outerText()
1832 // Getting outerText is the same as getting innerText, only
1833 // setting is different. You would think this should get the plain
1834 // text for the outer range, but this is wrong, <br> for instance
1835 // would return different values for inner and outer text by such
1836 // a rule, but it doesn't in WinIE, and we want to match that.
1840 String Element::title() const
1845 const AtomicString& Element::pseudo() const
1847 return getAttribute(pseudoAttr);
1850 void Element::setPseudo(const AtomicString& value)
1852 setAttribute(pseudoAttr, value);
1855 LayoutSize Element::minimumSizeForResizing() const
1857 return hasRareData() ? elementRareData()->m_minimumSizeForResizing : defaultMinimumSizeForResizing();
1860 void Element::setMinimumSizeForResizing(const LayoutSize& size)
1862 if (size == defaultMinimumSizeForResizing() && !hasRareData())
1864 ensureElementRareData()->m_minimumSizeForResizing = size;
1867 RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
1869 // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
1870 // properties, which are only known by the renderer because it did the layout, will be correct and so that the
1871 // values returned for the ":selection" pseudo-element will be correct.
1872 if (RenderStyle* usedStyle = renderStyle()) {
1873 if (pseudoElementSpecifier) {
1874 RenderStyle* cachedPseudoStyle = usedStyle->getCachedPseudoStyle(pseudoElementSpecifier);
1875 return cachedPseudoStyle ? cachedPseudoStyle : usedStyle;
1881 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
1882 // document tree and figure out when to destroy the computed style for such elements.
1885 ElementRareData* data = ensureElementRareData();
1886 if (!data->m_computedStyle)
1887 data->m_computedStyle = document()->styleForElementIgnoringPendingStylesheets(this);
1888 return pseudoElementSpecifier ? data->m_computedStyle->getCachedPseudoStyle(pseudoElementSpecifier) : data->m_computedStyle.get();
1891 void Element::setStyleAffectedByEmpty()
1893 ensureElementRareData()->setStyleAffectedByEmpty(true);
1896 void Element::setChildrenAffectedByHover(bool value)
1898 if (value || hasRareData())
1899 ensureElementRareData()->setChildrenAffectedByHover(value);
1902 void Element::setChildrenAffectedByActive(bool value)
1904 if (value || hasRareData())
1905 ensureElementRareData()->setChildrenAffectedByActive(value);
1908 void Element::setChildrenAffectedByDrag(bool value)
1910 if (value || hasRareData())
1911 ensureElementRareData()->setChildrenAffectedByDrag(value);
1914 void Element::setChildrenAffectedByFirstChildRules()
1916 ensureElementRareData()->setChildrenAffectedByFirstChildRules(true);
1919 void Element::setChildrenAffectedByLastChildRules()
1921 ensureElementRareData()->setChildrenAffectedByLastChildRules(true);
1924 void Element::setChildrenAffectedByDirectAdjacentRules()
1926 ensureElementRareData()->setChildrenAffectedByDirectAdjacentRules(true);
1929 void Element::setChildrenAffectedByForwardPositionalRules()
1931 ensureElementRareData()->setChildrenAffectedByForwardPositionalRules(true);
1934 void Element::setChildrenAffectedByBackwardPositionalRules()
1936 ensureElementRareData()->setChildrenAffectedByBackwardPositionalRules(true);
1939 void Element::setChildIndex(unsigned index)
1941 ElementRareData* rareData = ensureElementRareData();
1942 if (RenderStyle* style = renderStyle())
1944 rareData->setChildIndex(index);
1947 bool Element::rareDataStyleAffectedByEmpty() const
1949 ASSERT(hasRareData());
1950 return elementRareData()->styleAffectedByEmpty();
1953 bool Element::rareDataChildrenAffectedByHover() const
1955 ASSERT(hasRareData());
1956 return elementRareData()->childrenAffectedByHover();
1959 bool Element::rareDataChildrenAffectedByActive() const
1961 ASSERT(hasRareData());
1962 return elementRareData()->childrenAffectedByActive();
1965 bool Element::rareDataChildrenAffectedByDrag() const
1967 ASSERT(hasRareData());
1968 return elementRareData()->childrenAffectedByDrag();
1971 bool Element::rareDataChildrenAffectedByFirstChildRules() const
1973 ASSERT(hasRareData());
1974 return elementRareData()->childrenAffectedByFirstChildRules();
1977 bool Element::rareDataChildrenAffectedByLastChildRules() const
1979 ASSERT(hasRareData());
1980 return elementRareData()->childrenAffectedByLastChildRules();
1983 bool Element::rareDataChildrenAffectedByDirectAdjacentRules() const
1985 ASSERT(hasRareData());
1986 return elementRareData()->childrenAffectedByDirectAdjacentRules();
1989 bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
1991 ASSERT(hasRareData());
1992 return elementRareData()->childrenAffectedByForwardPositionalRules();
1995 bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
1997 ASSERT(hasRareData());
1998 return elementRareData()->childrenAffectedByBackwardPositionalRules();
2001 unsigned Element::rareDataChildIndex() const
2003 ASSERT(hasRareData());
2004 return elementRareData()->childIndex();
2007 void Element::setIsInCanvasSubtree(bool isInCanvasSubtree)
2009 ensureElementRareData()->setIsInCanvasSubtree(isInCanvasSubtree);
2012 bool Element::isInCanvasSubtree() const
2014 return hasRareData() && elementRareData()->isInCanvasSubtree();
2017 AtomicString Element::computeInheritedLanguage() const
2019 const Node* n = this;
2021 // The language property is inherited, so we iterate over the parents to find the first language.
2023 if (n->isElementNode()) {
2024 if (const ElementAttributeData* attributeData = static_cast<const Element*>(n)->attributeData()) {
2025 // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7
2026 if (const Attribute* attribute = attributeData->getAttributeItem(XMLNames::langAttr))
2027 value = attribute->value();
2028 else if (const Attribute* attribute = attributeData->getAttributeItem(HTMLNames::langAttr))
2029 value = attribute->value();
2031 } else if (n->isDocumentNode()) {
2032 // checking the MIME content-language
2033 value = static_cast<const Document*>(n)->contentLanguage();
2036 n = n->parentNode();
2037 } while (n && value.isNull());
2042 Locale& Element::locale() const
2044 return document()->getCachedLocale(computeInheritedLanguage());
2047 void Element::cancelFocusAppearanceUpdate()
2050 elementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
2051 if (document()->focusedNode() == this)
2052 document()->cancelFocusAppearanceUpdate();
2055 void Element::normalizeAttributes()
2057 updateInvalidAttributes();
2058 if (AttrNodeList* attrNodeList = attrNodeListForElement(this)) {
2059 for (unsigned i = 0; i < attrNodeList->size(); ++i)
2060 attrNodeList->at(i)->normalize();
2064 // ElementTraversal API
2065 Element* Element::firstElementChild() const
2067 return WebCore::firstElementChild(this);
2070 Element* Element::lastElementChild() const
2072 Node* n = lastChild();
2073 while (n && !n->isElementNode())
2074 n = n->previousSibling();
2075 return static_cast<Element*>(n);
2078 unsigned Element::childElementCount() const
2081 Node* n = firstChild();
2083 count += n->isElementNode();
2084 n = n->nextSibling();
2089 bool Element::shouldMatchReadOnlySelector() const
2094 bool Element::shouldMatchReadWriteSelector() const
2099 bool Element::webkitMatchesSelector(const String& selector, ExceptionCode& ec)
2101 if (selector.isEmpty()) {
2106 SelectorQuery* selectorQuery = document()->selectorQueryCache()->add(selector, document(), ec);
2109 return selectorQuery->matches(this);
2112 DOMTokenList* Element::classList()
2114 ElementRareData* data = ensureElementRareData();
2115 if (!data->m_classList)
2116 data->m_classList = ClassList::create(this);
2117 return data->m_classList.get();
2120 DOMTokenList* Element::optionalClassList() const
2124 return elementRareData()->m_classList.get();
2127 DOMStringMap* Element::dataset()
2129 ElementRareData* data = ensureElementRareData();
2130 if (!data->m_datasetDOMStringMap)
2131 data->m_datasetDOMStringMap = DatasetDOMStringMap::create(this);
2132 return data->m_datasetDOMStringMap.get();
2135 KURL Element::getURLAttribute(const QualifiedName& name) const
2137 #if !ASSERT_DISABLED
2138 if (attributeData()) {
2139 if (const Attribute* attribute = getAttributeItem(name))
2140 ASSERT(isURLAttribute(*attribute));
2143 return document()->completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
2146 KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
2148 #if !ASSERT_DISABLED
2149 if (attributeData()) {
2150 if (const Attribute* attribute = getAttributeItem(name))
2151 ASSERT(isURLAttribute(*attribute));
2154 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
2155 if (value.isEmpty())
2157 return document()->completeURL(value);
2160 int Element::getIntegralAttribute(const QualifiedName& attributeName) const
2162 return getAttribute(attributeName).string().toInt();
2165 void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
2167 // FIXME: Need an AtomicString version of String::number.
2168 setAttribute(attributeName, String::number(value));
2171 unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
2173 return getAttribute(attributeName).string().toUInt();
2176 void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
2178 // FIXME: Need an AtomicString version of String::number.
2179 setAttribute(attributeName, String::number(value));
2183 bool Element::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
2185 // Only create renderers for SVG elements whose parents are SVG elements, or for proper <svg xmlns="svgNS"> subdocuments.
2186 if (childContext.node()->isSVGElement())
2187 return childContext.node()->hasTagName(SVGNames::svgTag) || isSVGElement();
2189 return ContainerNode::childShouldCreateRenderer(childContext);
2193 #if ENABLE(FULLSCREEN_API)
2194 void Element::webkitRequestFullscreen()
2196 document()->requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, Document::EnforceIFrameAllowFullScreenRequirement);
2199 void Element::webkitRequestFullScreen(unsigned short flags)
2201 document()->requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), Document::EnforceIFrameAllowFullScreenRequirement);
2204 bool Element::containsFullScreenElement() const
2206 return hasRareData() && elementRareData()->containsFullScreenElement();
2209 void Element::setContainsFullScreenElement(bool flag)
2211 ensureElementRareData()->setContainsFullScreenElement(flag);
2212 setNeedsStyleRecalc(SyntheticStyleChange);
2215 static Element* parentCrossingFrameBoundaries(Element* element)
2218 return element->parentElement() ? element->parentElement() : element->document()->ownerElement();
2221 void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool flag)
2223 Element* element = this;
2224 while ((element = parentCrossingFrameBoundaries(element)))
2225 element->setContainsFullScreenElement(flag);
2229 #if ENABLE(DIALOG_ELEMENT)
2230 bool Element::isInTopLayer() const
2232 return hasRareData() && elementRareData()->isInTopLayer();
2235 void Element::setIsInTopLayer(bool inTopLayer)
2237 if (isInTopLayer() == inTopLayer)
2240 ensureElementRareData()->setIsInTopLayer(inTopLayer);
2243 document()->addToTopLayer(this);
2245 document()->removeFromTopLayer(this);
2246 setNeedsStyleRecalc(SyntheticStyleChange);
2250 #if ENABLE(POINTER_LOCK)
2251 void Element::webkitRequestPointerLock()
2253 if (document()->page())
2254 document()->page()->pointerLockController()->requestPointerLock(this);
2258 SpellcheckAttributeState Element::spellcheckAttributeState() const
2260 const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
2261 if (value == nullAtom)
2262 return SpellcheckAttributeDefault;
2263 if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
2264 return SpellcheckAttributeTrue;
2265 if (equalIgnoringCase(value, "false"))
2266 return SpellcheckAttributeFalse;
2268 return SpellcheckAttributeDefault;
2271 bool Element::isSpellCheckingEnabled() const
2273 for (const Element* element = this; element; element = element->parentOrHostElement()) {
2274 switch (element->spellcheckAttributeState()) {
2275 case SpellcheckAttributeTrue:
2277 case SpellcheckAttributeFalse:
2279 case SpellcheckAttributeDefault:
2287 PassRefPtr<WebKitAnimationList> Element::webkitGetAnimations() const
2292 AnimationController* animController = renderer()->animation();
2294 if (!animController)
2297 return animController->animationsForRenderer(renderer());
2300 RenderRegion* Element::renderRegion() const
2302 if (renderer() && renderer()->isRenderRegion())
2303 return toRenderRegion(renderer());
2308 #if ENABLE(CSS_REGIONS)
2310 const AtomicString& Element::webkitRegionOverset() const
2312 document()->updateLayoutIgnorePendingStylesheets();
2314 DEFINE_STATIC_LOCAL(AtomicString, undefinedState, ("undefined", AtomicString::ConstructFromLiteral));
2315 if (!document()->cssRegionsEnabled() || !renderRegion())
2316 return undefinedState;
2318 switch (renderRegion()->regionState()) {
2319 case RenderRegion::RegionFit: {
2320 DEFINE_STATIC_LOCAL(AtomicString, fitState, ("fit", AtomicString::ConstructFromLiteral));
2323 case RenderRegion::RegionEmpty: {
2324 DEFINE_STATIC_LOCAL(AtomicString, emptyState, ("empty", AtomicString::ConstructFromLiteral));
2327 case RenderRegion::RegionOverset: {
2328 DEFINE_STATIC_LOCAL(AtomicString, overflowState, ("overset", AtomicString::ConstructFromLiteral));
2329 return overflowState;
2331 case RenderRegion::RegionUndefined:
2332 return undefinedState;
2335 ASSERT_NOT_REACHED();
2336 return undefinedState;
2339 Vector<RefPtr<Range> > Element::webkitGetRegionFlowRanges() const
2341 document()->updateLayoutIgnorePendingStylesheets();
2343 Vector<RefPtr<Range> > rangeObjects;
2344 if (document()->cssRegionsEnabled() && renderer() && renderer()->isRenderRegion()) {
2345 RenderRegion* region = toRenderRegion(renderer());
2346 if (region->isValid())
2347 region->getRanges(rangeObjects);
2350 return rangeObjects;
2356 bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
2358 if (name == HTMLNames::styleAttr)
2363 return !SVGElement::isAnimatableAttribute(name);
2370 #ifdef DUMP_NODE_STATISTICS
2371 bool Element::hasNamedNodeMap() const
2373 return hasRareData() && elementRareData()->m_attributeMap;
2377 void Element::updateLabel(TreeScope* scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
2379 ASSERT(hasTagName(labelTag));
2384 if (oldForAttributeValue == newForAttributeValue)
2387 if (!oldForAttributeValue.isEmpty())
2388 scope->removeLabel(oldForAttributeValue, static_cast<HTMLLabelElement*>(this));
2389 if (!newForAttributeValue.isEmpty())
2390 scope->addLabel(newForAttributeValue, static_cast<HTMLLabelElement*>(this));
2393 void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
2395 if (isIdAttributeName(name))
2396 updateId(oldValue, newValue);
2397 else if (name == HTMLNames::nameAttr)
2398 updateName(oldValue, newValue);
2399 else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
2400 TreeScope* scope = treeScope();
2401 if (scope->shouldCacheLabelsByForAttribute())
2402 updateLabel(scope, oldValue, newValue);
2405 #if ENABLE(MUTATION_OBSERVERS)
2406 if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(this, name))
2407 recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue));
2410 #if ENABLE(INSPECTOR)
2411 InspectorInstrumentation::willModifyDOMAttr(document(), this, oldValue, newValue);
2415 void Element::didAddAttribute(const QualifiedName& name, const AtomicString& value)
2417 attributeChanged(name, value);
2418 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value);
2419 dispatchSubtreeModifiedEvent();
2422 void Element::didModifyAttribute(const QualifiedName& name, const AtomicString& value)
2424 attributeChanged(name, value);
2425 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value);
2426 // Do not dispatch a DOMSubtreeModified event here; see bug 81141.
2429 void Element::didRemoveAttribute(const QualifiedName& name)
2431 attributeChanged(name, nullAtom);
2432 InspectorInstrumentation::didRemoveDOMAttr(document(), this, name.localName());
2433 dispatchSubtreeModifiedEvent();
2437 void Element::updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName)
2439 if (!document()->isHTMLDocument())
2442 if (!oldName.isEmpty())
2443 static_cast<HTMLDocument*>(document())->removeNamedItem(oldName);
2445 if (!newName.isEmpty())
2446 static_cast<HTMLDocument*>(document())->addNamedItem(newName);
2449 void Element::updateExtraNamedItemRegistration(const AtomicString& oldId, const AtomicString& newId)
2451 if (!document()->isHTMLDocument())
2454 if (!oldId.isEmpty())
2455 static_cast<HTMLDocument*>(document())->removeExtraNamedItem(oldId);
2457 if (!newId.isEmpty())
2458 static_cast<HTMLDocument*>(document())->addExtraNamedItem(newId);
2461 PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
2463 if (HTMLCollection* collection = cachedHTMLCollection(type))
2466 RefPtr<HTMLCollection> collection;
2467 if (type == TableRows) {
2468 ASSERT(hasTagName(tableTag));
2469 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
2470 } else if (type == SelectOptions) {
2471 ASSERT(hasTagName(selectTag));
2472 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
2473 } else if (type == FormControls) {
2474 ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
2475 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
2476 #if ENABLE(MICRODATA)
2477 } else if (type == ItemProperties) {
2478 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLPropertiesCollection>(this, type);
2481 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLCollection>(this, type);
2484 HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
2486 return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0;
2489 IntSize Element::savedLayerScrollOffset() const
2491 return hasRareData() ? elementRareData()->m_savedLayerScrollOffset : IntSize();
2494 void Element::setSavedLayerScrollOffset(const IntSize& size)
2496 if (size.isZero() && !hasRareData())
2498 ensureElementRareData()->m_savedLayerScrollOffset = size;
2501 PassRefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
2503 if (AttrNodeList* attrNodeList = attrNodeListForElement(this))
2504 return findAttrNodeInList(attrNodeList, name);
2508 PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name)
2510 AttrNodeList* attrNodeList = ensureAttrNodeListForElement(this);
2511 RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
2513 attrNode = Attr::create(this, name);
2514 attrNodeList->append(attrNode);
2516 return attrNode.release();
2519 void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value)
2521 ASSERT(hasSyntheticAttrChildNodes());
2522 attrNode->detachFromElementWithValue(value);
2524 AttrNodeList* attrNodeList = attrNodeListForElement(this);
2525 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
2526 if (attrNodeList->at(i)->qualifiedName() == attrNode->qualifiedName()) {
2527 attrNodeList->remove(i);
2528 if (attrNodeList->isEmpty())
2529 removeAttrNodeListForElement(this);
2533 ASSERT_NOT_REACHED();
2536 void Element::detachAllAttrNodesFromElement()
2538 AttrNodeList* attrNodeList = attrNodeListForElement(this);
2539 ASSERT(attrNodeList);
2541 for (unsigned i = 0; i < attributeCount(); ++i) {
2542 const Attribute* attribute = attributeItem(i);
2543 if (RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, attribute->name()))
2544 attrNode->detachFromElementWithValue(attribute->value());
2547 removeAttrNodeListForElement(this);
2550 bool Element::willRecalcStyle(StyleChange)
2552 ASSERT(hasCustomCallbacks());
2556 void Element::didRecalcStyle(StyleChange)
2558 ASSERT(hasCustomCallbacks());
2562 PassRefPtr<RenderStyle> Element::customStyleForRenderer()
2564 ASSERT(hasCustomCallbacks());
2568 void Element::cloneAttributesFromElement(const Element& other)
2570 if (hasSyntheticAttrChildNodes())
2571 detachAllAttrNodesFromElement();
2573 other.updateInvalidAttributes();
2574 if (!other.m_attributeData) {
2575 m_attributeData.clear();
2579 const AtomicString& oldID = getIdAttribute();
2580 const AtomicString& newID = other.getIdAttribute();
2582 if (!oldID.isNull() || !newID.isNull())
2583 updateId(oldID, newID);
2585 const AtomicString& oldName = getNameAttribute();
2586 const AtomicString& newName = other.getNameAttribute();
2588 if (!oldName.isNull() || !newName.isNull())
2589 updateName(oldName, newName);
2591 // If 'other' has a mutable ElementAttributeData, convert it to an immutable one so we can share it between both elements.
2592 // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes.
2593 if (other.m_attributeData->isMutable()
2594 && !other.m_attributeData->presentationAttributeStyle()
2595 && (!other.m_attributeData->inlineStyle() || !other.m_attributeData->inlineStyle()->hasCSSOMWrapper()))
2596 const_cast<Element&>(other).m_attributeData = other.m_attributeData->makeImmutableCopy();
2598 if (!other.m_attributeData->isMutable())
2599 m_attributeData = other.m_attributeData;
2601 m_attributeData = other.m_attributeData->makeMutableCopy();
2603 for (unsigned i = 0; i < m_attributeData->length(); ++i) {
2604 const Attribute* attribute = const_cast<const ElementAttributeData*>(m_attributeData.get())->attributeItem(i);
2605 attributeChanged(attribute->name(), attribute->value());
2609 void Element::cloneDataFromElement(const Element& other)
2611 cloneAttributesFromElement(other);
2612 copyNonAttributePropertiesFromElement(other);
2615 void Element::createMutableAttributeData()
2617 if (!m_attributeData)
2618 m_attributeData = ElementAttributeData::create();
2620 m_attributeData = m_attributeData->makeMutableCopy();
2623 void Element::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
2625 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
2626 ContainerNode::reportMemoryUsage(memoryObjectInfo);
2627 info.addMember(m_tagName);
2628 info.addMember(m_attributeData);
2631 } // namespace WebCore