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, 2013 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"
65 #include "NodeTraversal.h"
67 #include "PointerLockController.h"
68 #include "PseudoElement.h"
69 #include "RenderRegion.h"
70 #include "RenderView.h"
71 #include "RenderWidget.h"
72 #include "SelectorQuery.h"
74 #include "ShadowRoot.h"
75 #include "StyleResolver.h"
77 #include "TextIterator.h"
78 #include "VoidCallback.h"
79 #include "WebCoreMemoryInstrumentation.h"
80 #include "XMLNSNames.h"
82 #include "htmlediting.h"
83 #include <wtf/BitVector.h>
84 #include <wtf/MemoryInstrumentationVector.h>
85 #include <wtf/text/CString.h>
88 #include "SVGDocumentExtensions.h"
89 #include "SVGElement.h"
95 using namespace HTMLNames;
96 using namespace XMLNames;
98 class StyleResolverParentPusher {
100 StyleResolverParentPusher(Element* parent)
102 , m_pushedStyleResolver(0)
107 if (m_pushedStyleResolver)
109 m_pushedStyleResolver = m_parent->document()->styleResolver();
110 m_pushedStyleResolver->pushParentElement(m_parent);
112 ~StyleResolverParentPusher()
115 if (!m_pushedStyleResolver)
118 // This tells us that our pushed style selector is in a bad state,
119 // so we should just bail out in that scenario.
120 ASSERT(m_pushedStyleResolver == m_parent->document()->styleResolver());
121 if (m_pushedStyleResolver != m_parent->document()->styleResolver())
124 m_pushedStyleResolver->popParentElement(m_parent);
129 StyleResolver* m_pushedStyleResolver;
132 typedef Vector<RefPtr<Attr> > AttrNodeList;
133 typedef HashMap<Element*, OwnPtr<AttrNodeList> > AttrNodeListMap;
135 static AttrNodeListMap& attrNodeListMap()
137 DEFINE_STATIC_LOCAL(AttrNodeListMap, map, ());
141 static AttrNodeList* attrNodeListForElement(Element* element)
143 if (!element->hasSyntheticAttrChildNodes())
145 ASSERT(attrNodeListMap().contains(element));
146 return attrNodeListMap().get(element);
149 static AttrNodeList* ensureAttrNodeListForElement(Element* element)
151 if (element->hasSyntheticAttrChildNodes()) {
152 ASSERT(attrNodeListMap().contains(element));
153 return attrNodeListMap().get(element);
155 ASSERT(!attrNodeListMap().contains(element));
156 element->setHasSyntheticAttrChildNodes(true);
157 AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList));
158 return result.iterator->value.get();
161 static void removeAttrNodeListForElement(Element* element)
163 ASSERT(element->hasSyntheticAttrChildNodes());
164 ASSERT(attrNodeListMap().contains(element));
165 attrNodeListMap().remove(element);
166 element->setHasSyntheticAttrChildNodes(false);
169 static Attr* findAttrNodeInList(AttrNodeList* attrNodeList, const QualifiedName& name)
171 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
172 if (attrNodeList->at(i)->qualifiedName() == name)
173 return attrNodeList->at(i).get();
178 PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document)
180 return adoptRef(new Element(tagName, document, CreateElement));
186 if (document() && document()->renderer()) {
187 // When the document is not destroyed, an element that was part of a named flow
188 // content nodes should have been removed from the content nodes collection
189 // and the inNamedFlow flag reset.
190 ASSERT(!inNamedFlow());
195 ElementRareData* data = elementRareData();
196 data->setPseudoElement(BEFORE, 0);
197 data->setPseudoElement(AFTER, 0);
201 if (hasSyntheticAttrChildNodes())
202 detachAllAttrNodesFromElement();
205 if (hasPendingResources()) {
206 document()->accessSVGExtensions()->removeElementFromPendingResources(this);
207 ASSERT(!hasPendingResources());
212 inline ElementRareData* Element::elementRareData() const
214 ASSERT(hasRareData());
215 return static_cast<ElementRareData*>(rareData());
218 inline ElementRareData* Element::ensureElementRareData()
220 return static_cast<ElementRareData*>(ensureRareData());
223 void Element::clearTabIndexExplicitlyIfNeeded()
226 elementRareData()->clearTabIndexExplicitly();
229 void Element::setTabIndexExplicitly(short tabIndex)
231 ensureElementRareData()->setTabIndexExplicitly(tabIndex);
234 bool Element::supportsFocus() const
236 return hasRareData() && elementRareData()->tabIndexSetExplicitly();
239 short Element::tabIndex() const
241 return hasRareData() ? elementRareData()->tabIndex() : 0;
244 DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, blur);
245 DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, error);
246 DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, focus);
247 DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, load);
249 PassRefPtr<Node> Element::cloneNode(bool deep)
251 return deep ? cloneElementWithChildren() : cloneElementWithoutChildren();
254 PassRefPtr<Element> Element::cloneElementWithChildren()
256 RefPtr<Element> clone = cloneElementWithoutChildren();
257 cloneChildNodes(clone.get());
258 return clone.release();
261 PassRefPtr<Element> Element::cloneElementWithoutChildren()
263 RefPtr<Element> clone = cloneElementWithoutAttributesAndChildren();
264 // This will catch HTML elements in the wrong namespace that are not correctly copied.
265 // This is a sanity check as HTML overloads some of the DOM methods.
266 ASSERT(isHTMLElement() == clone->isHTMLElement());
268 clone->cloneDataFromElement(*this);
269 return clone.release();
272 PassRefPtr<Element> Element::cloneElementWithoutAttributesAndChildren()
274 return document()->createElement(tagQName(), false);
277 PassRefPtr<Attr> Element::detachAttribute(size_t index)
279 ASSERT(elementData());
281 const Attribute* attribute = elementData()->attributeItem(index);
284 RefPtr<Attr> attrNode = attrIfExists(attribute->name());
286 detachAttrNodeFromElementWithValue(attrNode.get(), attribute->value());
288 attrNode = Attr::create(document(), attribute->name(), attribute->value());
290 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
291 return attrNode.release();
294 void Element::removeAttribute(const QualifiedName& name)
299 size_t index = elementData()->getAttributeItemIndex(name);
300 if (index == notFound)
303 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
306 void Element::setBooleanAttribute(const QualifiedName& name, bool value)
309 setAttribute(name, emptyAtom);
311 removeAttribute(name);
314 NamedNodeMap* Element::attributes() const
316 ensureElementDataWithSynchronizedAttributes();
317 ElementRareData* rareData = const_cast<Element*>(this)->ensureElementRareData();
318 if (NamedNodeMap* attributeMap = rareData->attributeMap())
321 rareData->setAttributeMap(NamedNodeMap::create(const_cast<Element*>(this)));
322 return rareData->attributeMap();
325 Node::NodeType Element::nodeType() const
330 bool Element::hasAttribute(const QualifiedName& name) const
332 return hasAttributeNS(name.namespaceURI(), name.localName());
335 const AtomicString& Element::getAttribute(const QualifiedName& name) const
340 if (UNLIKELY(name == styleAttr && elementData()->m_styleAttributeIsDirty))
341 updateStyleAttribute();
344 if (UNLIKELY(elementData()->m_animatedSVGAttributesAreDirty))
345 updateAnimatedSVGAttribute(name);
348 if (const Attribute* attribute = getAttributeItem(name))
349 return attribute->value();
353 void Element::scrollIntoView(bool alignToTop)
355 document()->updateLayoutIgnorePendingStylesheets();
360 LayoutRect bounds = boundingBox();
361 // Align to the top / bottom and to the closest edge.
363 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
365 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
368 void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
370 document()->updateLayoutIgnorePendingStylesheets();
375 LayoutRect bounds = boundingBox();
377 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
379 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
382 void Element::scrollByUnits(int units, ScrollGranularity granularity)
384 document()->updateLayoutIgnorePendingStylesheets();
389 if (!renderer()->hasOverflowClip())
392 ScrollDirection direction = ScrollDown;
394 direction = ScrollUp;
397 Node* stopNode = this;
398 toRenderBox(renderer())->scroll(direction, granularity, units, &stopNode);
401 void Element::scrollByLines(int lines)
403 scrollByUnits(lines, ScrollByLine);
406 void Element::scrollByPages(int pages)
408 scrollByUnits(pages, ScrollByPage);
411 static float localZoomForRenderer(RenderObject* renderer)
413 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
414 // other out, but the alternative is that we'd have to crawl up the whole render tree every
415 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
416 float zoomFactor = 1;
417 if (renderer->style()->effectiveZoom() != 1) {
418 // Need to find the nearest enclosing RenderObject that set up
419 // a differing zoom, and then we divide our result by it to eliminate the zoom.
420 RenderObject* prev = renderer;
421 for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) {
422 if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) {
423 zoomFactor = prev->style()->zoom();
428 if (prev->isRenderView())
429 zoomFactor = prev->style()->zoom();
434 static int adjustForLocalZoom(LayoutUnit value, RenderObject* renderer)
436 float zoomFactor = localZoomForRenderer(renderer);
439 #if ENABLE(SUBPIXEL_LAYOUT)
440 return lroundf(value / zoomFactor);
442 // Needed because computeLengthInt truncates (rather than rounds) when scaling up.
445 return static_cast<int>(value / zoomFactor);
449 int Element::offsetLeft()
451 document()->updateLayoutIgnorePendingStylesheets();
452 if (RenderBoxModelObject* renderer = renderBoxModelObject())
453 return adjustForLocalZoom(renderer->pixelSnappedOffsetLeft(), renderer);
457 int Element::offsetTop()
459 document()->updateLayoutIgnorePendingStylesheets();
460 if (RenderBoxModelObject* renderer = renderBoxModelObject())
461 return adjustForLocalZoom(renderer->pixelSnappedOffsetTop(), renderer);
465 int Element::offsetWidth()
467 document()->updateLayoutIgnorePendingStylesheets();
468 if (RenderBoxModelObject* renderer = renderBoxModelObject())
469 #if ENABLE(SUBPIXEL_LAYOUT)
470 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetWidth(), renderer).round();
472 return adjustForAbsoluteZoom(renderer->pixelSnappedOffsetWidth(), renderer);
477 int Element::offsetHeight()
479 document()->updateLayoutIgnorePendingStylesheets();
480 if (RenderBoxModelObject* renderer = renderBoxModelObject())
481 #if ENABLE(SUBPIXEL_LAYOUT)
482 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetHeight(), renderer).round();
484 return adjustForAbsoluteZoom(renderer->pixelSnappedOffsetHeight(), renderer);
489 Element* Element::offsetParent()
491 document()->updateLayoutIgnorePendingStylesheets();
492 if (RenderObject* rend = renderer())
493 if (RenderObject* offsetParent = rend->offsetParent())
494 return static_cast<Element*>(offsetParent->node());
498 int Element::clientLeft()
500 document()->updateLayoutIgnorePendingStylesheets();
502 if (RenderBox* renderer = renderBox())
503 return adjustForAbsoluteZoom(roundToInt(renderer->clientLeft()), renderer);
507 int Element::clientTop()
509 document()->updateLayoutIgnorePendingStylesheets();
511 if (RenderBox* renderer = renderBox())
512 return adjustForAbsoluteZoom(roundToInt(renderer->clientTop()), renderer);
516 int Element::clientWidth()
518 document()->updateLayoutIgnorePendingStylesheets();
520 // When in strict mode, clientWidth for the document element should return the width of the containing frame.
521 // When in quirks mode, clientWidth for the body element should return the width of the containing frame.
522 bool inQuirksMode = document()->inQuirksMode();
523 if ((!inQuirksMode && document()->documentElement() == this) ||
524 (inQuirksMode && isHTMLElement() && document()->body() == this)) {
525 if (FrameView* view = document()->view()) {
526 if (RenderView* renderView = document()->renderView())
527 return adjustForAbsoluteZoom(view->layoutWidth(), renderView);
531 if (RenderBox* renderer = renderBox())
532 #if ENABLE(SUBPIXEL_LAYOUT)
533 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientWidth(), renderer).round();
535 return adjustForAbsoluteZoom(renderer->pixelSnappedClientWidth(), renderer);
540 int Element::clientHeight()
542 document()->updateLayoutIgnorePendingStylesheets();
544 // When in strict mode, clientHeight for the document element should return the height of the containing frame.
545 // When in quirks mode, clientHeight for the body element should return the height of the containing frame.
546 bool inQuirksMode = document()->inQuirksMode();
548 if ((!inQuirksMode && document()->documentElement() == this) ||
549 (inQuirksMode && isHTMLElement() && document()->body() == this)) {
550 if (FrameView* view = document()->view()) {
551 if (RenderView* renderView = document()->renderView())
552 return adjustForAbsoluteZoom(view->layoutHeight(), renderView);
556 if (RenderBox* renderer = renderBox())
557 #if ENABLE(SUBPIXEL_LAYOUT)
558 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientHeight(), renderer).round();
560 return adjustForAbsoluteZoom(renderer->pixelSnappedClientHeight(), renderer);
565 int Element::scrollLeft()
567 document()->updateLayoutIgnorePendingStylesheets();
568 if (RenderBox* rend = renderBox())
569 return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
573 int Element::scrollTop()
575 document()->updateLayoutIgnorePendingStylesheets();
576 if (RenderBox* rend = renderBox())
577 return adjustForAbsoluteZoom(rend->scrollTop(), rend);
581 void Element::setScrollLeft(int newLeft)
583 document()->updateLayoutIgnorePendingStylesheets();
584 if (RenderBox* rend = renderBox())
585 rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
588 void Element::setScrollTop(int newTop)
590 document()->updateLayoutIgnorePendingStylesheets();
591 if (RenderBox* rend = renderBox())
592 rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
595 int Element::scrollWidth()
597 document()->updateLayoutIgnorePendingStylesheets();
598 if (RenderBox* rend = renderBox())
599 return adjustForAbsoluteZoom(rend->scrollWidth(), rend);
603 int Element::scrollHeight()
605 document()->updateLayoutIgnorePendingStylesheets();
606 if (RenderBox* rend = renderBox())
607 return adjustForAbsoluteZoom(rend->scrollHeight(), rend);
611 IntRect Element::boundsInRootViewSpace()
613 document()->updateLayoutIgnorePendingStylesheets();
615 FrameView* view = document()->view();
619 Vector<FloatQuad> quads;
621 if (isSVGElement() && renderer()) {
622 // Get the bounding rectangle from the SVG model.
623 SVGElement* svgElement = static_cast<SVGElement*>(this);
625 if (svgElement->getBoundingBox(localRect))
626 quads.append(renderer()->localToAbsoluteQuad(localRect));
630 // Get the bounding rectangle from the box model.
631 if (renderBoxModelObject())
632 renderBoxModelObject()->absoluteQuads(quads);
638 IntRect result = quads[0].enclosingBoundingBox();
639 for (size_t i = 1; i < quads.size(); ++i)
640 result.unite(quads[i].enclosingBoundingBox());
642 result = view->contentsToRootView(result);
646 PassRefPtr<ClientRectList> Element::getClientRects()
648 document()->updateLayoutIgnorePendingStylesheets();
650 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject();
651 if (!renderBoxModelObject)
652 return ClientRectList::create();
654 // FIXME: Handle SVG elements.
655 // FIXME: Handle table/inline-table with a caption.
657 Vector<FloatQuad> quads;
658 renderBoxModelObject->absoluteQuads(quads);
659 document()->adjustFloatQuadsForScrollAndAbsoluteZoomAndFrameScale(quads, renderBoxModelObject);
660 return ClientRectList::create(quads);
663 PassRefPtr<ClientRect> Element::getBoundingClientRect()
665 document()->updateLayoutIgnorePendingStylesheets();
667 Vector<FloatQuad> quads;
669 if (isSVGElement() && renderer() && !renderer()->isSVGRoot()) {
670 // Get the bounding rectangle from the SVG model.
671 SVGElement* svgElement = static_cast<SVGElement*>(this);
673 if (svgElement->getBoundingBox(localRect))
674 quads.append(renderer()->localToAbsoluteQuad(localRect));
678 // Get the bounding rectangle from the box model.
679 if (renderBoxModelObject())
680 renderBoxModelObject()->absoluteQuads(quads);
684 return ClientRect::create();
686 FloatRect result = quads[0].boundingBox();
687 for (size_t i = 1; i < quads.size(); ++i)
688 result.unite(quads[i].boundingBox());
690 document()->adjustFloatRectForScrollAndAbsoluteZoomAndFrameScale(result, renderer());
691 return ClientRect::create(result);
694 IntRect Element::screenRect() const
698 // FIXME: this should probably respect transforms
699 return document()->view()->contentsToScreen(renderer()->absoluteBoundingBoxRectIgnoringTransforms());
702 static inline bool shouldIgnoreAttributeCase(const Element* e)
704 return e && e->document()->isHTMLDocument() && e->isHTMLElement();
707 const AtomicString& Element::getAttribute(const AtomicString& name) const
712 bool ignoreCase = shouldIgnoreAttributeCase(this);
714 // Update the 'style' attribute if it's invalid and being requested:
715 if (elementData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(name, styleAttr.localName(), ignoreCase))
716 updateStyleAttribute();
719 if (elementData()->m_animatedSVGAttributesAreDirty) {
720 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
721 updateAnimatedSVGAttribute(QualifiedName(nullAtom, name, nullAtom));
725 if (const Attribute* attribute = elementData()->getAttributeItem(name, ignoreCase))
726 return attribute->value();
730 const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
732 return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
735 void Element::setAttribute(const AtomicString& name, const AtomicString& value, ExceptionCode& ec)
737 if (!Document::isValidName(name)) {
738 ec = INVALID_CHARACTER_ERR;
742 const AtomicString& localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
744 size_t index = ensureElementDataWithSynchronizedAttributes()->getAttributeItemIndex(localName, false);
745 const QualifiedName& qName = index != notFound ? attributeItem(index)->name() : QualifiedName(nullAtom, localName, nullAtom);
746 setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute);
749 void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
751 setAttributeInternal(ensureElementDataWithSynchronizedAttributes()->getAttributeItemIndex(name), name, value, NotInSynchronizationOfLazyAttribute);
754 void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value)
756 setAttributeInternal(ensureUniqueElementData()->getAttributeItemIndex(name), name, value, InSynchronizationOfLazyAttribute);
759 inline void Element::setAttributeInternal(size_t index, const QualifiedName& name, const AtomicString& newValue, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
761 if (newValue.isNull()) {
762 if (index != notFound)
763 removeAttributeInternal(index, inSynchronizationOfLazyAttribute);
767 if (index == notFound) {
768 addAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute);
772 if (!inSynchronizationOfLazyAttribute)
773 willModifyAttribute(name, attributeItem(index)->value(), newValue);
775 if (newValue != attributeItem(index)->value()) {
776 // If there is an Attr node hooked to this attribute, the Attr::setValue() call below
777 // will write into the ElementData.
778 // FIXME: Refactor this so it makes some sense.
779 if (RefPtr<Attr> attrNode = inSynchronizationOfLazyAttribute ? 0 : attrIfExists(name))
780 attrNode->setValue(newValue);
782 ensureUniqueElementData()->attributeItem(index)->setValue(newValue);
785 if (!inSynchronizationOfLazyAttribute)
786 didModifyAttribute(name, newValue);
789 static inline AtomicString makeIdForStyleResolution(const AtomicString& value, bool inQuirksMode)
792 return value.lower();
796 static bool checkNeedsStyleInvalidationForIdChange(const AtomicString& oldId, const AtomicString& newId, StyleResolver* styleResolver)
798 ASSERT(newId != oldId);
799 if (!oldId.isEmpty() && styleResolver->hasSelectorForId(oldId))
801 if (!newId.isEmpty() && styleResolver->hasSelectorForId(newId))
806 void Element::attributeChanged(const QualifiedName& name, const AtomicString& newValue)
808 if (ElementShadow* parentElementShadow = shadowOfParentForDistribution(this)) {
809 if (shouldInvalidateDistributionWhenAttributeChanged(parentElementShadow, name, newValue))
810 parentElementShadow->invalidateDistribution();
813 parseAttribute(name, newValue);
815 document()->incDOMTreeVersion();
817 StyleResolver* styleResolver = document()->styleResolverIfExists();
818 bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < FullStyleChange;
819 bool shouldInvalidateStyle = false;
821 if (isIdAttributeName(name)) {
822 AtomicString oldId = elementData()->idForStyleResolution();
823 AtomicString newId = makeIdForStyleResolution(newValue, document()->inQuirksMode());
824 if (newId != oldId) {
825 elementData()->setIdForStyleResolution(newId);
826 shouldInvalidateStyle = testShouldInvalidateStyle && checkNeedsStyleInvalidationForIdChange(oldId, newId, styleResolver);
828 } else if (name == classAttr)
829 classAttributeChanged(newValue);
830 else if (name == HTMLNames::nameAttr)
831 setHasName(!newValue.isNull());
832 else if (name == HTMLNames::pseudoAttr)
833 shouldInvalidateStyle |= testShouldInvalidateStyle && isInShadowTree();
835 shouldInvalidateStyle |= testShouldInvalidateStyle && styleResolver->hasSelectorForAttribute(name.localName());
837 invalidateNodeListCachesInAncestors(&name, this);
839 // If there is currently no StyleResolver, we can't be sure that this attribute change won't affect style.
840 shouldInvalidateStyle |= !styleResolver;
842 if (shouldInvalidateStyle)
843 setNeedsStyleRecalc();
845 if (AXObjectCache::accessibilityEnabled())
846 document()->axObjectCache()->handleAttributeChanged(name, this);
849 template <typename CharacterType>
850 static inline bool classStringHasClassName(const CharacterType* characters, unsigned length)
856 if (isNotHTMLSpace(characters[i]))
859 } while (i < length);
864 static inline bool classStringHasClassName(const AtomicString& newClassString)
866 unsigned length = newClassString.length();
871 if (newClassString.is8Bit())
872 return classStringHasClassName(newClassString.characters8(), length);
873 return classStringHasClassName(newClassString.characters16(), length);
876 template<typename Checker>
877 static bool checkSelectorForClassChange(const SpaceSplitString& changedClasses, const Checker& checker)
879 unsigned changedSize = changedClasses.size();
880 for (unsigned i = 0; i < changedSize; ++i) {
881 if (checker.hasSelectorForClass(changedClasses[i]))
887 template<typename Checker>
888 static bool checkSelectorForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, const Checker& checker)
890 unsigned oldSize = oldClasses.size();
892 return checkSelectorForClassChange(newClasses, checker);
893 BitVector remainingClassBits;
894 remainingClassBits.ensureSize(oldSize);
895 // Class vectors tend to be very short. This is faster than using a hash table.
896 unsigned newSize = newClasses.size();
897 for (unsigned i = 0; i < newSize; ++i) {
898 for (unsigned j = 0; j < oldSize; ++j) {
899 if (newClasses[i] == oldClasses[j]) {
900 remainingClassBits.quickSet(j);
904 if (checker.hasSelectorForClass(newClasses[i]))
907 for (unsigned i = 0; i < oldSize; ++i) {
908 // If the bit is not set the the corresponding class has been removed.
909 if (remainingClassBits.quickGet(i))
911 if (checker.hasSelectorForClass(oldClasses[i]))
917 void Element::classAttributeChanged(const AtomicString& newClassString)
919 StyleResolver* styleResolver = document()->styleResolverIfExists();
920 bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < FullStyleChange;
921 bool shouldInvalidateStyle = false;
923 if (classStringHasClassName(newClassString)) {
924 const bool shouldFoldCase = document()->inQuirksMode();
925 const SpaceSplitString oldClasses = elementData()->classNames();
926 elementData()->setClass(newClassString, shouldFoldCase);
927 const SpaceSplitString& newClasses = elementData()->classNames();
928 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, newClasses, *styleResolver);
930 const SpaceSplitString& oldClasses = elementData()->classNames();
931 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, *styleResolver);
932 elementData()->clearClass();
936 elementRareData()->clearClassListValueForQuirksMode();
938 if (shouldInvalidateStyle)
939 setNeedsStyleRecalc();
942 bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
944 ASSERT(elementShadow);
945 const SelectRuleFeatureSet& featureSet = elementShadow->distributor().ensureSelectFeatureSet(elementShadow);
947 if (isIdAttributeName(name)) {
948 AtomicString oldId = elementData()->idForStyleResolution();
949 AtomicString newId = makeIdForStyleResolution(newValue, document()->inQuirksMode());
950 if (newId != oldId) {
951 if (!oldId.isEmpty() && featureSet.hasSelectorForId(oldId))
953 if (!newId.isEmpty() && featureSet.hasSelectorForId(newId))
958 if (name == HTMLNames::classAttr) {
959 const AtomicString& newClassString = newValue;
960 if (classStringHasClassName(newClassString)) {
961 const bool shouldFoldCase = document()->inQuirksMode();
962 const SpaceSplitString& oldClasses = elementData()->classNames();
963 const SpaceSplitString newClasses(newClassString, shouldFoldCase);
964 if (checkSelectorForClassChange(oldClasses, newClasses, featureSet))
967 const SpaceSplitString& oldClasses = elementData()->classNames();
968 if (checkSelectorForClassChange(oldClasses, featureSet))
973 return featureSet.hasSelectorForAttribute(name.localName());
976 // Returns true is the given attribute is an event handler.
977 // We consider an event handler any attribute that begins with "on".
978 // It is a simple solution that has the advantage of not requiring any
979 // code or configuration change if a new event handler is defined.
981 static bool isEventHandlerAttribute(const QualifiedName& name)
983 return name.namespaceURI().isNull() && name.localName().startsWith("on");
986 // FIXME: Share code with Element::isURLAttribute.
987 static bool isAttributeToRemove(const QualifiedName& name, const AtomicString& value)
989 return (name.localName() == hrefAttr.localName() || name.localName() == nohrefAttr.localName()
990 || name == srcAttr || name == actionAttr || name == formactionAttr) && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(value));
993 void Element::parserSetAttributes(const Vector<Attribute>& attributeVector, FragmentScriptingPermission scriptingPermission)
995 ASSERT(!inDocument());
996 ASSERT(!parentNode());
998 ASSERT(!m_elementData);
1000 if (attributeVector.isEmpty())
1003 Vector<Attribute> filteredAttributes = attributeVector;
1005 // If the element is created as result of a paste or drag-n-drop operation
1006 // we want to remove all the script and event handlers.
1007 if (!scriptingContentIsAllowed(scriptingPermission)) {
1009 while (i < filteredAttributes.size()) {
1010 Attribute& attribute = filteredAttributes[i];
1011 if (isEventHandlerAttribute(attribute.name())) {
1012 filteredAttributes.remove(i);
1016 if (isAttributeToRemove(attribute.name(), attribute.value()))
1017 attribute.setValue(emptyAtom);
1022 if (document() && document()->sharedObjectPool())
1023 m_elementData = document()->sharedObjectPool()->cachedShareableElementDataWithAttributes(filteredAttributes);
1025 m_elementData = ShareableElementData::createWithAttributes(filteredAttributes);
1027 // Iterate over the set of attributes we already have on the stack in case
1028 // attributeChanged mutates m_elementData.
1029 // FIXME: Find a way so we don't have to do this.
1030 for (unsigned i = 0; i < filteredAttributes.size(); ++i)
1031 attributeChanged(filteredAttributes[i].name(), filteredAttributes[i].value());
1034 bool Element::hasAttributes() const
1036 updateInvalidAttributes();
1037 return elementData() && elementData()->length();
1040 bool Element::hasEquivalentAttributes(const Element* other) const
1042 const ElementData* elementData = elementDataWithSynchronizedAttributes();
1043 const ElementData* otherElementData = other->elementDataWithSynchronizedAttributes();
1044 if (elementData == otherElementData)
1047 return elementData->isEquivalent(otherElementData);
1048 if (otherElementData)
1049 return otherElementData->isEquivalent(elementData);
1053 String Element::nodeName() const
1055 return m_tagName.toString();
1058 String Element::nodeNamePreservingCase() const
1060 return m_tagName.toString();
1063 void Element::setPrefix(const AtomicString& prefix, ExceptionCode& ec)
1066 checkSetPrefix(prefix, ec);
1070 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
1073 KURL Element::baseURI() const
1075 const AtomicString& baseAttribute = getAttribute(baseAttr);
1076 KURL base(KURL(), baseAttribute);
1077 if (!base.protocol().isEmpty())
1080 ContainerNode* parent = parentNode();
1084 const KURL& parentBase = parent->baseURI();
1085 if (parentBase.isNull())
1088 return KURL(parentBase, baseAttribute);
1091 const QualifiedName& Element::imageSourceAttributeName() const
1096 bool Element::rendererIsNeeded(const NodeRenderingContext& context)
1098 return context.style()->display() != NONE;
1101 RenderObject* Element::createRenderer(RenderArena*, RenderStyle* style)
1103 return RenderObject::createObject(this, style);
1106 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
1107 bool Element::isDateTimeFieldElement() const
1113 bool Element::wasChangedSinceLastFormControlChangeEvent() const
1118 void Element::setChangedSinceLastFormControlChangeEvent(bool)
1122 Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertionPoint)
1124 // need to do superclass processing first so inDocument() is true
1125 // by the time we reach updateId
1126 ContainerNode::insertedInto(insertionPoint);
1128 #if ENABLE(FULLSCREEN_API)
1129 if (containsFullScreenElement() && parentElement() && !parentElement()->containsFullScreenElement())
1130 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
1133 if (Element* before = pseudoElement(BEFORE))
1134 before->insertedInto(insertionPoint);
1136 if (Element* after = pseudoElement(AFTER))
1137 after->insertedInto(insertionPoint);
1139 if (!insertionPoint->isInTreeScope())
1140 return InsertionDone;
1143 elementRareData()->clearClassListValueForQuirksMode();
1145 TreeScope* scope = insertionPoint->treeScope();
1146 if (scope != treeScope())
1147 return InsertionDone;
1149 const AtomicString& idValue = getIdAttribute();
1150 if (!idValue.isNull())
1151 updateId(scope, nullAtom, idValue);
1153 const AtomicString& nameValue = getNameAttribute();
1154 if (!nameValue.isNull())
1155 updateName(nullAtom, nameValue);
1157 if (hasTagName(labelTag)) {
1158 if (scope->shouldCacheLabelsByForAttribute())
1159 updateLabel(scope, nullAtom, fastGetAttribute(forAttr));
1162 return InsertionDone;
1165 void Element::removedFrom(ContainerNode* insertionPoint)
1168 bool wasInDocument = insertionPoint->document();
1171 if (Element* before = pseudoElement(BEFORE))
1172 before->removedFrom(insertionPoint);
1174 if (Element* after = pseudoElement(AFTER))
1175 after->removedFrom(insertionPoint);
1177 #if ENABLE(DIALOG_ELEMENT)
1178 document()->removeFromTopLayer(this);
1180 #if ENABLE(FULLSCREEN_API)
1181 if (containsFullScreenElement())
1182 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
1184 #if ENABLE(POINTER_LOCK)
1185 if (document()->page())
1186 document()->page()->pointerLockController()->elementRemoved(this);
1189 setSavedLayerScrollOffset(IntSize());
1191 if (insertionPoint->isInTreeScope() && treeScope() == document()) {
1192 const AtomicString& idValue = getIdAttribute();
1193 if (!idValue.isNull())
1194 updateId(insertionPoint->treeScope(), idValue, nullAtom);
1196 const AtomicString& nameValue = getNameAttribute();
1197 if (!nameValue.isNull())
1198 updateName(nameValue, nullAtom);
1200 if (hasTagName(labelTag)) {
1201 TreeScope* treeScope = insertionPoint->treeScope();
1202 if (treeScope->shouldCacheLabelsByForAttribute())
1203 updateLabel(treeScope, fastGetAttribute(forAttr), nullAtom);
1207 ContainerNode::removedFrom(insertionPoint);
1209 if (wasInDocument && hasPendingResources())
1210 document()->accessSVGExtensions()->removeElementFromPendingResources(this);
1214 void Element::createRendererIfNeeded()
1216 NodeRenderingContext(this).createRendererForElementIfNeeded();
1219 void Element::attach()
1221 PostAttachCallbackDisabler callbackDisabler(this);
1222 StyleResolverParentPusher parentPusher(this);
1223 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1225 createRendererIfNeeded();
1227 if (parentElement() && parentElement()->isInCanvasSubtree())
1228 setIsInCanvasSubtree(true);
1230 updatePseudoElement(BEFORE);
1232 // When a shadow root exists, it does the work of attaching the children.
1233 if (ElementShadow* shadow = this->shadow()) {
1234 parentPusher.push();
1236 } else if (firstChild())
1237 parentPusher.push();
1239 ContainerNode::attach();
1241 updatePseudoElement(AFTER);
1243 if (hasRareData()) {
1244 ElementRareData* data = elementRareData();
1245 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
1246 if (isFocusable() && document()->focusedNode() == this)
1247 document()->updateFocusAppearanceSoon(false /* don't restore selection */);
1248 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1253 void Element::unregisterNamedFlowContentNode()
1255 if (document()->cssRegionsEnabled() && inNamedFlow() && document()->renderView())
1256 document()->renderView()->flowThreadController()->unregisterNamedFlowContentNode(this);
1259 void Element::detach()
1261 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1262 unregisterNamedFlowContentNode();
1263 cancelFocusAppearanceUpdate();
1264 if (hasRareData()) {
1265 ElementRareData* data = elementRareData();
1266 data->setPseudoElement(BEFORE, 0);
1267 data->setPseudoElement(AFTER, 0);
1268 data->setIsInCanvasSubtree(false);
1269 data->resetComputedStyle();
1270 data->resetDynamicRestyleObservations();
1273 if (ElementShadow* shadow = this->shadow()) {
1274 detachChildrenIfNeeded();
1277 ContainerNode::detach();
1280 bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle)
1282 ASSERT(currentStyle == renderStyle());
1288 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles();
1289 if (!pseudoStyleCache)
1292 size_t cacheSize = pseudoStyleCache->size();
1293 for (size_t i = 0; i < cacheSize; ++i) {
1294 RefPtr<RenderStyle> newPseudoStyle;
1295 PseudoId pseudoId = pseudoStyleCache->at(i)->styleType();
1296 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
1297 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle);
1299 newPseudoStyle = renderer()->getUncachedPseudoStyle(pseudoId, newStyle, newStyle);
1300 if (!newPseudoStyle)
1302 if (*newPseudoStyle != *pseudoStyleCache->at(i)) {
1303 if (pseudoId < FIRST_INTERNAL_PSEUDOID)
1304 newStyle->setHasPseudoStyle(pseudoId);
1305 newStyle->addCachedPseudoStyle(newPseudoStyle);
1306 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
1307 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
1308 // is needed, but for now just assume a layout will be required. The diff code
1309 // in RenderObject::setStyle would need to be factored out so that it could be reused.
1310 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
1318 PassRefPtr<RenderStyle> Element::styleForRenderer()
1320 if (hasCustomCallbacks()) {
1321 if (RefPtr<RenderStyle> style = customStyleForRenderer())
1322 return style.release();
1325 return document()->styleResolver()->styleForElement(this);
1328 void Element::recalcStyle(StyleChange change)
1330 if (hasCustomCallbacks()) {
1331 if (!willRecalcStyle(change))
1335 // Ref currentStyle in case it would otherwise be deleted when setting the new style in the renderer.
1336 RefPtr<RenderStyle> currentStyle(renderStyle());
1337 bool hasParentStyle = parentNodeForRenderingAndStyle() ? static_cast<bool>(parentNodeForRenderingAndStyle()->renderStyle()) : false;
1338 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
1339 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
1341 if ((change > NoChange || needsStyleRecalc())) {
1343 elementRareData()->resetComputedStyle();
1345 if (hasParentStyle && (change >= Inherit || needsStyleRecalc())) {
1346 RefPtr<RenderStyle> newStyle = styleForRenderer();
1347 StyleChange ch = Node::diff(currentStyle.get(), newStyle.get(), document());
1348 if (ch == Detach || !currentStyle) {
1349 // FIXME: The style gets computed twice by calling attach. We could do better if we passed the style along.
1351 // attach recalculates the style for all children. No need to do it twice.
1352 clearNeedsStyleRecalc();
1353 clearChildNeedsStyleRecalc();
1355 if (hasCustomCallbacks())
1356 didRecalcStyle(change);
1360 if (RenderObject* renderer = this->renderer()) {
1361 if (ch != NoChange || pseudoStyleCacheIsInvalid(currentStyle.get(), newStyle.get()) || (change == Force && renderer->requiresForcedStyleRecalcPropagation()) || styleChangeType() == SyntheticStyleChange)
1362 renderer->setAnimatableStyle(newStyle.get());
1363 else if (needsStyleRecalc()) {
1364 // Although no change occurred, we use the new style so that the cousin style sharing code won't get
1365 // fooled into believing this style is the same.
1366 renderer->setStyleInternal(newStyle.get());
1370 // 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
1371 // 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).
1372 if (document()->styleSheetCollection()->usesRemUnits() && document()->documentElement() == this && ch != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize()) {
1373 // Cached RenderStyles may depend on the re units.
1374 document()->styleResolver()->invalidateMatchedPropertiesCache();
1378 if (change != Force) {
1379 if (styleChangeType() >= FullStyleChange)
1385 StyleResolverParentPusher parentPusher(this);
1387 // FIXME: This does not care about sibling combinators. Will be necessary in XBL2 world.
1388 if (ElementShadow* shadow = this->shadow()) {
1389 if (change >= Inherit || shadow->childNeedsStyleRecalc() || shadow->needsStyleRecalc()) {
1390 parentPusher.push();
1391 shadow->recalcStyle(change);
1395 updatePseudoElement(BEFORE, change);
1397 // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
1398 // For now we will just worry about the common case, since it's a lot trickier to get the second case right
1399 // without doing way too much re-resolution.
1400 bool forceCheckOfNextElementSibling = false;
1401 bool forceCheckOfAnyElementSibling = false;
1402 for (Node *n = firstChild(); n; n = n->nextSibling()) {
1403 if (n->isTextNode()) {
1404 toText(n)->recalcTextStyle(change);
1407 if (!n->isElementNode())
1409 Element* element = static_cast<Element*>(n);
1410 bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() == FullStyleChange;
1411 if ((forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling))
1412 element->setNeedsStyleRecalc();
1413 if (change >= Inherit || element->childNeedsStyleRecalc() || element->needsStyleRecalc()) {
1414 parentPusher.push();
1415 element->recalcStyle(change);
1417 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
1418 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
1421 updatePseudoElement(AFTER, change);
1423 clearNeedsStyleRecalc();
1424 clearChildNeedsStyleRecalc();
1426 if (hasCustomCallbacks())
1427 didRecalcStyle(change);
1430 ElementShadow* Element::shadow() const
1432 return hasRareData() ? elementRareData()->shadow() : 0;
1435 ElementShadow* Element::ensureShadow()
1437 return ensureElementRareData()->ensureShadow();
1440 void Element::didAffectSelector(AffectedSelectorMask mask)
1442 setNeedsStyleRecalc();
1443 if (ElementShadow* elementShadow = shadowOfParentForDistribution(this))
1444 elementShadow->didAffectSelector(mask);
1447 PassRefPtr<ShadowRoot> Element::createShadowRoot(ExceptionCode& ec)
1449 if (alwaysCreateUserAgentShadowRoot())
1450 ensureUserAgentShadowRoot();
1452 #if ENABLE(SHADOW_DOM)
1453 if (RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled())
1454 return ensureShadow()->addShadowRoot(this, ShadowRoot::AuthorShadowRoot);
1457 // Since some elements recreates shadow root dynamically, multiple shadow
1458 // subtrees won't work well in that element. Until they are fixed, we disable
1459 // adding author shadow root for them.
1460 if (!areAuthorShadowsAllowed()) {
1461 ec = HIERARCHY_REQUEST_ERR;
1464 return ensureShadow()->addShadowRoot(this, ShadowRoot::AuthorShadowRoot);
1467 ShadowRoot* Element::shadowRoot() const
1469 ElementShadow* elementShadow = shadow();
1472 ShadowRoot* shadowRoot = elementShadow->youngestShadowRoot();
1473 if (shadowRoot->type() == ShadowRoot::AuthorShadowRoot)
1478 ShadowRoot* Element::userAgentShadowRoot() const
1480 if (ElementShadow* elementShadow = shadow()) {
1481 if (ShadowRoot* shadowRoot = elementShadow->oldestShadowRoot()) {
1482 ASSERT(shadowRoot->type() == ShadowRoot::UserAgentShadowRoot);
1490 ShadowRoot* Element::ensureUserAgentShadowRoot()
1492 if (ShadowRoot* shadowRoot = userAgentShadowRoot())
1494 ShadowRoot* shadowRoot = ensureShadow()->addShadowRoot(this, ShadowRoot::UserAgentShadowRoot);
1495 didAddUserAgentShadowRoot(shadowRoot);
1499 const AtomicString& Element::shadowPseudoId() const
1504 bool Element::childTypeAllowed(NodeType type) const
1510 case PROCESSING_INSTRUCTION_NODE:
1511 case CDATA_SECTION_NODE:
1512 case ENTITY_REFERENCE_NODE:
1520 static void checkForEmptyStyleChange(Element* element, RenderStyle* style)
1522 if (!style && !element->styleAffectedByEmpty())
1525 if (!style || (element->styleAffectedByEmpty() && (!style->emptyState() || element->hasChildNodes())))
1526 element->setNeedsStyleRecalc();
1529 static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
1530 Node* beforeChange, Node* afterChange, int childCountDelta)
1533 checkForEmptyStyleChange(e, style);
1535 if (!style || (e->needsStyleRecalc() && e->childrenAffectedByPositionalRules()))
1538 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1539 // In the DOM case, we only need to do something if |afterChange| is not 0.
1540 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
1541 if (e->childrenAffectedByFirstChildRules() && afterChange) {
1542 // Find our new first child.
1543 Node* newFirstChild = 0;
1544 for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {};
1546 // Find the first element node following |afterChange|
1547 Node* firstElementAfterInsertion = 0;
1548 for (firstElementAfterInsertion = afterChange;
1549 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
1550 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
1552 // This is the insert/append case.
1553 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertion && firstElementAfterInsertion->attached() &&
1554 firstElementAfterInsertion->renderStyle() && firstElementAfterInsertion->renderStyle()->firstChildState())
1555 firstElementAfterInsertion->setNeedsStyleRecalc();
1557 // We also have to handle node removal.
1558 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChild->renderStyle() || !newFirstChild->renderStyle()->firstChildState()))
1559 newFirstChild->setNeedsStyleRecalc();
1562 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1563 // In the DOM case, we only need to do something if |afterChange| is not 0.
1564 if (e->childrenAffectedByLastChildRules() && beforeChange) {
1565 // Find our new last child.
1566 Node* newLastChild = 0;
1567 for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {};
1569 // Find the last element node going backwards from |beforeChange|
1570 Node* lastElementBeforeInsertion = 0;
1571 for (lastElementBeforeInsertion = beforeChange;
1572 lastElementBeforeInsertion && !lastElementBeforeInsertion->isElementNode();
1573 lastElementBeforeInsertion = lastElementBeforeInsertion->previousSibling()) {};
1575 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertion && lastElementBeforeInsertion->attached() &&
1576 lastElementBeforeInsertion->renderStyle() && lastElementBeforeInsertion->renderStyle()->lastChildState())
1577 lastElementBeforeInsertion->setNeedsStyleRecalc();
1579 // 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
1581 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChild->renderStyle() || !newLastChild->renderStyle()->lastChildState()))
1582 newLastChild->setNeedsStyleRecalc();
1585 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
1586 // that could be affected by this DOM change.
1587 if (e->childrenAffectedByDirectAdjacentRules() && afterChange) {
1588 Node* firstElementAfterInsertion = 0;
1589 for (firstElementAfterInsertion = afterChange;
1590 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
1591 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
1592 if (firstElementAfterInsertion && firstElementAfterInsertion->attached())
1593 firstElementAfterInsertion->setNeedsStyleRecalc();
1596 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
1597 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1598 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
1600 // |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.
1601 // 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
1602 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
1603 if ((e->childrenAffectedByForwardPositionalRules() && afterChange)
1604 || (e->childrenAffectedByBackwardPositionalRules() && beforeChange))
1605 e->setNeedsStyleRecalc();
1608 void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
1610 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
1611 if (changedByParser)
1612 checkForEmptyStyleChange(this, renderStyle());
1614 checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
1616 if (ElementShadow * shadow = this->shadow())
1617 shadow->invalidateDistribution();
1620 void Element::beginParsingChildren()
1622 clearIsParsingChildrenFinished();
1623 StyleResolver* styleResolver = document()->styleResolverIfExists();
1624 if (styleResolver && attached())
1625 styleResolver->pushParentElement(this);
1628 void Element::finishParsingChildren()
1630 ContainerNode::finishParsingChildren();
1631 setIsParsingChildrenFinished();
1632 checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
1633 if (StyleResolver* styleResolver = document()->styleResolverIfExists())
1634 styleResolver->popParentElement(this);
1638 void Element::formatForDebugger(char* buffer, unsigned length) const
1640 StringBuilder result;
1643 result.append(nodeName());
1645 s = getIdAttribute();
1646 if (s.length() > 0) {
1647 if (result.length() > 0)
1648 result.appendLiteral("; ");
1649 result.appendLiteral("id=");
1653 s = getAttribute(classAttr);
1654 if (s.length() > 0) {
1655 if (result.length() > 0)
1656 result.appendLiteral("; ");
1657 result.appendLiteral("class=");
1661 strncpy(buffer, result.toString().utf8().data(), length - 1);
1665 const Vector<RefPtr<Attr> >& Element::attrNodeList()
1667 ASSERT(hasSyntheticAttrChildNodes());
1668 return *attrNodeListForElement(this);
1671 PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionCode& ec)
1674 ec = TYPE_MISMATCH_ERR;
1678 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName());
1679 if (oldAttrNode.get() == attrNode)
1680 return attrNode; // This Attr is already attached to the element.
1682 // INUSE_ATTRIBUTE_ERR: Raised if node is an Attr that is already an attribute of another Element object.
1683 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
1684 if (attrNode->ownerElement()) {
1685 ec = INUSE_ATTRIBUTE_ERR;
1689 updateInvalidAttributes();
1690 UniqueElementData* elementData = ensureUniqueElementData();
1692 size_t index = elementData->getAttributeItemIndex(attrNode->qualifiedName());
1693 if (index != notFound) {
1695 detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData->attributeItem(index)->value());
1697 oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), elementData->attributeItem(index)->value());
1700 setAttributeInternal(index, attrNode->qualifiedName(), attrNode->value(), NotInSynchronizationOfLazyAttribute);
1702 attrNode->attachToElement(this);
1703 ensureAttrNodeListForElement(this)->append(attrNode);
1705 return oldAttrNode.release();
1708 PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionCode& ec)
1710 return setAttributeNode(attr, ec);
1713 PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec)
1716 ec = TYPE_MISMATCH_ERR;
1719 if (attr->ownerElement() != this) {
1724 ASSERT(document() == attr->document());
1726 const ElementData* elementData = elementDataWithSynchronizedAttributes();
1727 ASSERT(elementData);
1729 size_t index = elementData->getAttributeItemIndex(attr->qualifiedName());
1730 if (index == notFound) {
1735 return detachAttribute(index);
1738 bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionCode& ec)
1740 String prefix, localName;
1741 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec))
1745 QualifiedName qName(prefix, localName, namespaceURI);
1747 if (!Document::hasValidNamespaceForAttributes(qName)) {
1756 void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode& ec)
1758 QualifiedName parsedName = anyName;
1759 if (!parseAttributeName(parsedName, namespaceURI, qualifiedName, ec))
1761 setAttribute(parsedName, value);
1764 void Element::removeAttributeInternal(size_t index, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1766 ASSERT_WITH_SECURITY_IMPLICATION(index < attributeCount());
1768 UniqueElementData* elementData = ensureUniqueElementData();
1770 QualifiedName name = elementData->attributeItem(index)->name();
1771 AtomicString valueBeingRemoved = elementData->attributeItem(index)->value();
1773 if (!inSynchronizationOfLazyAttribute) {
1774 if (!valueBeingRemoved.isNull())
1775 willModifyAttribute(name, valueBeingRemoved, nullAtom);
1778 if (RefPtr<Attr> attrNode = attrIfExists(name))
1779 detachAttrNodeFromElementWithValue(attrNode.get(), elementData->attributeItem(index)->value());
1781 elementData->removeAttribute(index);
1783 if (!inSynchronizationOfLazyAttribute)
1784 didRemoveAttribute(name);
1787 void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1789 if (!inSynchronizationOfLazyAttribute)
1790 willModifyAttribute(name, nullAtom, value);
1791 ensureUniqueElementData()->addAttribute(name, value);
1792 if (!inSynchronizationOfLazyAttribute)
1793 didAddAttribute(name, value);
1796 void Element::removeAttribute(const AtomicString& name)
1801 AtomicString localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1802 size_t index = elementData()->getAttributeItemIndex(localName, false);
1803 if (index == notFound) {
1804 if (UNLIKELY(localName == styleAttr) && elementData()->m_styleAttributeIsDirty && isStyledElement())
1805 static_cast<StyledElement*>(this)->removeAllInlineStyleProperties();
1809 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
1812 void Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName)
1814 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI));
1817 PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& name)
1819 const ElementData* elementData = elementDataWithSynchronizedAttributes();
1822 const Attribute* attribute = elementData->getAttributeItem(name, shouldIgnoreAttributeCase(this));
1825 return ensureAttr(attribute->name());
1828 PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
1830 const ElementData* elementData = elementDataWithSynchronizedAttributes();
1833 const Attribute* attribute = elementData->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI));
1836 return ensureAttr(attribute->name());
1839 bool Element::hasAttribute(const AtomicString& name) const
1844 // This call to String::lower() seems to be required but
1845 // there may be a way to remove it.
1846 AtomicString localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1847 return elementDataWithSynchronizedAttributes()->getAttributeItem(localName, false);
1850 bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
1852 const ElementData* elementData = elementDataWithSynchronizedAttributes();
1855 return elementData->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI));
1858 CSSStyleDeclaration *Element::style()
1863 void Element::focus(bool restorePreviousSelection, FocusDirection direction)
1868 Document* doc = document();
1869 if (doc->focusedNode() == this)
1872 // If the stylesheets have already been loaded we can reliably check isFocusable.
1873 // If not, we continue and set the focused node on the focus controller below so
1874 // that it can be updated soon after attach.
1875 if (doc->haveStylesheetsLoaded()) {
1876 doc->updateLayoutIgnorePendingStylesheets();
1881 if (!supportsFocus())
1884 RefPtr<Node> protect;
1885 if (Page* page = doc->page()) {
1886 // Focus and change event handlers can cause us to lose our last ref.
1887 // If a focus event handler changes the focus to a different node it
1888 // does not make sense to continue and update appearence.
1890 if (!page->focusController()->setFocusedNode(this, doc->frame(), direction))
1894 // Setting the focused node above might have invalidated the layout due to scripts.
1895 doc->updateLayoutIgnorePendingStylesheets();
1897 if (!isFocusable()) {
1898 ensureElementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
1902 cancelFocusAppearanceUpdate();
1903 updateFocusAppearance(restorePreviousSelection);
1906 void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
1908 if (isRootEditableElement()) {
1909 Frame* frame = document()->frame();
1913 // When focusing an editable element in an iframe, don't reset the selection if it already contains a selection.
1914 if (this == frame->selection()->rootEditableElement())
1917 // FIXME: We should restore the previous selection if there is one.
1918 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
1920 if (frame->selection()->shouldChangeSelection(newSelection)) {
1921 frame->selection()->setSelection(newSelection);
1922 frame->selection()->revealSelection();
1924 } else if (renderer() && !renderer()->isWidget())
1925 renderer()->scrollRectToVisible(boundingBox());
1928 void Element::blur()
1930 cancelFocusAppearanceUpdate();
1931 Document* doc = document();
1932 if (treeScope()->focusedNode() == this) {
1934 doc->frame()->page()->focusController()->setFocusedNode(0, doc->frame());
1936 doc->setFocusedNode(0);
1940 String Element::innerText()
1942 // We need to update layout, since plainText uses line boxes in the render tree.
1943 document()->updateLayoutIgnorePendingStylesheets();
1946 return textContent(true);
1948 return plainText(rangeOfContents(const_cast<Element*>(this)).get());
1951 String Element::outerText()
1953 // Getting outerText is the same as getting innerText, only
1954 // setting is different. You would think this should get the plain
1955 // text for the outer range, but this is wrong, <br> for instance
1956 // would return different values for inner and outer text by such
1957 // a rule, but it doesn't in WinIE, and we want to match that.
1961 String Element::title() const
1966 const AtomicString& Element::pseudo() const
1968 return getAttribute(pseudoAttr);
1971 void Element::setPseudo(const AtomicString& value)
1973 setAttribute(pseudoAttr, value);
1976 LayoutSize Element::minimumSizeForResizing() const
1978 return hasRareData() ? elementRareData()->minimumSizeForResizing() : defaultMinimumSizeForResizing();
1981 void Element::setMinimumSizeForResizing(const LayoutSize& size)
1983 if (!hasRareData() && size == defaultMinimumSizeForResizing())
1985 ensureElementRareData()->setMinimumSizeForResizing(size);
1988 RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
1990 if (PseudoElement* element = pseudoElement(pseudoElementSpecifier))
1991 return element->computedStyle();
1993 // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
1994 // properties, which are only known by the renderer because it did the layout, will be correct and so that the
1995 // values returned for the ":selection" pseudo-element will be correct.
1996 if (RenderStyle* usedStyle = renderStyle()) {
1997 if (pseudoElementSpecifier) {
1998 RenderStyle* cachedPseudoStyle = usedStyle->getCachedPseudoStyle(pseudoElementSpecifier);
1999 return cachedPseudoStyle ? cachedPseudoStyle : usedStyle;
2005 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
2006 // document tree and figure out when to destroy the computed style for such elements.
2009 ElementRareData* data = ensureElementRareData();
2010 if (!data->computedStyle())
2011 data->setComputedStyle(document()->styleForElementIgnoringPendingStylesheets(this));
2012 return pseudoElementSpecifier ? data->computedStyle()->getCachedPseudoStyle(pseudoElementSpecifier) : data->computedStyle();
2015 void Element::setStyleAffectedByEmpty()
2017 ensureElementRareData()->setStyleAffectedByEmpty(true);
2020 void Element::setChildrenAffectedByHover(bool value)
2022 if (value || hasRareData())
2023 ensureElementRareData()->setChildrenAffectedByHover(value);
2026 void Element::setChildrenAffectedByActive(bool value)
2028 if (value || hasRareData())
2029 ensureElementRareData()->setChildrenAffectedByActive(value);
2032 void Element::setChildrenAffectedByDrag(bool value)
2034 if (value || hasRareData())
2035 ensureElementRareData()->setChildrenAffectedByDrag(value);
2038 void Element::setChildrenAffectedByFirstChildRules()
2040 ensureElementRareData()->setChildrenAffectedByFirstChildRules(true);
2043 void Element::setChildrenAffectedByLastChildRules()
2045 ensureElementRareData()->setChildrenAffectedByLastChildRules(true);
2048 void Element::setChildrenAffectedByDirectAdjacentRules()
2050 ensureElementRareData()->setChildrenAffectedByDirectAdjacentRules(true);
2053 void Element::setChildrenAffectedByForwardPositionalRules()
2055 ensureElementRareData()->setChildrenAffectedByForwardPositionalRules(true);
2058 void Element::setChildrenAffectedByBackwardPositionalRules()
2060 ensureElementRareData()->setChildrenAffectedByBackwardPositionalRules(true);
2063 void Element::setChildIndex(unsigned index)
2065 ElementRareData* rareData = ensureElementRareData();
2066 if (RenderStyle* style = renderStyle())
2068 rareData->setChildIndex(index);
2071 bool Element::hasFlagsSetDuringStylingOfChildren() const
2075 return rareDataChildrenAffectedByHover()
2076 || rareDataChildrenAffectedByActive()
2077 || rareDataChildrenAffectedByDrag()
2078 || rareDataChildrenAffectedByFirstChildRules()
2079 || rareDataChildrenAffectedByLastChildRules()
2080 || rareDataChildrenAffectedByDirectAdjacentRules()
2081 || rareDataChildrenAffectedByForwardPositionalRules()
2082 || rareDataChildrenAffectedByBackwardPositionalRules();
2085 bool Element::rareDataStyleAffectedByEmpty() const
2087 ASSERT(hasRareData());
2088 return elementRareData()->styleAffectedByEmpty();
2091 bool Element::rareDataChildrenAffectedByHover() const
2093 ASSERT(hasRareData());
2094 return elementRareData()->childrenAffectedByHover();
2097 bool Element::rareDataChildrenAffectedByActive() const
2099 ASSERT(hasRareData());
2100 return elementRareData()->childrenAffectedByActive();
2103 bool Element::rareDataChildrenAffectedByDrag() const
2105 ASSERT(hasRareData());
2106 return elementRareData()->childrenAffectedByDrag();
2109 bool Element::rareDataChildrenAffectedByFirstChildRules() const
2111 ASSERT(hasRareData());
2112 return elementRareData()->childrenAffectedByFirstChildRules();
2115 bool Element::rareDataChildrenAffectedByLastChildRules() const
2117 ASSERT(hasRareData());
2118 return elementRareData()->childrenAffectedByLastChildRules();
2121 bool Element::rareDataChildrenAffectedByDirectAdjacentRules() const
2123 ASSERT(hasRareData());
2124 return elementRareData()->childrenAffectedByDirectAdjacentRules();
2127 bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
2129 ASSERT(hasRareData());
2130 return elementRareData()->childrenAffectedByForwardPositionalRules();
2133 bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
2135 ASSERT(hasRareData());
2136 return elementRareData()->childrenAffectedByBackwardPositionalRules();
2139 unsigned Element::rareDataChildIndex() const
2141 ASSERT(hasRareData());
2142 return elementRareData()->childIndex();
2145 void Element::setIsInCanvasSubtree(bool isInCanvasSubtree)
2147 ensureElementRareData()->setIsInCanvasSubtree(isInCanvasSubtree);
2150 bool Element::isInCanvasSubtree() const
2152 return hasRareData() && elementRareData()->isInCanvasSubtree();
2155 AtomicString Element::computeInheritedLanguage() const
2157 const Node* n = this;
2159 // The language property is inherited, so we iterate over the parents to find the first language.
2161 if (n->isElementNode()) {
2162 if (const ElementData* elementData = static_cast<const Element*>(n)->elementData()) {
2163 // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7
2164 if (const Attribute* attribute = elementData->getAttributeItem(XMLNames::langAttr))
2165 value = attribute->value();
2166 else if (const Attribute* attribute = elementData->getAttributeItem(HTMLNames::langAttr))
2167 value = attribute->value();
2169 } else if (n->isDocumentNode()) {
2170 // checking the MIME content-language
2171 value = static_cast<const Document*>(n)->contentLanguage();
2174 n = n->parentNode();
2175 } while (n && value.isNull());
2180 Locale& Element::locale() const
2182 return document()->getCachedLocale(computeInheritedLanguage());
2185 void Element::cancelFocusAppearanceUpdate()
2188 elementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
2189 if (document()->focusedNode() == this)
2190 document()->cancelFocusAppearanceUpdate();
2193 void Element::normalizeAttributes()
2195 if (!hasAttributes())
2197 for (unsigned i = 0; i < attributeCount(); ++i) {
2198 if (RefPtr<Attr> attr = attrIfExists(attributeItem(i)->name()))
2203 void Element::updatePseudoElement(PseudoId pseudoId, StyleChange change)
2205 PseudoElement* existing = pseudoElement(pseudoId);
2207 // PseudoElement styles hang off their parent element's style so if we needed
2208 // a style recalc we should Force one on the pseudo.
2209 existing->recalcStyle(needsStyleRecalc() ? Force : change);
2211 // Wait until our parent is not displayed or pseudoElementRendererIsNeeded
2212 // is false, otherwise we could continously create and destroy PseudoElements
2213 // when RenderObject::isChildAllowed on our parent returns false for the
2214 // PseudoElement's renderer for each style recalc.
2215 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
2216 setPseudoElement(pseudoId, 0);
2217 } else if (RefPtr<PseudoElement> element = createPseudoElementIfNeeded(pseudoId)) {
2219 setPseudoElement(pseudoId, element.release());
2223 PassRefPtr<PseudoElement> Element::createPseudoElementIfNeeded(PseudoId pseudoId)
2225 if (!document()->styleSheetCollection()->usesBeforeAfterRules())
2228 if (!renderer() || !renderer()->canHaveGeneratedChildren())
2231 if (isPseudoElement())
2234 if (!pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
2237 return PseudoElement::create(this, pseudoId);
2240 bool Element::hasPseudoElements() const
2242 return hasRareData() && elementRareData()->hasPseudoElements();
2245 PseudoElement* Element::pseudoElement(PseudoId pseudoId) const
2247 return hasRareData() ? elementRareData()->pseudoElement(pseudoId) : 0;
2250 void Element::setPseudoElement(PseudoId pseudoId, PassRefPtr<PseudoElement> element)
2252 ensureElementRareData()->setPseudoElement(pseudoId, element);
2253 resetNeedsShadowTreeWalker();
2256 RenderObject* Element::pseudoElementRenderer(PseudoId pseudoId) const
2258 if (PseudoElement* element = pseudoElement(pseudoId))
2259 return element->renderer();
2263 // ElementTraversal API
2264 Element* Element::firstElementChild() const
2266 return ElementTraversal::firstWithin(this);
2269 Element* Element::lastElementChild() const
2271 Node* n = lastChild();
2272 while (n && !n->isElementNode())
2273 n = n->previousSibling();
2274 return static_cast<Element*>(n);
2277 unsigned Element::childElementCount() const
2280 Node* n = firstChild();
2282 count += n->isElementNode();
2283 n = n->nextSibling();
2288 bool Element::matchesReadOnlyPseudoClass() const
2293 bool Element::matchesReadWritePseudoClass() const
2298 bool Element::webkitMatchesSelector(const String& selector, ExceptionCode& ec)
2300 if (selector.isEmpty()) {
2305 SelectorQuery* selectorQuery = document()->selectorQueryCache()->add(selector, document(), ec);
2308 return selectorQuery->matches(this);
2311 DOMTokenList* Element::classList()
2313 ElementRareData* data = ensureElementRareData();
2314 if (!data->classList())
2315 data->setClassList(ClassList::create(this));
2316 return data->classList();
2319 DOMStringMap* Element::dataset()
2321 ElementRareData* data = ensureElementRareData();
2322 if (!data->dataset())
2323 data->setDataset(DatasetDOMStringMap::create(this));
2324 return data->dataset();
2327 KURL Element::getURLAttribute(const QualifiedName& name) const
2329 #if !ASSERT_DISABLED
2330 if (elementData()) {
2331 if (const Attribute* attribute = getAttributeItem(name))
2332 ASSERT(isURLAttribute(*attribute));
2335 return document()->completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
2338 KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
2340 #if !ASSERT_DISABLED
2341 if (elementData()) {
2342 if (const Attribute* attribute = getAttributeItem(name))
2343 ASSERT(isURLAttribute(*attribute));
2346 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
2347 if (value.isEmpty())
2349 return document()->completeURL(value);
2352 int Element::getIntegralAttribute(const QualifiedName& attributeName) const
2354 return getAttribute(attributeName).string().toInt();
2357 void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
2359 // FIXME: Need an AtomicString version of String::number.
2360 setAttribute(attributeName, String::number(value));
2363 unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
2365 return getAttribute(attributeName).string().toUInt();
2368 void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
2370 // FIXME: Need an AtomicString version of String::number.
2371 setAttribute(attributeName, String::number(value));
2375 bool Element::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
2377 // Only create renderers for SVG elements whose parents are SVG elements, or for proper <svg xmlns="svgNS"> subdocuments.
2378 if (childContext.node()->isSVGElement())
2379 return childContext.node()->hasTagName(SVGNames::svgTag) || isSVGElement();
2381 return ContainerNode::childShouldCreateRenderer(childContext);
2385 #if ENABLE(FULLSCREEN_API)
2386 void Element::webkitRequestFullscreen()
2388 document()->requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, Document::EnforceIFrameAllowFullScreenRequirement);
2391 void Element::webkitRequestFullScreen(unsigned short flags)
2393 document()->requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), Document::EnforceIFrameAllowFullScreenRequirement);
2396 bool Element::containsFullScreenElement() const
2398 return hasRareData() && elementRareData()->containsFullScreenElement();
2401 void Element::setContainsFullScreenElement(bool flag)
2403 ensureElementRareData()->setContainsFullScreenElement(flag);
2404 setNeedsStyleRecalc(SyntheticStyleChange);
2407 static Element* parentCrossingFrameBoundaries(Element* element)
2410 return element->parentElement() ? element->parentElement() : element->document()->ownerElement();
2413 void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool flag)
2415 Element* element = this;
2416 while ((element = parentCrossingFrameBoundaries(element)))
2417 element->setContainsFullScreenElement(flag);
2421 #if ENABLE(DIALOG_ELEMENT)
2422 bool Element::isInTopLayer() const
2424 return hasRareData() && elementRareData()->isInTopLayer();
2427 void Element::setIsInTopLayer(bool inTopLayer)
2429 if (isInTopLayer() == inTopLayer)
2431 ensureElementRareData()->setIsInTopLayer(inTopLayer);
2433 // We must ensure a reattach occurs so the renderer is inserted in the correct sibling order under RenderView according to its
2434 // top layer position, or in its usual place if not in the top layer.
2435 reattachIfAttached();
2439 #if ENABLE(POINTER_LOCK)
2440 void Element::webkitRequestPointerLock()
2442 if (document()->page())
2443 document()->page()->pointerLockController()->requestPointerLock(this);
2447 SpellcheckAttributeState Element::spellcheckAttributeState() const
2449 const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
2450 if (value == nullAtom)
2451 return SpellcheckAttributeDefault;
2452 if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
2453 return SpellcheckAttributeTrue;
2454 if (equalIgnoringCase(value, "false"))
2455 return SpellcheckAttributeFalse;
2457 return SpellcheckAttributeDefault;
2460 bool Element::isSpellCheckingEnabled() const
2462 for (const Element* element = this; element; element = element->parentOrShadowHostElement()) {
2463 switch (element->spellcheckAttributeState()) {
2464 case SpellcheckAttributeTrue:
2466 case SpellcheckAttributeFalse:
2468 case SpellcheckAttributeDefault:
2476 RenderRegion* Element::renderRegion() const
2478 if (renderer() && renderer()->isRenderRegion())
2479 return toRenderRegion(renderer());
2484 #if ENABLE(CSS_REGIONS)
2486 const AtomicString& Element::webkitRegionOverset() const
2488 document()->updateLayoutIgnorePendingStylesheets();
2490 DEFINE_STATIC_LOCAL(AtomicString, undefinedState, ("undefined", AtomicString::ConstructFromLiteral));
2491 if (!document()->cssRegionsEnabled() || !renderRegion())
2492 return undefinedState;
2494 switch (renderRegion()->regionState()) {
2495 case RenderRegion::RegionFit: {
2496 DEFINE_STATIC_LOCAL(AtomicString, fitState, ("fit", AtomicString::ConstructFromLiteral));
2499 case RenderRegion::RegionEmpty: {
2500 DEFINE_STATIC_LOCAL(AtomicString, emptyState, ("empty", AtomicString::ConstructFromLiteral));
2503 case RenderRegion::RegionOverset: {
2504 DEFINE_STATIC_LOCAL(AtomicString, overflowState, ("overset", AtomicString::ConstructFromLiteral));
2505 return overflowState;
2507 case RenderRegion::RegionUndefined:
2508 return undefinedState;
2511 ASSERT_NOT_REACHED();
2512 return undefinedState;
2515 Vector<RefPtr<Range> > Element::webkitGetRegionFlowRanges() const
2517 document()->updateLayoutIgnorePendingStylesheets();
2519 Vector<RefPtr<Range> > rangeObjects;
2520 if (document()->cssRegionsEnabled() && renderer() && renderer()->isRenderRegion()) {
2521 RenderRegion* region = toRenderRegion(renderer());
2522 if (region->isValid())
2523 region->getRanges(rangeObjects);
2526 return rangeObjects;
2532 bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
2534 if (name == HTMLNames::styleAttr)
2539 return !static_cast<const SVGElement*>(this)->isAnimatableAttribute(name);
2546 #ifdef DUMP_NODE_STATISTICS
2547 bool Element::hasNamedNodeMap() const
2549 return hasRareData() && elementRareData()->attributeMap();
2553 void Element::updateLabel(TreeScope* scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
2555 ASSERT(hasTagName(labelTag));
2560 if (oldForAttributeValue == newForAttributeValue)
2563 if (!oldForAttributeValue.isEmpty())
2564 scope->removeLabel(oldForAttributeValue, static_cast<HTMLLabelElement*>(this));
2565 if (!newForAttributeValue.isEmpty())
2566 scope->addLabel(newForAttributeValue, static_cast<HTMLLabelElement*>(this));
2569 void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
2571 if (isIdAttributeName(name))
2572 updateId(oldValue, newValue);
2573 else if (name == HTMLNames::nameAttr)
2574 updateName(oldValue, newValue);
2575 else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
2576 TreeScope* scope = treeScope();
2577 if (scope->shouldCacheLabelsByForAttribute())
2578 updateLabel(scope, oldValue, newValue);
2581 if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(this, name))
2582 recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue));
2584 #if ENABLE(INSPECTOR)
2585 InspectorInstrumentation::willModifyDOMAttr(document(), this, oldValue, newValue);
2589 void Element::didAddAttribute(const QualifiedName& name, const AtomicString& value)
2591 attributeChanged(name, value);
2592 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value);
2593 dispatchSubtreeModifiedEvent();
2596 void Element::didModifyAttribute(const QualifiedName& name, const AtomicString& value)
2598 attributeChanged(name, value);
2599 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value);
2600 // Do not dispatch a DOMSubtreeModified event here; see bug 81141.
2603 void Element::didRemoveAttribute(const QualifiedName& name)
2605 attributeChanged(name, nullAtom);
2606 InspectorInstrumentation::didRemoveDOMAttr(document(), this, name.localName());
2607 dispatchSubtreeModifiedEvent();
2611 void Element::updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName)
2613 if (!document()->isHTMLDocument())
2616 if (!oldName.isEmpty())
2617 static_cast<HTMLDocument*>(document())->removeNamedItem(oldName);
2619 if (!newName.isEmpty())
2620 static_cast<HTMLDocument*>(document())->addNamedItem(newName);
2623 void Element::updateExtraNamedItemRegistration(const AtomicString& oldId, const AtomicString& newId)
2625 if (!document()->isHTMLDocument())
2628 if (!oldId.isEmpty())
2629 static_cast<HTMLDocument*>(document())->removeExtraNamedItem(oldId);
2631 if (!newId.isEmpty())
2632 static_cast<HTMLDocument*>(document())->addExtraNamedItem(newId);
2635 PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
2637 if (HTMLCollection* collection = cachedHTMLCollection(type))
2640 RefPtr<HTMLCollection> collection;
2641 if (type == TableRows) {
2642 ASSERT(hasTagName(tableTag));
2643 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
2644 } else if (type == SelectOptions) {
2645 ASSERT(hasTagName(selectTag));
2646 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
2647 } else if (type == FormControls) {
2648 ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
2649 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
2650 #if ENABLE(MICRODATA)
2651 } else if (type == ItemProperties) {
2652 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLPropertiesCollection>(this, type);
2655 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLCollection>(this, type);
2658 HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
2660 return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0;
2663 IntSize Element::savedLayerScrollOffset() const
2665 return hasRareData() ? elementRareData()->savedLayerScrollOffset() : IntSize();
2668 void Element::setSavedLayerScrollOffset(const IntSize& size)
2670 if (size.isZero() && !hasRareData())
2672 ensureElementRareData()->setSavedLayerScrollOffset(size);
2675 PassRefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
2677 if (AttrNodeList* attrNodeList = attrNodeListForElement(this))
2678 return findAttrNodeInList(attrNodeList, name);
2682 PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name)
2684 AttrNodeList* attrNodeList = ensureAttrNodeListForElement(this);
2685 RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
2687 attrNode = Attr::create(this, name);
2688 attrNodeList->append(attrNode);
2690 return attrNode.release();
2693 void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value)
2695 ASSERT(hasSyntheticAttrChildNodes());
2696 attrNode->detachFromElementWithValue(value);
2698 AttrNodeList* attrNodeList = attrNodeListForElement(this);
2699 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
2700 if (attrNodeList->at(i)->qualifiedName() == attrNode->qualifiedName()) {
2701 attrNodeList->remove(i);
2702 if (attrNodeList->isEmpty())
2703 removeAttrNodeListForElement(this);
2707 ASSERT_NOT_REACHED();
2710 void Element::detachAllAttrNodesFromElement()
2712 AttrNodeList* attrNodeList = attrNodeListForElement(this);
2713 ASSERT(attrNodeList);
2715 for (unsigned i = 0; i < attributeCount(); ++i) {
2716 const Attribute* attribute = attributeItem(i);
2717 if (RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, attribute->name()))
2718 attrNode->detachFromElementWithValue(attribute->value());
2721 removeAttrNodeListForElement(this);
2724 bool Element::willRecalcStyle(StyleChange)
2726 ASSERT(hasCustomCallbacks());
2730 void Element::didRecalcStyle(StyleChange)
2732 ASSERT(hasCustomCallbacks());
2736 PassRefPtr<RenderStyle> Element::customStyleForRenderer()
2738 ASSERT(hasCustomCallbacks());
2742 void Element::cloneAttributesFromElement(const Element& other)
2744 if (hasSyntheticAttrChildNodes())
2745 detachAllAttrNodesFromElement();
2747 other.updateInvalidAttributes();
2748 if (!other.m_elementData) {
2749 m_elementData.clear();
2753 const AtomicString& oldID = getIdAttribute();
2754 const AtomicString& newID = other.getIdAttribute();
2756 if (!oldID.isNull() || !newID.isNull())
2757 updateId(oldID, newID);
2759 const AtomicString& oldName = getNameAttribute();
2760 const AtomicString& newName = other.getNameAttribute();
2762 if (!oldName.isNull() || !newName.isNull())
2763 updateName(oldName, newName);
2765 // If 'other' has a mutable ElementData, convert it to an immutable one so we can share it between both elements.
2766 // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes.
2767 if (other.m_elementData->isUnique()
2768 && !other.m_elementData->presentationAttributeStyle()
2769 && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper()))
2770 const_cast<Element&>(other).m_elementData = static_cast<const UniqueElementData*>(other.m_elementData.get())->makeShareableCopy();
2772 if (!other.m_elementData->isUnique())
2773 m_elementData = other.m_elementData;
2775 m_elementData = other.m_elementData->makeUniqueCopy();
2777 for (unsigned i = 0; i < m_elementData->length(); ++i) {
2778 const Attribute* attribute = const_cast<const ElementData*>(m_elementData.get())->attributeItem(i);
2779 attributeChanged(attribute->name(), attribute->value());
2783 void Element::cloneDataFromElement(const Element& other)
2785 cloneAttributesFromElement(other);
2786 copyNonAttributePropertiesFromElement(other);
2789 void Element::createUniqueElementData()
2792 m_elementData = UniqueElementData::create();
2794 ASSERT(!m_elementData->isUnique());
2795 m_elementData = static_cast<ShareableElementData*>(m_elementData.get())->makeUniqueCopy();
2799 void Element::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
2801 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
2802 ContainerNode::reportMemoryUsage(memoryObjectInfo);
2803 info.addMember(m_tagName, "tagName");
2804 info.addMember(m_elementData, "elementData");
2808 bool Element::hasPendingResources() const
2810 return hasRareData() && elementRareData()->hasPendingResources();
2813 void Element::setHasPendingResources()
2815 ensureElementRareData()->setHasPendingResources(true);
2818 void Element::clearHasPendingResources()
2820 ensureElementRareData()->setHasPendingResources(false);
2824 void ElementData::deref()
2830 delete static_cast<UniqueElementData*>(this);
2832 delete static_cast<ShareableElementData*>(this);
2835 ElementData::ElementData()
2838 , m_presentationAttributeStyleIsDirty(false)
2839 , m_styleAttributeIsDirty(false)
2841 , m_animatedSVGAttributesAreDirty(false)
2846 ElementData::ElementData(unsigned arraySize)
2848 , m_arraySize(arraySize)
2849 , m_presentationAttributeStyleIsDirty(false)
2850 , m_styleAttributeIsDirty(false)
2852 , m_animatedSVGAttributesAreDirty(false)
2857 struct SameSizeAsElementData : public RefCounted<SameSizeAsElementData> {
2862 COMPILE_ASSERT(sizeof(ElementData) == sizeof(SameSizeAsElementData), element_attribute_data_should_stay_small);
2864 static size_t sizeForShareableElementDataWithAttributeCount(unsigned count)
2866 return sizeof(ShareableElementData) + sizeof(Attribute) * count;
2869 PassRefPtr<ShareableElementData> ShareableElementData::createWithAttributes(const Vector<Attribute>& attributes)
2871 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(attributes.size()));
2872 return adoptRef(new (slot) ShareableElementData(attributes));
2875 PassRefPtr<UniqueElementData> UniqueElementData::create()
2877 return adoptRef(new UniqueElementData);
2880 ShareableElementData::ShareableElementData(const Vector<Attribute>& attributes)
2881 : ElementData(attributes.size())
2883 for (unsigned i = 0; i < m_arraySize; ++i)
2884 new (&m_attributeArray[i]) Attribute(attributes[i]);
2887 ShareableElementData::~ShareableElementData()
2889 for (unsigned i = 0; i < m_arraySize; ++i)
2890 m_attributeArray[i].~Attribute();
2893 ShareableElementData::ShareableElementData(const UniqueElementData& other)
2894 : ElementData(other, false)
2896 ASSERT(!other.m_presentationAttributeStyle);
2898 if (other.m_inlineStyle) {
2899 ASSERT(!other.m_inlineStyle->hasCSSOMWrapper());
2900 m_inlineStyle = other.m_inlineStyle->immutableCopyIfNeeded();
2903 for (unsigned i = 0; i < m_arraySize; ++i)
2904 new (&m_attributeArray[i]) Attribute(other.m_attributeVector.at(i));
2907 ElementData::ElementData(const ElementData& other, bool isUnique)
2908 : m_isUnique(isUnique)
2909 , m_arraySize(isUnique ? 0 : other.length())
2910 , m_presentationAttributeStyleIsDirty(other.m_presentationAttributeStyleIsDirty)
2911 , m_styleAttributeIsDirty(other.m_styleAttributeIsDirty)
2913 , m_animatedSVGAttributesAreDirty(other.m_animatedSVGAttributesAreDirty)
2915 , m_classNames(other.m_classNames)
2916 , m_idForStyleResolution(other.m_idForStyleResolution)
2918 // NOTE: The inline style is copied by the subclass copy constructor since we don't know what to do with it here.
2921 UniqueElementData::UniqueElementData()
2925 UniqueElementData::UniqueElementData(const UniqueElementData& other)
2926 : ElementData(other, true)
2927 , m_presentationAttributeStyle(other.m_presentationAttributeStyle)
2928 , m_attributeVector(other.m_attributeVector)
2930 m_inlineStyle = other.m_inlineStyle ? other.m_inlineStyle->copy() : 0;
2933 UniqueElementData::UniqueElementData(const ShareableElementData& other)
2934 : ElementData(other, true)
2936 // An ShareableElementData should never have a mutable inline StylePropertySet attached.
2937 ASSERT(!other.m_inlineStyle || !other.m_inlineStyle->isMutable());
2938 m_inlineStyle = other.m_inlineStyle;
2940 m_attributeVector.reserveCapacity(other.length());
2941 for (unsigned i = 0; i < other.length(); ++i)
2942 m_attributeVector.uncheckedAppend(other.m_attributeArray[i]);
2945 PassRefPtr<UniqueElementData> ElementData::makeUniqueCopy() const
2948 return adoptRef(new UniqueElementData(static_cast<const UniqueElementData&>(*this)));
2949 return adoptRef(new UniqueElementData(static_cast<const ShareableElementData&>(*this)));
2952 PassRefPtr<ShareableElementData> UniqueElementData::makeShareableCopy() const
2954 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(m_attributeVector.size()));
2955 return adoptRef(new (slot) ShareableElementData(*this));
2958 void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value)
2960 m_attributeVector.append(Attribute(attributeName, value));
2963 void UniqueElementData::removeAttribute(size_t index)
2965 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
2966 m_attributeVector.remove(index);
2969 bool ElementData::isEquivalent(const ElementData* other) const
2974 unsigned len = length();
2975 if (len != other->length())
2978 for (unsigned i = 0; i < len; i++) {
2979 const Attribute* attribute = attributeItem(i);
2980 const Attribute* otherAttr = other->getAttributeItem(attribute->name());
2981 if (!otherAttr || attribute->value() != otherAttr->value())
2988 void ElementData::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
2990 size_t actualSize = m_isUnique ? sizeof(ElementData) : sizeForShareableElementDataWithAttributeCount(m_arraySize);
2991 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM, actualSize);
2992 info.addMember(m_inlineStyle, "inlineStyle");
2993 info.addMember(m_classNames, "classNames");
2994 info.addMember(m_idForStyleResolution, "idForStyleResolution");
2996 const UniqueElementData* uniqueThis = static_cast<const UniqueElementData*>(this);
2997 info.addMember(uniqueThis->m_presentationAttributeStyle, "presentationAttributeStyle");
2998 info.addMember(uniqueThis->m_attributeVector, "attributeVector");
3000 for (unsigned i = 0, len = length(); i < len; i++)
3001 info.addMember(*attributeItem(i), "*attributeItem");
3004 size_t ElementData::getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const
3006 // Continue to checking case-insensitively and/or full namespaced names if necessary:
3007 for (unsigned i = 0; i < length(); ++i) {
3008 const Attribute* attribute = attributeItem(i);
3009 if (!attribute->name().hasPrefix()) {
3010 if (shouldIgnoreAttributeCase && equalIgnoringCase(name, attribute->localName()))
3013 // FIXME: Would be faster to do this comparison without calling toString, which
3014 // generates a temporary string by concatenation. But this branch is only reached
3015 // if the attribute name has a prefix, which is rare in HTML.
3016 if (equalPossiblyIgnoringCase(name, attribute->name().toString(), shouldIgnoreAttributeCase))
3023 Attribute* UniqueElementData::getAttributeItem(const QualifiedName& name)
3025 for (unsigned i = 0; i < length(); ++i) {
3026 if (m_attributeVector.at(i).name().matches(name))
3027 return &m_attributeVector.at(i);
3032 Attribute* UniqueElementData::attributeItem(unsigned index)
3034 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
3035 return &m_attributeVector.at(index);
3038 } // namespace WebCore