blob: e8645e2e3669d4ce0a155a7819e52fae10cb16da [file] [log] [blame]
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001/*
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)
9 *
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.
14 *
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.
19 *
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.
24 */
25
26#include "config.h"
27#include "core/dom/Element.h"
28
29#include "HTMLNames.h"
30#include "XMLNSNames.h"
31#include "XMLNames.h"
32#include "core/accessibility/AXObjectCache.h"
33#include "core/css/CSSParser.h"
34#include "core/css/CSSSelectorList.h"
35#include "core/css/StylePropertySet.h"
Torne (Richard Coles)81a51572013-05-13 16:52:28 +010036#include "core/css/resolver/StyleResolver.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010037#include "core/dom/Attr.h"
38#include "core/dom/ClientRect.h"
39#include "core/dom/ClientRectList.h"
40#include "core/dom/CustomElementRegistry.h"
41#include "core/dom/DatasetDOMStringMap.h"
42#include "core/dom/Document.h"
43#include "core/dom/DocumentFragment.h"
44#include "core/dom/DocumentSharedObjectPool.h"
45#include "core/dom/ElementRareData.h"
46#include "core/dom/ExceptionCode.h"
47#include "core/dom/MutationObserverInterestGroup.h"
48#include "core/dom/MutationRecord.h"
49#include "core/dom/NamedNodeMap.h"
50#include "core/dom/NodeList.h"
51#include "core/dom/NodeRenderStyle.h"
52#include "core/dom/NodeRenderingContext.h"
53#include "core/dom/NodeTraversal.h"
54#include "core/dom/PseudoElement.h"
55#include "core/dom/SelectorQuery.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010056#include "core/dom/Text.h"
57#include "core/dom/WebCoreMemoryInstrumentation.h"
Torne (Richard Coles)e5249552013-05-15 11:35:13 +010058#include "core/dom/shadow/InsertionPoint.h"
59#include "core/dom/shadow/ShadowRoot.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010060#include "core/editing/FrameSelection.h"
61#include "core/editing/TextIterator.h"
62#include "core/editing/htmlediting.h"
63#include "core/html/ClassList.h"
64#include "core/html/DOMTokenList.h"
65#include "core/html/HTMLCollection.h"
66#include "core/html/HTMLDocument.h"
67#include "core/html/HTMLElement.h"
68#include "core/html/HTMLFormControlsCollection.h"
69#include "core/html/HTMLFrameOwnerElement.h"
70#include "core/html/HTMLLabelElement.h"
71#include "core/html/HTMLOptionsCollection.h"
72#include "core/html/HTMLTableRowsCollection.h"
73#include "core/html/VoidCallback.h"
74#include "core/html/parser/HTMLParserIdioms.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010075#include "core/inspector/InspectorInstrumentation.h"
76#include "core/page/FocusController.h"
77#include "core/page/Frame.h"
78#include "core/page/FrameView.h"
79#include "core/page/Page.h"
80#include "core/page/PointerLockController.h"
81#include "core/page/Settings.h"
82#include "core/rendering/FlowThreadController.h"
83#include "core/rendering/RenderRegion.h"
84#include "core/rendering/RenderView.h"
85#include "core/rendering/RenderWidget.h"
86#include <wtf/BitVector.h>
87#include <wtf/MemoryInstrumentationVector.h>
88#include <wtf/text/CString.h>
89
90#if ENABLE(SVG)
91#include "SVGNames.h"
92#include "core/svg/SVGDocumentExtensions.h"
93#include "core/svg/SVGElement.h"
94#endif
95
96namespace WebCore {
97
98using namespace HTMLNames;
99using namespace XMLNames;
100
101static inline bool shouldIgnoreAttributeCase(const Element* e)
102{
103 return e && e->document()->isHTMLDocument() && e->isHTMLElement();
104}
105
106class StyleResolverParentPusher {
107public:
108 StyleResolverParentPusher(Element* parent)
109 : m_parent(parent)
110 , m_pushedStyleResolver(0)
111 {
112 }
113 void push()
114 {
115 if (m_pushedStyleResolver)
116 return;
117 m_pushedStyleResolver = m_parent->document()->styleResolver();
118 m_pushedStyleResolver->pushParentElement(m_parent);
119 }
120 ~StyleResolverParentPusher()
121 {
122
123 if (!m_pushedStyleResolver)
124 return;
125
126 // This tells us that our pushed style selector is in a bad state,
127 // so we should just bail out in that scenario.
128 ASSERT(m_pushedStyleResolver == m_parent->document()->styleResolver());
129 if (m_pushedStyleResolver != m_parent->document()->styleResolver())
130 return;
131
132 m_pushedStyleResolver->popParentElement(m_parent);
133 }
134
135private:
136 Element* m_parent;
137 StyleResolver* m_pushedStyleResolver;
138};
139
140typedef Vector<RefPtr<Attr> > AttrNodeList;
141typedef HashMap<Element*, OwnPtr<AttrNodeList> > AttrNodeListMap;
142
143static AttrNodeListMap& attrNodeListMap()
144{
145 DEFINE_STATIC_LOCAL(AttrNodeListMap, map, ());
146 return map;
147}
148
149static AttrNodeList* attrNodeListForElement(Element* element)
150{
151 if (!element->hasSyntheticAttrChildNodes())
152 return 0;
153 ASSERT(attrNodeListMap().contains(element));
154 return attrNodeListMap().get(element);
155}
156
157static AttrNodeList* ensureAttrNodeListForElement(Element* element)
158{
159 if (element->hasSyntheticAttrChildNodes()) {
160 ASSERT(attrNodeListMap().contains(element));
161 return attrNodeListMap().get(element);
162 }
163 ASSERT(!attrNodeListMap().contains(element));
164 element->setHasSyntheticAttrChildNodes(true);
165 AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList));
166 return result.iterator->value.get();
167}
168
169static void removeAttrNodeListForElement(Element* element)
170{
171 ASSERT(element->hasSyntheticAttrChildNodes());
172 ASSERT(attrNodeListMap().contains(element));
173 attrNodeListMap().remove(element);
174 element->setHasSyntheticAttrChildNodes(false);
175}
176
177static Attr* findAttrNodeInList(AttrNodeList* attrNodeList, const QualifiedName& name)
178{
179 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
180 if (attrNodeList->at(i)->qualifiedName() == name)
181 return attrNodeList->at(i).get();
182 }
183 return 0;
184}
185
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100186PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document)
187{
188 return adoptRef(new Element(tagName, document, CreateElement));
189}
190
191Element::~Element()
192{
193#ifndef NDEBUG
194 if (document() && document()->renderer()) {
195 // When the document is not destroyed, an element that was part of a named flow
196 // content nodes should have been removed from the content nodes collection
197 // and the inNamedFlow flag reset.
198 ASSERT(!inNamedFlow());
199 }
200#endif
201
202 if (hasRareData()) {
203 ElementRareData* data = elementRareData();
204 data->setPseudoElement(BEFORE, 0);
205 data->setPseudoElement(AFTER, 0);
206 data->clearShadow();
207 }
208
209 if (isCustomElement() && document() && document()->registry()) {
210 document()->registry()->customElementWasDestroyed(this);
211 }
212
213 if (hasSyntheticAttrChildNodes())
214 detachAllAttrNodesFromElement();
215
216#if ENABLE(SVG)
217 if (hasPendingResources()) {
218 document()->accessSVGExtensions()->removeElementFromPendingResources(this);
219 ASSERT(!hasPendingResources());
220 }
221#endif
222}
223
224inline ElementRareData* Element::elementRareData() const
225{
226 ASSERT(hasRareData());
227 return static_cast<ElementRareData*>(rareData());
228}
229
230inline ElementRareData* Element::ensureElementRareData()
231{
232 return static_cast<ElementRareData*>(ensureRareData());
233}
234
235void Element::clearTabIndexExplicitlyIfNeeded()
236{
237 if (hasRareData())
238 elementRareData()->clearTabIndexExplicitly();
239}
240
241void Element::setTabIndexExplicitly(short tabIndex)
242{
243 ensureElementRareData()->setTabIndexExplicitly(tabIndex);
244}
245
246bool Element::supportsFocus() const
247{
248 return hasRareData() && elementRareData()->tabIndexSetExplicitly();
249}
250
251short Element::tabIndex() const
252{
253 return hasRareData() ? elementRareData()->tabIndex() : 0;
254}
255
256DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, blur);
257DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, error);
258DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, focus);
259DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, load);
260
261PassRefPtr<Node> Element::cloneNode(bool deep)
262{
263 return deep ? cloneElementWithChildren() : cloneElementWithoutChildren();
264}
265
266PassRefPtr<Element> Element::cloneElementWithChildren()
267{
268 RefPtr<Element> clone = cloneElementWithoutChildren();
269 cloneChildNodes(clone.get());
270 return clone.release();
271}
272
273PassRefPtr<Element> Element::cloneElementWithoutChildren()
274{
275 RefPtr<Element> clone = cloneElementWithoutAttributesAndChildren();
276 // This will catch HTML elements in the wrong namespace that are not correctly copied.
277 // This is a sanity check as HTML overloads some of the DOM methods.
278 ASSERT(isHTMLElement() == clone->isHTMLElement());
279
280 clone->cloneDataFromElement(*this);
281 return clone.release();
282}
283
284PassRefPtr<Element> Element::cloneElementWithoutAttributesAndChildren()
285{
286 return document()->createElement(tagQName(), false);
287}
288
289PassRefPtr<Attr> Element::detachAttribute(size_t index)
290{
291 ASSERT(elementData());
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100292 const Attribute* attribute = elementData()->attributeItem(index);
293 RefPtr<Attr> attrNode = attrIfExists(attribute->name());
294 if (attrNode)
295 detachAttrNodeAtIndex(attrNode.get(), index);
296 else {
297 attrNode = Attr::create(document(), attribute->name(), attribute->value());
298 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
299 }
300 return attrNode.release();
301}
302
303void Element::detachAttrNodeAtIndex(Attr* attr, size_t index)
304{
305 ASSERT(attr);
306 ASSERT(elementData());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100307
308 const Attribute* attribute = elementData()->attributeItem(index);
309 ASSERT(attribute);
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100310 ASSERT(attribute->name() == attr->qualifiedName());
311 detachAttrNodeFromElementWithValue(attr, attribute->value());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100312 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100313}
314
315void Element::removeAttribute(const QualifiedName& name)
316{
317 if (!elementData())
318 return;
319
320 size_t index = elementData()->getAttributeItemIndex(name);
321 if (index == notFound)
322 return;
323
324 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
325}
326
327void Element::setBooleanAttribute(const QualifiedName& name, bool value)
328{
329 if (value)
330 setAttribute(name, emptyAtom);
331 else
332 removeAttribute(name);
333}
334
335NamedNodeMap* Element::attributes() const
336{
337 ElementRareData* rareData = const_cast<Element*>(this)->ensureElementRareData();
338 if (NamedNodeMap* attributeMap = rareData->attributeMap())
339 return attributeMap;
340
341 rareData->setAttributeMap(NamedNodeMap::create(const_cast<Element*>(this)));
342 return rareData->attributeMap();
343}
344
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100345void Element::addActiveAnimation(Animation* animation)
346{
347 ElementRareData* rareData = ensureElementRareData();
348 if (!rareData->activeAnimations())
349 rareData->setActiveAnimations(adoptPtr(new Vector<Animation*>));
350 rareData->activeAnimations()->append(animation);
351}
352
353void Element::removeActiveAnimation(Animation* animation)
354{
355 ElementRareData* rareData = elementRareData();
356 ASSERT(rareData);
357 size_t position = rareData->activeAnimations()->find(animation);
358 ASSERT(position != notFound);
359 rareData->activeAnimations()->remove(position);
360}
361
362bool Element::hasActiveAnimations() const
363{
364 return hasRareData() && elementRareData()->activeAnimations()
365 && elementRareData()->activeAnimations()->size();
366}
367
368Vector<Animation*>* Element::activeAnimations() const
369{
370 if (!elementRareData())
371 return 0;
372 return elementRareData()->activeAnimations();
373}
374
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100375Node::NodeType Element::nodeType() const
376{
377 return ELEMENT_NODE;
378}
379
380bool Element::hasAttribute(const QualifiedName& name) const
381{
382 return hasAttributeNS(name.namespaceURI(), name.localName());
383}
384
385void Element::synchronizeAllAttributes() const
386{
387 if (!elementData())
388 return;
389 if (elementData()->m_styleAttributeIsDirty) {
390 ASSERT(isStyledElement());
391 static_cast<const StyledElement*>(this)->synchronizeStyleAttributeInternal();
392 }
393#if ENABLE(SVG)
394 if (elementData()->m_animatedSVGAttributesAreDirty) {
395 ASSERT(isSVGElement());
396 toSVGElement(this)->synchronizeAnimatedSVGAttribute(anyQName());
397 }
398#endif
399}
400
401inline void Element::synchronizeAttribute(const QualifiedName& name) const
402{
403 if (!elementData())
404 return;
405 if (UNLIKELY(name == styleAttr && elementData()->m_styleAttributeIsDirty)) {
406 ASSERT(isStyledElement());
407 static_cast<const StyledElement*>(this)->synchronizeStyleAttributeInternal();
408 return;
409 }
410#if ENABLE(SVG)
411 if (UNLIKELY(elementData()->m_animatedSVGAttributesAreDirty)) {
412 ASSERT(isSVGElement());
413 toSVGElement(this)->synchronizeAnimatedSVGAttribute(name);
414 }
415#endif
416}
417
418inline void Element::synchronizeAttribute(const AtomicString& localName) const
419{
420 // This version of synchronizeAttribute() is streamlined for the case where you don't have a full QualifiedName,
421 // e.g when called from DOM API.
422 if (!elementData())
423 return;
424 if (elementData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(localName, styleAttr.localName(), shouldIgnoreAttributeCase(this))) {
425 ASSERT(isStyledElement());
426 static_cast<const StyledElement*>(this)->synchronizeStyleAttributeInternal();
427 return;
428 }
429#if ENABLE(SVG)
430 if (elementData()->m_animatedSVGAttributesAreDirty) {
431 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
432 ASSERT(isSVGElement());
433 static_cast<const SVGElement*>(this)->synchronizeAnimatedSVGAttribute(QualifiedName(nullAtom, localName, nullAtom));
434 }
435#endif
436}
437
438const AtomicString& Element::getAttribute(const QualifiedName& name) const
439{
440 if (!elementData())
441 return nullAtom;
442 synchronizeAttribute(name);
443 if (const Attribute* attribute = getAttributeItem(name))
444 return attribute->value();
445 return nullAtom;
446}
447
448void Element::scrollIntoView(bool alignToTop)
449{
450 document()->updateLayoutIgnorePendingStylesheets();
451
452 if (!renderer())
453 return;
454
455 LayoutRect bounds = boundingBox();
456 // Align to the top / bottom and to the closest edge.
457 if (alignToTop)
458 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
459 else
460 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
461}
462
463void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
464{
465 document()->updateLayoutIgnorePendingStylesheets();
466
467 if (!renderer())
468 return;
469
470 LayoutRect bounds = boundingBox();
471 if (centerIfNeeded)
472 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
473 else
474 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
475}
476
477void Element::scrollByUnits(int units, ScrollGranularity granularity)
478{
479 document()->updateLayoutIgnorePendingStylesheets();
480
481 if (!renderer())
482 return;
483
484 if (!renderer()->hasOverflowClip())
485 return;
486
487 ScrollDirection direction = ScrollDown;
488 if (units < 0) {
489 direction = ScrollUp;
490 units = -units;
491 }
492 Node* stopNode = this;
493 toRenderBox(renderer())->scroll(direction, granularity, units, &stopNode);
494}
495
496void Element::scrollByLines(int lines)
497{
498 scrollByUnits(lines, ScrollByLine);
499}
500
501void Element::scrollByPages(int pages)
502{
503 scrollByUnits(pages, ScrollByPage);
504}
505
506static float localZoomForRenderer(RenderObject* renderer)
507{
508 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
509 // other out, but the alternative is that we'd have to crawl up the whole render tree every
510 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
511 float zoomFactor = 1;
512 if (renderer->style()->effectiveZoom() != 1) {
513 // Need to find the nearest enclosing RenderObject that set up
514 // a differing zoom, and then we divide our result by it to eliminate the zoom.
515 RenderObject* prev = renderer;
516 for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) {
517 if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) {
518 zoomFactor = prev->style()->zoom();
519 break;
520 }
521 prev = curr;
522 }
523 if (prev->isRenderView())
524 zoomFactor = prev->style()->zoom();
525 }
526 return zoomFactor;
527}
528
529static int adjustForLocalZoom(LayoutUnit value, RenderObject* renderer)
530{
531 float zoomFactor = localZoomForRenderer(renderer);
532 if (zoomFactor == 1)
533 return value;
534 return lroundf(value / zoomFactor);
535}
536
537int Element::offsetLeft()
538{
539 document()->updateLayoutIgnorePendingStylesheets();
540 if (RenderBoxModelObject* renderer = renderBoxModelObject())
541 return adjustForLocalZoom(renderer->pixelSnappedOffsetLeft(), renderer);
542 return 0;
543}
544
545int Element::offsetTop()
546{
547 document()->updateLayoutIgnorePendingStylesheets();
548 if (RenderBoxModelObject* renderer = renderBoxModelObject())
549 return adjustForLocalZoom(renderer->pixelSnappedOffsetTop(), renderer);
550 return 0;
551}
552
553int Element::offsetWidth()
554{
555 document()->updateLayoutIgnorePendingStylesheets();
556 if (RenderBoxModelObject* renderer = renderBoxModelObject())
557 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetWidth(), renderer).round();
558 return 0;
559}
560
561int Element::offsetHeight()
562{
563 document()->updateLayoutIgnorePendingStylesheets();
564 if (RenderBoxModelObject* renderer = renderBoxModelObject())
565 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetHeight(), renderer).round();
566 return 0;
567}
568
569Element* Element::bindingsOffsetParent()
570{
571 Element* element = offsetParent();
572 if (!element || !element->isInShadowTree())
573 return element;
574 return element->containingShadowRoot()->type() == ShadowRoot::UserAgentShadowRoot ? 0 : element;
575}
576
577Element* Element::offsetParent()
578{
579 document()->updateLayoutIgnorePendingStylesheets();
580 if (RenderObject* renderer = this->renderer())
581 return renderer->offsetParent();
582 return 0;
583}
584
585int Element::clientLeft()
586{
587 document()->updateLayoutIgnorePendingStylesheets();
588
589 if (RenderBox* renderer = renderBox())
590 return adjustForAbsoluteZoom(roundToInt(renderer->clientLeft()), renderer);
591 return 0;
592}
593
594int Element::clientTop()
595{
596 document()->updateLayoutIgnorePendingStylesheets();
597
598 if (RenderBox* renderer = renderBox())
599 return adjustForAbsoluteZoom(roundToInt(renderer->clientTop()), renderer);
600 return 0;
601}
602
603int Element::clientWidth()
604{
605 document()->updateLayoutIgnorePendingStylesheets();
606
607 // When in strict mode, clientWidth for the document element should return the width of the containing frame.
608 // When in quirks mode, clientWidth for the body element should return the width of the containing frame.
609 bool inQuirksMode = document()->inQuirksMode();
610 if ((!inQuirksMode && document()->documentElement() == this) ||
611 (inQuirksMode && isHTMLElement() && document()->body() == this)) {
612 if (FrameView* view = document()->view()) {
613 if (RenderView* renderView = document()->renderView())
614 return adjustForAbsoluteZoom(view->layoutWidth(), renderView);
615 }
616 }
617
618 if (RenderBox* renderer = renderBox())
619 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientWidth(), renderer).round();
620 return 0;
621}
622
623int Element::clientHeight()
624{
625 document()->updateLayoutIgnorePendingStylesheets();
626
627 // When in strict mode, clientHeight for the document element should return the height of the containing frame.
628 // When in quirks mode, clientHeight for the body element should return the height of the containing frame.
629 bool inQuirksMode = document()->inQuirksMode();
630
631 if ((!inQuirksMode && document()->documentElement() == this) ||
632 (inQuirksMode && isHTMLElement() && document()->body() == this)) {
633 if (FrameView* view = document()->view()) {
634 if (RenderView* renderView = document()->renderView())
635 return adjustForAbsoluteZoom(view->layoutHeight(), renderView);
636 }
637 }
638
639 if (RenderBox* renderer = renderBox())
640 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientHeight(), renderer).round();
641 return 0;
642}
643
644int Element::scrollLeft()
645{
646 document()->updateLayoutIgnorePendingStylesheets();
647 if (RenderBox* rend = renderBox())
648 return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
649 return 0;
650}
651
652int Element::scrollTop()
653{
654 document()->updateLayoutIgnorePendingStylesheets();
655 if (RenderBox* rend = renderBox())
656 return adjustForAbsoluteZoom(rend->scrollTop(), rend);
657 return 0;
658}
659
660void Element::setScrollLeft(int newLeft)
661{
662 document()->updateLayoutIgnorePendingStylesheets();
663 if (RenderBox* rend = renderBox())
664 rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
665}
666
667void Element::setScrollTop(int newTop)
668{
669 document()->updateLayoutIgnorePendingStylesheets();
670 if (RenderBox* rend = renderBox())
671 rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
672}
673
674int Element::scrollWidth()
675{
676 document()->updateLayoutIgnorePendingStylesheets();
677 if (RenderBox* rend = renderBox())
678 return adjustForAbsoluteZoom(rend->scrollWidth(), rend);
679 return 0;
680}
681
682int Element::scrollHeight()
683{
684 document()->updateLayoutIgnorePendingStylesheets();
685 if (RenderBox* rend = renderBox())
686 return adjustForAbsoluteZoom(rend->scrollHeight(), rend);
687 return 0;
688}
689
690IntRect Element::boundsInRootViewSpace()
691{
692 document()->updateLayoutIgnorePendingStylesheets();
693
694 FrameView* view = document()->view();
695 if (!view)
696 return IntRect();
697
698 Vector<FloatQuad> quads;
699#if ENABLE(SVG)
700 if (isSVGElement() && renderer()) {
701 // Get the bounding rectangle from the SVG model.
702 SVGElement* svgElement = toSVGElement(this);
703 FloatRect localRect;
704 if (svgElement->getBoundingBox(localRect))
705 quads.append(renderer()->localToAbsoluteQuad(localRect));
706 } else
707#endif
708 {
709 // Get the bounding rectangle from the box model.
710 if (renderBoxModelObject())
711 renderBoxModelObject()->absoluteQuads(quads);
712 }
713
714 if (quads.isEmpty())
715 return IntRect();
716
717 IntRect result = quads[0].enclosingBoundingBox();
718 for (size_t i = 1; i < quads.size(); ++i)
719 result.unite(quads[i].enclosingBoundingBox());
720
721 result = view->contentsToRootView(result);
722 return result;
723}
724
725PassRefPtr<ClientRectList> Element::getClientRects()
726{
727 document()->updateLayoutIgnorePendingStylesheets();
728
729 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject();
730 if (!renderBoxModelObject)
731 return ClientRectList::create();
732
733 // FIXME: Handle SVG elements.
734 // FIXME: Handle table/inline-table with a caption.
735
736 Vector<FloatQuad> quads;
737 renderBoxModelObject->absoluteQuads(quads);
738 document()->adjustFloatQuadsForScrollAndAbsoluteZoom(quads, renderBoxModelObject);
739 return ClientRectList::create(quads);
740}
741
742PassRefPtr<ClientRect> Element::getBoundingClientRect()
743{
744 document()->updateLayoutIgnorePendingStylesheets();
745
746 Vector<FloatQuad> quads;
747#if ENABLE(SVG)
748 if (isSVGElement() && renderer() && !renderer()->isSVGRoot()) {
749 // Get the bounding rectangle from the SVG model.
750 SVGElement* svgElement = toSVGElement(this);
751 FloatRect localRect;
752 if (svgElement->getBoundingBox(localRect))
753 quads.append(renderer()->localToAbsoluteQuad(localRect));
754 } else
755#endif
756 {
757 // Get the bounding rectangle from the box model.
758 if (renderBoxModelObject())
759 renderBoxModelObject()->absoluteQuads(quads);
760 }
761
762 if (quads.isEmpty())
763 return ClientRect::create();
764
765 FloatRect result = quads[0].boundingBox();
766 for (size_t i = 1; i < quads.size(); ++i)
767 result.unite(quads[i].boundingBox());
768
769 document()->adjustFloatRectForScrollAndAbsoluteZoom(result, renderer());
770 return ClientRect::create(result);
771}
772
773IntRect Element::screenRect() const
774{
775 if (!renderer())
776 return IntRect();
777 // FIXME: this should probably respect transforms
778 return document()->view()->contentsToScreen(renderer()->absoluteBoundingBoxRectIgnoringTransforms());
779}
780
781const AtomicString& Element::getAttribute(const AtomicString& localName) const
782{
783 if (!elementData())
784 return nullAtom;
785 synchronizeAttribute(localName);
786 if (const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase(this)))
787 return attribute->value();
788 return nullAtom;
789}
790
791const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
792{
793 return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
794}
795
796void Element::setAttribute(const AtomicString& localName, const AtomicString& value, ExceptionCode& ec)
797{
798 if (!Document::isValidName(localName)) {
799 ec = INVALID_CHARACTER_ERR;
800 return;
801 }
802
803 synchronizeAttribute(localName);
804 const AtomicString& caseAdjustedLocalName = shouldIgnoreAttributeCase(this) ? localName.lower() : localName;
805
806 size_t index = elementData() ? elementData()->getAttributeItemIndex(caseAdjustedLocalName, false) : notFound;
807 const QualifiedName& qName = index != notFound ? attributeItem(index)->name() : QualifiedName(nullAtom, caseAdjustedLocalName, nullAtom);
808 setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute);
809}
810
811void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
812{
813 synchronizeAttribute(name);
814 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : notFound;
815 setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute);
816}
817
818void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value)
819{
820 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : notFound;
821 setAttributeInternal(index, name, value, InSynchronizationOfLazyAttribute);
822}
823
824inline void Element::setAttributeInternal(size_t index, const QualifiedName& name, const AtomicString& newValue, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
825{
826 if (newValue.isNull()) {
827 if (index != notFound)
828 removeAttributeInternal(index, inSynchronizationOfLazyAttribute);
829 return;
830 }
831
832 if (index == notFound) {
833 addAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute);
834 return;
835 }
836
837 if (!inSynchronizationOfLazyAttribute)
838 willModifyAttribute(name, attributeItem(index)->value(), newValue);
839
840 if (newValue != attributeItem(index)->value()) {
841 // If there is an Attr node hooked to this attribute, the Attr::setValue() call below
842 // will write into the ElementData.
843 // FIXME: Refactor this so it makes some sense.
844 if (RefPtr<Attr> attrNode = inSynchronizationOfLazyAttribute ? 0 : attrIfExists(name))
845 attrNode->setValue(newValue);
846 else
847 ensureUniqueElementData()->attributeItem(index)->setValue(newValue);
848 }
849
850 if (!inSynchronizationOfLazyAttribute)
851 didModifyAttribute(name, newValue);
852}
853
854static inline AtomicString makeIdForStyleResolution(const AtomicString& value, bool inQuirksMode)
855{
856 if (inQuirksMode)
857 return value.lower();
858 return value;
859}
860
861static bool checkNeedsStyleInvalidationForIdChange(const AtomicString& oldId, const AtomicString& newId, StyleResolver* styleResolver)
862{
863 ASSERT(newId != oldId);
864 if (!oldId.isEmpty() && styleResolver->hasSelectorForId(oldId))
865 return true;
866 if (!newId.isEmpty() && styleResolver->hasSelectorForId(newId))
867 return true;
868 return false;
869}
870
871void Element::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason)
872{
873 if (ElementShadow* parentElementShadow = shadowOfParentForDistribution(this)) {
874 if (shouldInvalidateDistributionWhenAttributeChanged(parentElementShadow, name, newValue))
875 parentElementShadow->invalidateDistribution();
876 }
877
878 parseAttribute(name, newValue);
879
880 document()->incDOMTreeVersion();
881
882 StyleResolver* styleResolver = document()->styleResolverIfExists();
883 bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < FullStyleChange;
884 bool shouldInvalidateStyle = false;
885
886 if (isIdAttributeName(name)) {
887 AtomicString oldId = elementData()->idForStyleResolution();
888 AtomicString newId = makeIdForStyleResolution(newValue, document()->inQuirksMode());
889 if (newId != oldId) {
890 elementData()->setIdForStyleResolution(newId);
891 shouldInvalidateStyle = testShouldInvalidateStyle && checkNeedsStyleInvalidationForIdChange(oldId, newId, styleResolver);
892 }
893 } else if (name == classAttr)
894 classAttributeChanged(newValue);
895 else if (name == HTMLNames::nameAttr)
896 setHasName(!newValue.isNull());
897 else if (name == HTMLNames::pseudoAttr)
898 shouldInvalidateStyle |= testShouldInvalidateStyle && isInShadowTree();
899
900 invalidateNodeListCachesInAncestors(&name, this);
901
902 // If there is currently no StyleResolver, we can't be sure that this attribute change won't affect style.
903 shouldInvalidateStyle |= !styleResolver;
904
905 if (shouldInvalidateStyle)
906 setNeedsStyleRecalc();
907
908 if (AXObjectCache* cache = document()->existingAXObjectCache())
909 cache->handleAttributeChanged(name, this);
910}
911
912inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
913{
914 if (RuntimeEnabledFeatures::customDOMElementsEnabled() && name == isAttr) {
915 document()->ensureCustomElementRegistry()->didGiveTypeExtension(this, newValue);
916 }
917 attributeChanged(name, newValue, reason);
918}
919
920template <typename CharacterType>
921static inline bool classStringHasClassName(const CharacterType* characters, unsigned length)
922{
923 ASSERT(length > 0);
924
925 unsigned i = 0;
926 do {
927 if (isNotHTMLSpace(characters[i]))
928 break;
929 ++i;
930 } while (i < length);
931
932 return i < length;
933}
934
935static inline bool classStringHasClassName(const AtomicString& newClassString)
936{
937 unsigned length = newClassString.length();
938
939 if (!length)
940 return false;
941
942 if (newClassString.is8Bit())
943 return classStringHasClassName(newClassString.characters8(), length);
944 return classStringHasClassName(newClassString.characters16(), length);
945}
946
947template<typename Checker>
948static bool checkSelectorForClassChange(const SpaceSplitString& changedClasses, const Checker& checker)
949{
950 unsigned changedSize = changedClasses.size();
951 for (unsigned i = 0; i < changedSize; ++i) {
952 if (checker.hasSelectorForClass(changedClasses[i]))
953 return true;
954 }
955 return false;
956}
957
958template<typename Checker>
959static bool checkSelectorForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, const Checker& checker)
960{
961 unsigned oldSize = oldClasses.size();
962 if (!oldSize)
963 return checkSelectorForClassChange(newClasses, checker);
964 BitVector remainingClassBits;
965 remainingClassBits.ensureSize(oldSize);
966 // Class vectors tend to be very short. This is faster than using a hash table.
967 unsigned newSize = newClasses.size();
968 for (unsigned i = 0; i < newSize; ++i) {
969 for (unsigned j = 0; j < oldSize; ++j) {
970 if (newClasses[i] == oldClasses[j]) {
971 remainingClassBits.quickSet(j);
972 continue;
973 }
974 }
975 if (checker.hasSelectorForClass(newClasses[i]))
976 return true;
977 }
978 for (unsigned i = 0; i < oldSize; ++i) {
979 // If the bit is not set the the corresponding class has been removed.
980 if (remainingClassBits.quickGet(i))
981 continue;
982 if (checker.hasSelectorForClass(oldClasses[i]))
983 return true;
984 }
985 return false;
986}
987
988void Element::classAttributeChanged(const AtomicString& newClassString)
989{
990 StyleResolver* styleResolver = document()->styleResolverIfExists();
991 bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < FullStyleChange;
992 bool shouldInvalidateStyle = false;
993
994 if (classStringHasClassName(newClassString)) {
995 const bool shouldFoldCase = document()->inQuirksMode();
996 const SpaceSplitString oldClasses = elementData()->classNames();
997 elementData()->setClass(newClassString, shouldFoldCase);
998 const SpaceSplitString& newClasses = elementData()->classNames();
999 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, newClasses, *styleResolver);
1000 } else {
1001 const SpaceSplitString& oldClasses = elementData()->classNames();
1002 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, *styleResolver);
1003 elementData()->clearClass();
1004 }
1005
1006 if (hasRareData())
1007 elementRareData()->clearClassListValueForQuirksMode();
1008
1009 if (shouldInvalidateStyle)
1010 setNeedsStyleRecalc();
1011}
1012
1013bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
1014{
1015 ASSERT(elementShadow);
1016 const SelectRuleFeatureSet& featureSet = elementShadow->distributor().ensureSelectFeatureSet(elementShadow);
1017
1018 if (isIdAttributeName(name)) {
1019 AtomicString oldId = elementData()->idForStyleResolution();
1020 AtomicString newId = makeIdForStyleResolution(newValue, document()->inQuirksMode());
1021 if (newId != oldId) {
1022 if (!oldId.isEmpty() && featureSet.hasSelectorForId(oldId))
1023 return true;
1024 if (!newId.isEmpty() && featureSet.hasSelectorForId(newId))
1025 return true;
1026 }
1027 }
1028
1029 if (name == HTMLNames::classAttr) {
1030 const AtomicString& newClassString = newValue;
1031 if (classStringHasClassName(newClassString)) {
1032 const bool shouldFoldCase = document()->inQuirksMode();
1033 const SpaceSplitString& oldClasses = elementData()->classNames();
1034 const SpaceSplitString newClasses(newClassString, shouldFoldCase);
1035 if (checkSelectorForClassChange(oldClasses, newClasses, featureSet))
1036 return true;
1037 } else {
1038 const SpaceSplitString& oldClasses = elementData()->classNames();
1039 if (checkSelectorForClassChange(oldClasses, featureSet))
1040 return true;
1041 }
1042 }
1043
1044 return featureSet.hasSelectorForAttribute(name.localName());
1045}
1046
1047// Returns true is the given attribute is an event handler.
1048// We consider an event handler any attribute that begins with "on".
1049// It is a simple solution that has the advantage of not requiring any
1050// code or configuration change if a new event handler is defined.
1051
1052static inline bool isEventHandlerAttribute(const Attribute& attribute)
1053{
1054 return attribute.name().namespaceURI().isNull() && attribute.name().localName().startsWith("on");
1055}
1056
1057bool Element::isJavaScriptURLAttribute(const Attribute& attribute) const
1058{
1059 return isURLAttribute(attribute) && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(attribute.value()));
1060}
1061
1062void Element::stripScriptingAttributes(Vector<Attribute>& attributeVector) const
1063{
1064 size_t destination = 0;
1065 for (size_t source = 0; source < attributeVector.size(); ++source) {
1066 if (isEventHandlerAttribute(attributeVector[source])
1067 || isJavaScriptURLAttribute(attributeVector[source])
1068 || isHTMLContentAttribute(attributeVector[source]))
1069 continue;
1070
1071 if (source != destination)
1072 attributeVector[destination] = attributeVector[source];
1073
1074 ++destination;
1075 }
1076 attributeVector.shrink(destination);
1077}
1078
1079void Element::parserSetAttributes(const Vector<Attribute>& attributeVector)
1080{
1081 ASSERT(!inDocument());
1082 ASSERT(!parentNode());
1083 ASSERT(!m_elementData);
1084
1085 if (attributeVector.isEmpty())
1086 return;
1087
1088 if (document() && document()->sharedObjectPool())
1089 m_elementData = document()->sharedObjectPool()->cachedShareableElementDataWithAttributes(attributeVector);
1090 else
1091 m_elementData = ShareableElementData::createWithAttributes(attributeVector);
1092
1093 // Use attributeVector instead of m_elementData because attributeChanged might modify m_elementData.
1094 for (unsigned i = 0; i < attributeVector.size(); ++i)
1095 attributeChangedFromParserOrByCloning(attributeVector[i].name(), attributeVector[i].value(), ModifiedDirectly);
1096}
1097
1098bool Element::hasAttributes() const
1099{
1100 synchronizeAllAttributes();
1101 return elementData() && elementData()->length();
1102}
1103
1104bool Element::hasEquivalentAttributes(const Element* other) const
1105{
1106 synchronizeAllAttributes();
1107 other->synchronizeAllAttributes();
1108 if (elementData() == other->elementData())
1109 return true;
1110 if (elementData())
1111 return elementData()->isEquivalent(other->elementData());
1112 if (other->elementData())
1113 return other->elementData()->isEquivalent(elementData());
1114 return true;
1115}
1116
1117String Element::nodeName() const
1118{
1119 return m_tagName.toString();
1120}
1121
1122String Element::nodeNamePreservingCase() const
1123{
1124 return m_tagName.toString();
1125}
1126
1127void Element::setPrefix(const AtomicString& prefix, ExceptionCode& ec)
1128{
1129 ec = 0;
1130 checkSetPrefix(prefix, ec);
1131 if (ec)
1132 return;
1133
1134 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
1135}
1136
1137KURL Element::baseURI() const
1138{
1139 const AtomicString& baseAttribute = getAttribute(baseAttr);
1140 KURL base(KURL(), baseAttribute);
1141 if (!base.protocol().isEmpty())
1142 return base;
1143
1144 ContainerNode* parent = parentNode();
1145 if (!parent)
1146 return base;
1147
1148 const KURL& parentBase = parent->baseURI();
1149 if (parentBase.isNull())
1150 return base;
1151
1152 return KURL(parentBase, baseAttribute);
1153}
1154
1155const AtomicString& Element::imageSourceURL() const
1156{
1157 return getAttribute(srcAttr);
1158}
1159
1160bool Element::rendererIsNeeded(const NodeRenderingContext& context)
1161{
1162 return context.style()->display() != NONE;
1163}
1164
1165RenderObject* Element::createRenderer(RenderArena*, RenderStyle* style)
1166{
1167 return RenderObject::createObject(this, style);
1168}
1169
1170#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
1171bool Element::isDateTimeFieldElement() const
1172{
1173 return false;
1174}
1175#endif
1176
1177bool Element::wasChangedSinceLastFormControlChangeEvent() const
1178{
1179 return false;
1180}
1181
1182void Element::setChangedSinceLastFormControlChangeEvent(bool)
1183{
1184}
1185
1186bool Element::isDisabledFormControl() const
1187{
1188 // FIXME: disabled and inert are separate concepts in the spec, but now we treat them as the same.
1189 // For example, an inert, non-disabled form control should not be grayed out.
1190 if (isInert())
1191 return true;
1192 return false;
1193}
1194
1195bool Element::isInert() const
1196{
1197 Element* dialog = document()->activeModalDialog();
1198 return dialog && !containsIncludingShadowDOM(dialog) && !dialog->containsIncludingShadowDOM(this);
1199}
1200
1201Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertionPoint)
1202{
1203 // need to do superclass processing first so inDocument() is true
1204 // by the time we reach updateId
1205 ContainerNode::insertedInto(insertionPoint);
1206
1207 if (containsFullScreenElement() && parentElement() && !parentElement()->containsFullScreenElement())
1208 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
1209
1210 if (Element* before = pseudoElement(BEFORE))
1211 before->insertedInto(insertionPoint);
1212
1213 if (Element* after = pseudoElement(AFTER))
1214 after->insertedInto(insertionPoint);
1215
1216 if (!insertionPoint->isInTreeScope())
1217 return InsertionDone;
1218
1219 if (hasRareData())
1220 elementRareData()->clearClassListValueForQuirksMode();
1221
1222 TreeScope* scope = insertionPoint->treeScope();
1223 if (scope != treeScope())
1224 return InsertionDone;
1225
1226 const AtomicString& idValue = getIdAttribute();
1227 if (!idValue.isNull())
1228 updateId(scope, nullAtom, idValue);
1229
1230 const AtomicString& nameValue = getNameAttribute();
1231 if (!nameValue.isNull())
1232 updateName(nullAtom, nameValue);
1233
1234 if (hasTagName(labelTag)) {
1235 if (scope->shouldCacheLabelsByForAttribute())
1236 updateLabel(scope, nullAtom, fastGetAttribute(forAttr));
1237 }
1238
1239 return InsertionDone;
1240}
1241
1242void Element::removedFrom(ContainerNode* insertionPoint)
1243{
1244#if ENABLE(SVG)
1245 bool wasInDocument = insertionPoint->document();
1246#endif
1247
1248 if (Element* before = pseudoElement(BEFORE))
1249 before->removedFrom(insertionPoint);
1250
1251 if (Element* after = pseudoElement(AFTER))
1252 after->removedFrom(insertionPoint);
1253
1254 document()->removeFromTopLayer(this);
1255 if (containsFullScreenElement())
1256 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
1257
1258 if (document()->page())
1259 document()->page()->pointerLockController()->elementRemoved(this);
1260
1261 setSavedLayerScrollOffset(IntSize());
1262
1263 if (insertionPoint->isInTreeScope() && treeScope() == document()) {
1264 const AtomicString& idValue = getIdAttribute();
1265 if (!idValue.isNull())
1266 updateId(insertionPoint->treeScope(), idValue, nullAtom);
1267
1268 const AtomicString& nameValue = getNameAttribute();
1269 if (!nameValue.isNull())
1270 updateName(nameValue, nullAtom);
1271
1272 if (hasTagName(labelTag)) {
1273 TreeScope* treeScope = insertionPoint->treeScope();
1274 if (treeScope->shouldCacheLabelsByForAttribute())
1275 updateLabel(treeScope, fastGetAttribute(forAttr), nullAtom);
1276 }
1277 }
1278
1279 ContainerNode::removedFrom(insertionPoint);
1280#if ENABLE(SVG)
1281 if (wasInDocument && hasPendingResources())
1282 document()->accessSVGExtensions()->removeElementFromPendingResources(this);
1283#endif
1284}
1285
1286void Element::createRendererIfNeeded()
1287{
1288 NodeRenderingContext(this).createRendererForElementIfNeeded();
1289}
1290
1291void Element::attach()
1292{
1293 PostAttachCallbackDisabler callbackDisabler(this);
1294 StyleResolverParentPusher parentPusher(this);
1295 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1296
1297 createRendererIfNeeded();
1298
1299 if (parentElement() && parentElement()->isInCanvasSubtree())
1300 setIsInCanvasSubtree(true);
1301
1302 createPseudoElementIfNeeded(BEFORE);
1303
1304 // When a shadow root exists, it does the work of attaching the children.
1305 if (ElementShadow* shadow = this->shadow()) {
1306 parentPusher.push();
1307 shadow->attach();
1308 } else if (firstChild())
1309 parentPusher.push();
1310
1311 ContainerNode::attach();
1312
1313 createPseudoElementIfNeeded(AFTER);
1314
1315 if (hasRareData()) {
1316 ElementRareData* data = elementRareData();
1317 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
1318 if (isFocusable() && document()->focusedNode() == this)
1319 document()->updateFocusAppearanceSoon(false /* don't restore selection */);
1320 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1321 }
1322 }
1323}
1324
1325void Element::unregisterNamedFlowContentNode()
1326{
1327 if (RuntimeEnabledFeatures::cssRegionsEnabled() && inNamedFlow() && document()->renderView())
1328 document()->renderView()->flowThreadController()->unregisterNamedFlowContentNode(this);
1329}
1330
1331void Element::detach()
1332{
1333 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1334 unregisterNamedFlowContentNode();
1335 cancelFocusAppearanceUpdate();
1336 if (hasRareData()) {
1337 ElementRareData* data = elementRareData();
1338 data->setPseudoElement(BEFORE, 0);
1339 data->setPseudoElement(AFTER, 0);
1340 data->setIsInCanvasSubtree(false);
1341 data->resetComputedStyle();
1342 data->resetDynamicRestyleObservations();
1343 }
1344
1345 if (ElementShadow* shadow = this->shadow()) {
1346 detachChildrenIfNeeded();
1347 shadow->detach();
1348 }
1349 ContainerNode::detach();
1350}
1351
1352bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle)
1353{
1354 ASSERT(currentStyle == renderStyle());
1355 ASSERT(renderer());
1356
1357 if (!currentStyle)
1358 return false;
1359
1360 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles();
1361 if (!pseudoStyleCache)
1362 return false;
1363
1364 size_t cacheSize = pseudoStyleCache->size();
1365 for (size_t i = 0; i < cacheSize; ++i) {
1366 RefPtr<RenderStyle> newPseudoStyle;
1367 PseudoId pseudoId = pseudoStyleCache->at(i)->styleType();
1368 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
1369 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle);
1370 else
1371 newPseudoStyle = renderer()->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
1372 if (!newPseudoStyle)
1373 return true;
1374 if (*newPseudoStyle != *pseudoStyleCache->at(i)) {
1375 if (pseudoId < FIRST_INTERNAL_PSEUDOID)
1376 newStyle->setHasPseudoStyle(pseudoId);
1377 newStyle->addCachedPseudoStyle(newPseudoStyle);
1378 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
1379 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
1380 // is needed, but for now just assume a layout will be required. The diff code
1381 // in RenderObject::setStyle would need to be factored out so that it could be reused.
1382 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
1383 }
1384 return true;
1385 }
1386 }
1387 return false;
1388}
1389
1390PassRefPtr<RenderStyle> Element::styleForRenderer()
1391{
1392 if (hasCustomStyleCallbacks()) {
1393 if (RefPtr<RenderStyle> style = customStyleForRenderer())
1394 return style.release();
1395 }
1396
1397 return document()->styleResolver()->styleForElement(this);
1398}
1399
1400void Element::recalcStyle(StyleChange change)
1401{
1402 if (hasCustomStyleCallbacks())
1403 willRecalcStyle(change);
1404
1405 // Ref currentStyle in case it would otherwise be deleted when setting the new style in the renderer.
1406 RefPtr<RenderStyle> currentStyle(renderStyle());
1407 bool hasParentStyle = parentNodeForRenderingAndStyle() ? static_cast<bool>(parentNodeForRenderingAndStyle()->renderStyle()) : false;
1408 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
1409 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
1410
1411 if ((change > NoChange || needsStyleRecalc())) {
1412 if (hasRareData())
1413 elementRareData()->resetComputedStyle();
1414 }
1415 if (hasParentStyle && (change >= Inherit || needsStyleRecalc())) {
1416 StyleChange localChange = Detach;
1417 RefPtr<RenderStyle> newStyle;
1418 if (currentStyle) {
1419 // FIXME: This still recalcs style twice when changing display types, but saves
1420 // us from recalcing twice when going from none -> anything else which is more
1421 // common, especially during lazy attach.
1422 newStyle = styleForRenderer();
1423 localChange = Node::diff(currentStyle.get(), newStyle.get(), document());
1424 }
1425 if (localChange == Detach) {
1426 // FIXME: The style gets computed twice by calling attach. We could do better if we passed the style along.
1427 reattach();
1428 // attach recalculates the style for all children. No need to do it twice.
1429 clearNeedsStyleRecalc();
1430 clearChildNeedsStyleRecalc();
1431
1432 if (hasCustomStyleCallbacks())
1433 didRecalcStyle(change);
1434 return;
1435 }
1436
1437 if (RenderObject* renderer = this->renderer()) {
1438 if (localChange != NoChange || pseudoStyleCacheIsInvalid(currentStyle.get(), newStyle.get()) || (change == Force && renderer->requiresForcedStyleRecalcPropagation()) || styleChangeType() == SyntheticStyleChange)
1439 renderer->setAnimatableStyle(newStyle.get());
1440 else if (needsStyleRecalc()) {
1441 // Although no change occurred, we use the new style so that the cousin style sharing code won't get
1442 // fooled into believing this style is the same.
1443 renderer->setStyleInternal(newStyle.get());
1444 }
1445 }
1446
1447 // 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
1448 // 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).
1449 if (document()->styleSheetCollection()->usesRemUnits() && document()->documentElement() == this && localChange != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize()) {
1450 // Cached RenderStyles may depend on the re units.
1451 document()->styleResolver()->invalidateMatchedPropertiesCache();
1452 change = Force;
1453 }
1454
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001455 if (styleChangeType() == FullStyleChange)
1456 change = Force;
1457 else if (change != Force)
1458 change = localChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001459 }
1460 StyleResolverParentPusher parentPusher(this);
1461
1462 // FIXME: This does not care about sibling combinators. Will be necessary in XBL2 world.
1463 if (ElementShadow* shadow = this->shadow()) {
1464 if (shouldRecalcStyle(change, shadow)) {
1465 parentPusher.push();
1466 shadow->recalcStyle(change);
1467 }
1468 }
1469
1470 if (shouldRecalcStyle(change, this))
1471 updatePseudoElement(BEFORE, change);
1472
1473 // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
1474 // For now we will just worry about the common case, since it's a lot trickier to get the second case right
1475 // without doing way too much re-resolution.
1476 bool forceCheckOfNextElementSibling = false;
1477 bool forceCheckOfAnyElementSibling = false;
1478 for (Node *n = firstChild(); n; n = n->nextSibling()) {
1479 if (n->isTextNode()) {
1480 toText(n)->recalcTextStyle(change);
1481 continue;
1482 }
1483 if (!n->isElementNode())
1484 continue;
1485 Element* element = toElement(n);
1486 bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() == FullStyleChange;
1487 if ((forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling))
1488 element->setNeedsStyleRecalc();
1489 if (shouldRecalcStyle(change, element)) {
1490 parentPusher.push();
1491 element->recalcStyle(change);
1492 }
1493 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
1494 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
1495 }
1496
1497 if (shouldRecalcStyle(change, this))
1498 updatePseudoElement(AFTER, change);
1499
1500 clearNeedsStyleRecalc();
1501 clearChildNeedsStyleRecalc();
1502
1503 if (hasCustomStyleCallbacks())
1504 didRecalcStyle(change);
1505 InspectorInstrumentation::didRecalculateStyleForElement(this);
1506}
1507
1508ElementShadow* Element::shadow() const
1509{
1510 return hasRareData() ? elementRareData()->shadow() : 0;
1511}
1512
1513ElementShadow* Element::ensureShadow()
1514{
1515 return ensureElementRareData()->ensureShadow();
1516}
1517
1518void Element::didAffectSelector(AffectedSelectorMask mask)
1519{
1520 setNeedsStyleRecalc();
1521 if (ElementShadow* elementShadow = shadowOfParentForDistribution(this))
1522 elementShadow->didAffectSelector(mask);
1523}
1524
1525PassRefPtr<ShadowRoot> Element::createShadowRoot(ExceptionCode& ec)
1526{
1527 if (alwaysCreateUserAgentShadowRoot())
1528 ensureUserAgentShadowRoot();
1529
1530 if (RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled())
1531 return ensureShadow()->addShadowRoot(this, ShadowRoot::AuthorShadowRoot);
1532
1533 // Since some elements recreates shadow root dynamically, multiple shadow
1534 // subtrees won't work well in that element. Until they are fixed, we disable
1535 // adding author shadow root for them.
1536 if (!areAuthorShadowsAllowed()) {
1537 ec = HIERARCHY_REQUEST_ERR;
1538 return 0;
1539 }
1540 return ensureShadow()->addShadowRoot(this, ShadowRoot::AuthorShadowRoot);
1541}
1542
1543ShadowRoot* Element::shadowRoot() const
1544{
1545 ElementShadow* elementShadow = shadow();
1546 if (!elementShadow)
1547 return 0;
1548 ShadowRoot* shadowRoot = elementShadow->youngestShadowRoot();
1549 if (shadowRoot->type() == ShadowRoot::AuthorShadowRoot)
1550 return shadowRoot;
1551 return 0;
1552}
1553
1554ShadowRoot* Element::userAgentShadowRoot() const
1555{
1556 if (ElementShadow* elementShadow = shadow()) {
1557 if (ShadowRoot* shadowRoot = elementShadow->oldestShadowRoot()) {
1558 ASSERT(shadowRoot->type() == ShadowRoot::UserAgentShadowRoot);
1559 return shadowRoot;
1560 }
1561 }
1562
1563 return 0;
1564}
1565
1566ShadowRoot* Element::ensureUserAgentShadowRoot()
1567{
1568 if (ShadowRoot* shadowRoot = userAgentShadowRoot())
1569 return shadowRoot;
1570 ShadowRoot* shadowRoot = ensureShadow()->addShadowRoot(this, ShadowRoot::UserAgentShadowRoot);
1571 didAddUserAgentShadowRoot(shadowRoot);
1572 return shadowRoot;
1573}
1574
1575const AtomicString& Element::shadowPseudoId() const
1576{
1577 return pseudo();
1578}
1579
1580bool Element::childTypeAllowed(NodeType type) const
1581{
1582 switch (type) {
1583 case ELEMENT_NODE:
1584 case TEXT_NODE:
1585 case COMMENT_NODE:
1586 case PROCESSING_INSTRUCTION_NODE:
1587 case CDATA_SECTION_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001588 return true;
1589 default:
1590 break;
1591 }
1592 return false;
1593}
1594
1595static void checkForEmptyStyleChange(Element* element, RenderStyle* style)
1596{
1597 if (!style && !element->styleAffectedByEmpty())
1598 return;
1599
1600 if (!style || (element->styleAffectedByEmpty() && (!style->emptyState() || element->hasChildNodes())))
1601 element->setNeedsStyleRecalc();
1602}
1603
1604static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
1605 Node* beforeChange, Node* afterChange, int childCountDelta)
1606{
1607 // :empty selector.
1608 checkForEmptyStyleChange(e, style);
1609
1610 if (!style || (e->needsStyleRecalc() && e->childrenAffectedByPositionalRules()))
1611 return;
1612
1613 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1614 // In the DOM case, we only need to do something if |afterChange| is not 0.
1615 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
1616 if (e->childrenAffectedByFirstChildRules() && afterChange) {
1617 // Find our new first child.
1618 Node* newFirstChild = 0;
1619 for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {};
1620
1621 // Find the first element node following |afterChange|
1622 Node* firstElementAfterInsertion = 0;
1623 for (firstElementAfterInsertion = afterChange;
1624 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
1625 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
1626
1627 // This is the insert/append case.
1628 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertion && firstElementAfterInsertion->attached() &&
1629 firstElementAfterInsertion->renderStyle() && firstElementAfterInsertion->renderStyle()->firstChildState())
1630 firstElementAfterInsertion->setNeedsStyleRecalc();
1631
1632 // We also have to handle node removal.
1633 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChild->renderStyle() || !newFirstChild->renderStyle()->firstChildState()))
1634 newFirstChild->setNeedsStyleRecalc();
1635 }
1636
1637 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1638 // In the DOM case, we only need to do something if |afterChange| is not 0.
1639 if (e->childrenAffectedByLastChildRules() && beforeChange) {
1640 // Find our new last child.
1641 Node* newLastChild = 0;
1642 for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {};
1643
1644 // Find the last element node going backwards from |beforeChange|
1645 Node* lastElementBeforeInsertion = 0;
1646 for (lastElementBeforeInsertion = beforeChange;
1647 lastElementBeforeInsertion && !lastElementBeforeInsertion->isElementNode();
1648 lastElementBeforeInsertion = lastElementBeforeInsertion->previousSibling()) {};
1649
1650 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertion && lastElementBeforeInsertion->attached() &&
1651 lastElementBeforeInsertion->renderStyle() && lastElementBeforeInsertion->renderStyle()->lastChildState())
1652 lastElementBeforeInsertion->setNeedsStyleRecalc();
1653
1654 // 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
1655 // to match now.
1656 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChild->renderStyle() || !newLastChild->renderStyle()->lastChildState()))
1657 newLastChild->setNeedsStyleRecalc();
1658 }
1659
1660 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
1661 // that could be affected by this DOM change.
1662 if (e->childrenAffectedByDirectAdjacentRules() && afterChange) {
1663 Node* firstElementAfterInsertion = 0;
1664 for (firstElementAfterInsertion = afterChange;
1665 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
1666 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
1667 if (firstElementAfterInsertion && firstElementAfterInsertion->attached())
1668 firstElementAfterInsertion->setNeedsStyleRecalc();
1669 }
1670
1671 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
1672 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1673 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
1674 // backward case.
1675 // |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.
1676 // 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
1677 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
1678 if ((e->childrenAffectedByForwardPositionalRules() && afterChange)
1679 || (e->childrenAffectedByBackwardPositionalRules() && beforeChange))
1680 e->setNeedsStyleRecalc();
1681}
1682
1683void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
1684{
1685 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
1686 if (changedByParser)
1687 checkForEmptyStyleChange(this, renderStyle());
1688 else
1689 checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
1690
1691 if (ElementShadow * shadow = this->shadow())
1692 shadow->invalidateDistribution();
1693}
1694
1695void Element::removeAllEventListeners()
1696{
1697 ContainerNode::removeAllEventListeners();
1698 if (ElementShadow* shadow = this->shadow())
1699 shadow->removeAllEventListeners();
1700}
1701
1702void Element::beginParsingChildren()
1703{
1704 clearIsParsingChildrenFinished();
1705 StyleResolver* styleResolver = document()->styleResolverIfExists();
1706 if (styleResolver && attached())
1707 styleResolver->pushParentElement(this);
1708}
1709
1710void Element::finishParsingChildren()
1711{
1712 ContainerNode::finishParsingChildren();
1713 setIsParsingChildrenFinished();
1714 checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
1715 if (StyleResolver* styleResolver = document()->styleResolverIfExists())
1716 styleResolver->popParentElement(this);
1717}
1718
1719#ifndef NDEBUG
1720void Element::formatForDebugger(char* buffer, unsigned length) const
1721{
1722 StringBuilder result;
1723 String s;
1724
1725 result.append(nodeName());
1726
1727 s = getIdAttribute();
1728 if (s.length() > 0) {
1729 if (result.length() > 0)
1730 result.appendLiteral("; ");
1731 result.appendLiteral("id=");
1732 result.append(s);
1733 }
1734
1735 s = getAttribute(classAttr);
1736 if (s.length() > 0) {
1737 if (result.length() > 0)
1738 result.appendLiteral("; ");
1739 result.appendLiteral("class=");
1740 result.append(s);
1741 }
1742
1743 strncpy(buffer, result.toString().utf8().data(), length - 1);
1744}
1745#endif
1746
1747const Vector<RefPtr<Attr> >& Element::attrNodeList()
1748{
1749 ASSERT(hasSyntheticAttrChildNodes());
1750 return *attrNodeListForElement(this);
1751}
1752
1753PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionCode& ec)
1754{
1755 if (!attrNode) {
1756 ec = TYPE_MISMATCH_ERR;
1757 return 0;
1758 }
1759
1760 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName());
1761 if (oldAttrNode.get() == attrNode)
1762 return attrNode; // This Attr is already attached to the element.
1763
1764 // INUSE_ATTRIBUTE_ERR: Raised if node is an Attr that is already an attribute of another Element object.
1765 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
1766 if (attrNode->ownerElement()) {
1767 ec = INUSE_ATTRIBUTE_ERR;
1768 return 0;
1769 }
1770
1771 synchronizeAllAttributes();
1772 UniqueElementData* elementData = ensureUniqueElementData();
1773
1774 size_t index = elementData->getAttributeItemIndex(attrNode->qualifiedName());
1775 if (index != notFound) {
1776 if (oldAttrNode)
1777 detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData->attributeItem(index)->value());
1778 else
1779 oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), elementData->attributeItem(index)->value());
1780 }
1781
1782 setAttributeInternal(index, attrNode->qualifiedName(), attrNode->value(), NotInSynchronizationOfLazyAttribute);
1783
1784 attrNode->attachToElement(this);
1785 ensureAttrNodeListForElement(this)->append(attrNode);
1786
1787 return oldAttrNode.release();
1788}
1789
1790PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionCode& ec)
1791{
1792 return setAttributeNode(attr, ec);
1793}
1794
1795PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec)
1796{
1797 if (!attr) {
1798 ec = TYPE_MISMATCH_ERR;
1799 return 0;
1800 }
1801 if (attr->ownerElement() != this) {
1802 ec = NOT_FOUND_ERR;
1803 return 0;
1804 }
1805
1806 ASSERT(document() == attr->document());
1807
1808 synchronizeAttribute(attr->qualifiedName());
1809
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001810 size_t index = elementData()->getAttrIndex(attr);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001811 if (index == notFound) {
1812 ec = NOT_FOUND_ERR;
1813 return 0;
1814 }
1815
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001816 RefPtr<Attr> guard(attr);
1817 detachAttrNodeAtIndex(attr, index);
1818 return guard.release();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001819}
1820
1821bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionCode& ec)
1822{
1823 String prefix, localName;
1824 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec))
1825 return false;
1826 ASSERT(!ec);
1827
1828 QualifiedName qName(prefix, localName, namespaceURI);
1829
1830 if (!Document::hasValidNamespaceForAttributes(qName)) {
1831 ec = NAMESPACE_ERR;
1832 return false;
1833 }
1834
1835 out = qName;
1836 return true;
1837}
1838
1839void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode& ec)
1840{
1841 QualifiedName parsedName = anyName;
1842 if (!parseAttributeName(parsedName, namespaceURI, qualifiedName, ec))
1843 return;
1844 setAttribute(parsedName, value);
1845}
1846
1847void Element::removeAttributeInternal(size_t index, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1848{
1849 ASSERT_WITH_SECURITY_IMPLICATION(index < attributeCount());
1850
1851 UniqueElementData* elementData = ensureUniqueElementData();
1852
1853 QualifiedName name = elementData->attributeItem(index)->name();
1854 AtomicString valueBeingRemoved = elementData->attributeItem(index)->value();
1855
1856 if (!inSynchronizationOfLazyAttribute) {
1857 if (!valueBeingRemoved.isNull())
1858 willModifyAttribute(name, valueBeingRemoved, nullAtom);
1859 }
1860
1861 if (RefPtr<Attr> attrNode = attrIfExists(name))
1862 detachAttrNodeFromElementWithValue(attrNode.get(), elementData->attributeItem(index)->value());
1863
1864 elementData->removeAttribute(index);
1865
1866 if (!inSynchronizationOfLazyAttribute)
1867 didRemoveAttribute(name);
1868}
1869
1870void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1871{
1872 if (!inSynchronizationOfLazyAttribute)
1873 willModifyAttribute(name, nullAtom, value);
1874 ensureUniqueElementData()->addAttribute(name, value);
1875 if (!inSynchronizationOfLazyAttribute)
1876 didAddAttribute(name, value);
1877}
1878
1879void Element::removeAttribute(const AtomicString& name)
1880{
1881 if (!elementData())
1882 return;
1883
1884 AtomicString localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1885 size_t index = elementData()->getAttributeItemIndex(localName, false);
1886 if (index == notFound) {
1887 if (UNLIKELY(localName == styleAttr) && elementData()->m_styleAttributeIsDirty && isStyledElement())
1888 static_cast<StyledElement*>(this)->removeAllInlineStyleProperties();
1889 return;
1890 }
1891
1892 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
1893}
1894
1895void Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName)
1896{
1897 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI));
1898}
1899
1900PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& localName)
1901{
1902 if (!elementData())
1903 return 0;
1904 synchronizeAttribute(localName);
1905 const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase(this));
1906 if (!attribute)
1907 return 0;
1908 return ensureAttr(attribute->name());
1909}
1910
1911PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
1912{
1913 if (!elementData())
1914 return 0;
1915 QualifiedName qName(nullAtom, localName, namespaceURI);
1916 synchronizeAttribute(qName);
1917 const Attribute* attribute = elementData()->getAttributeItem(qName);
1918 if (!attribute)
1919 return 0;
1920 return ensureAttr(attribute->name());
1921}
1922
1923bool Element::hasAttribute(const AtomicString& localName) const
1924{
1925 if (!elementData())
1926 return false;
1927 synchronizeAttribute(localName);
1928 return elementData()->getAttributeItem(shouldIgnoreAttributeCase(this) ? localName.lower() : localName, false);
1929}
1930
1931bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
1932{
1933 if (!elementData())
1934 return false;
1935 QualifiedName qName(nullAtom, localName, namespaceURI);
1936 synchronizeAttribute(qName);
1937 return elementData()->getAttributeItem(qName);
1938}
1939
1940CSSStyleDeclaration *Element::style()
1941{
1942 return 0;
1943}
1944
1945void Element::focus(bool restorePreviousSelection, FocusDirection direction)
1946{
1947 if (!inDocument())
1948 return;
1949
1950 Document* doc = document();
1951 if (doc->focusedNode() == this)
1952 return;
1953
1954 // If the stylesheets have already been loaded we can reliably check isFocusable.
1955 // If not, we continue and set the focused node on the focus controller below so
1956 // that it can be updated soon after attach.
1957 if (doc->haveStylesheetsLoaded()) {
1958 doc->updateLayoutIgnorePendingStylesheets();
1959 if (!isFocusable())
1960 return;
1961 }
1962
1963 if (!supportsFocus())
1964 return;
1965
1966 RefPtr<Node> protect;
1967 if (Page* page = doc->page()) {
1968 // Focus and change event handlers can cause us to lose our last ref.
1969 // If a focus event handler changes the focus to a different node it
1970 // does not make sense to continue and update appearence.
1971 protect = this;
1972 if (!page->focusController()->setFocusedNode(this, doc->frame(), direction))
1973 return;
1974 }
1975
1976 // Setting the focused node above might have invalidated the layout due to scripts.
1977 doc->updateLayoutIgnorePendingStylesheets();
1978
1979 if (!isFocusable()) {
1980 ensureElementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
1981 return;
1982 }
1983
1984 cancelFocusAppearanceUpdate();
1985 updateFocusAppearance(restorePreviousSelection);
1986}
1987
1988void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
1989{
1990 if (isRootEditableElement()) {
1991 Frame* frame = document()->frame();
1992 if (!frame)
1993 return;
1994
1995 // When focusing an editable element in an iframe, don't reset the selection if it already contains a selection.
1996 if (this == frame->selection()->rootEditableElement())
1997 return;
1998
1999 // FIXME: We should restore the previous selection if there is one.
2000 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
2001
2002 if (frame->selection()->shouldChangeSelection(newSelection)) {
2003 frame->selection()->setSelection(newSelection);
2004 frame->selection()->revealSelection();
2005 }
2006 } else if (renderer() && !renderer()->isWidget())
2007 renderer()->scrollRectToVisible(boundingBox());
2008}
2009
2010void Element::blur()
2011{
2012 cancelFocusAppearanceUpdate();
2013 Document* doc = document();
2014 if (treeScope()->focusedNode() == this) {
2015 if (doc->frame())
2016 doc->frame()->page()->focusController()->setFocusedNode(0, doc->frame());
2017 else
2018 doc->setFocusedNode(0);
2019 }
2020}
2021
2022String Element::innerText()
2023{
2024 // We need to update layout, since plainText uses line boxes in the render tree.
2025 document()->updateLayoutIgnorePendingStylesheets();
2026
2027 if (!renderer())
2028 return textContent(true);
2029
2030 return plainText(rangeOfContents(const_cast<Element*>(this)).get());
2031}
2032
2033String Element::outerText()
2034{
2035 // Getting outerText is the same as getting innerText, only
2036 // setting is different. You would think this should get the plain
2037 // text for the outer range, but this is wrong, <br> for instance
2038 // would return different values for inner and outer text by such
2039 // a rule, but it doesn't in WinIE, and we want to match that.
2040 return innerText();
2041}
2042
2043String Element::title() const
2044{
2045 return String();
2046}
2047
2048const AtomicString& Element::pseudo() const
2049{
2050 return getAttribute(pseudoAttr);
2051}
2052
2053void Element::setPseudo(const AtomicString& value)
2054{
2055 setAttribute(pseudoAttr, value);
2056}
2057
2058LayoutSize Element::minimumSizeForResizing() const
2059{
2060 return hasRareData() ? elementRareData()->minimumSizeForResizing() : defaultMinimumSizeForResizing();
2061}
2062
2063void Element::setMinimumSizeForResizing(const LayoutSize& size)
2064{
2065 if (!hasRareData() && size == defaultMinimumSizeForResizing())
2066 return;
2067 ensureElementRareData()->setMinimumSizeForResizing(size);
2068}
2069
2070RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
2071{
2072 if (PseudoElement* element = pseudoElement(pseudoElementSpecifier))
2073 return element->computedStyle();
2074
2075 // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
2076 // properties, which are only known by the renderer because it did the layout, will be correct and so that the
2077 // values returned for the ":selection" pseudo-element will be correct.
2078 if (RenderStyle* usedStyle = renderStyle()) {
2079 if (pseudoElementSpecifier) {
2080 RenderStyle* cachedPseudoStyle = usedStyle->getCachedPseudoStyle(pseudoElementSpecifier);
2081 return cachedPseudoStyle ? cachedPseudoStyle : usedStyle;
2082 } else
2083 return usedStyle;
2084 }
2085
2086 if (!attached())
2087 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
2088 // document tree and figure out when to destroy the computed style for such elements.
2089 return 0;
2090
2091 ElementRareData* data = ensureElementRareData();
2092 if (!data->computedStyle())
2093 data->setComputedStyle(document()->styleForElementIgnoringPendingStylesheets(this));
2094 return pseudoElementSpecifier ? data->computedStyle()->getCachedPseudoStyle(pseudoElementSpecifier) : data->computedStyle();
2095}
2096
2097void Element::setStyleAffectedByEmpty()
2098{
2099 ensureElementRareData()->setStyleAffectedByEmpty(true);
2100}
2101
2102void Element::setChildrenAffectedByHover(bool value)
2103{
2104 if (value || hasRareData())
2105 ensureElementRareData()->setChildrenAffectedByHover(value);
2106}
2107
2108void Element::setChildrenAffectedByActive(bool value)
2109{
2110 if (value || hasRareData())
2111 ensureElementRareData()->setChildrenAffectedByActive(value);
2112}
2113
2114void Element::setChildrenAffectedByDrag(bool value)
2115{
2116 if (value || hasRareData())
2117 ensureElementRareData()->setChildrenAffectedByDrag(value);
2118}
2119
2120void Element::setChildrenAffectedByFirstChildRules()
2121{
2122 ensureElementRareData()->setChildrenAffectedByFirstChildRules(true);
2123}
2124
2125void Element::setChildrenAffectedByLastChildRules()
2126{
2127 ensureElementRareData()->setChildrenAffectedByLastChildRules(true);
2128}
2129
2130void Element::setChildrenAffectedByDirectAdjacentRules()
2131{
2132 ensureElementRareData()->setChildrenAffectedByDirectAdjacentRules(true);
2133}
2134
2135void Element::setChildrenAffectedByForwardPositionalRules()
2136{
2137 ensureElementRareData()->setChildrenAffectedByForwardPositionalRules(true);
2138}
2139
2140void Element::setChildrenAffectedByBackwardPositionalRules()
2141{
2142 ensureElementRareData()->setChildrenAffectedByBackwardPositionalRules(true);
2143}
2144
2145void Element::setChildIndex(unsigned index)
2146{
2147 ElementRareData* rareData = ensureElementRareData();
2148 if (RenderStyle* style = renderStyle())
2149 style->setUnique();
2150 rareData->setChildIndex(index);
2151}
2152
2153bool Element::hasFlagsSetDuringStylingOfChildren() const
2154{
2155 if (!hasRareData())
2156 return false;
2157 return rareDataChildrenAffectedByHover()
2158 || rareDataChildrenAffectedByActive()
2159 || rareDataChildrenAffectedByDrag()
2160 || rareDataChildrenAffectedByFirstChildRules()
2161 || rareDataChildrenAffectedByLastChildRules()
2162 || rareDataChildrenAffectedByDirectAdjacentRules()
2163 || rareDataChildrenAffectedByForwardPositionalRules()
2164 || rareDataChildrenAffectedByBackwardPositionalRules();
2165}
2166
2167bool Element::rareDataStyleAffectedByEmpty() const
2168{
2169 ASSERT(hasRareData());
2170 return elementRareData()->styleAffectedByEmpty();
2171}
2172
2173bool Element::rareDataChildrenAffectedByHover() const
2174{
2175 ASSERT(hasRareData());
2176 return elementRareData()->childrenAffectedByHover();
2177}
2178
2179bool Element::rareDataChildrenAffectedByActive() const
2180{
2181 ASSERT(hasRareData());
2182 return elementRareData()->childrenAffectedByActive();
2183}
2184
2185bool Element::rareDataChildrenAffectedByDrag() const
2186{
2187 ASSERT(hasRareData());
2188 return elementRareData()->childrenAffectedByDrag();
2189}
2190
2191bool Element::rareDataChildrenAffectedByFirstChildRules() const
2192{
2193 ASSERT(hasRareData());
2194 return elementRareData()->childrenAffectedByFirstChildRules();
2195}
2196
2197bool Element::rareDataChildrenAffectedByLastChildRules() const
2198{
2199 ASSERT(hasRareData());
2200 return elementRareData()->childrenAffectedByLastChildRules();
2201}
2202
2203bool Element::rareDataChildrenAffectedByDirectAdjacentRules() const
2204{
2205 ASSERT(hasRareData());
2206 return elementRareData()->childrenAffectedByDirectAdjacentRules();
2207}
2208
2209bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
2210{
2211 ASSERT(hasRareData());
2212 return elementRareData()->childrenAffectedByForwardPositionalRules();
2213}
2214
2215bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
2216{
2217 ASSERT(hasRareData());
2218 return elementRareData()->childrenAffectedByBackwardPositionalRules();
2219}
2220
2221unsigned Element::rareDataChildIndex() const
2222{
2223 ASSERT(hasRareData());
2224 return elementRareData()->childIndex();
2225}
2226
2227void Element::setIsInCanvasSubtree(bool isInCanvasSubtree)
2228{
2229 ensureElementRareData()->setIsInCanvasSubtree(isInCanvasSubtree);
2230}
2231
2232bool Element::isInCanvasSubtree() const
2233{
2234 return hasRareData() && elementRareData()->isInCanvasSubtree();
2235}
2236
2237bool Element::isUnresolvedCustomElement()
2238{
2239 return isCustomElement() && document()->registry()->isUnresolved(this);
2240}
2241
2242AtomicString Element::computeInheritedLanguage() const
2243{
2244 const Node* n = this;
2245 AtomicString value;
2246 // The language property is inherited, so we iterate over the parents to find the first language.
2247 do {
2248 if (n->isElementNode()) {
2249 if (const ElementData* elementData = toElement(n)->elementData()) {
2250 // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7
2251 if (const Attribute* attribute = elementData->getAttributeItem(XMLNames::langAttr))
2252 value = attribute->value();
2253 else if (const Attribute* attribute = elementData->getAttributeItem(HTMLNames::langAttr))
2254 value = attribute->value();
2255 }
2256 } else if (n->isDocumentNode()) {
2257 // checking the MIME content-language
2258 value = toDocument(n)->contentLanguage();
2259 }
2260
2261 n = n->parentNode();
2262 } while (n && value.isNull());
2263
2264 return value;
2265}
2266
2267Locale& Element::locale() const
2268{
2269 return document()->getCachedLocale(computeInheritedLanguage());
2270}
2271
2272void Element::cancelFocusAppearanceUpdate()
2273{
2274 if (hasRareData())
2275 elementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
2276 if (document()->focusedNode() == this)
2277 document()->cancelFocusAppearanceUpdate();
2278}
2279
2280void Element::normalizeAttributes()
2281{
2282 if (!hasAttributes())
2283 return;
2284 for (unsigned i = 0; i < attributeCount(); ++i) {
2285 if (RefPtr<Attr> attr = attrIfExists(attributeItem(i)->name()))
2286 attr->normalize();
2287 }
2288}
2289
2290void Element::updatePseudoElement(PseudoId pseudoId, StyleChange change)
2291{
2292 PseudoElement* element = pseudoElement(pseudoId);
2293 if (element && (needsStyleRecalc() || shouldRecalcStyle(change, element))) {
2294 // PseudoElement styles hang off their parent element's style so if we needed
2295 // a style recalc we should Force one on the pseudo.
2296 element->recalcStyle(needsStyleRecalc() ? Force : change);
2297
2298 // Wait until our parent is not displayed or pseudoElementRendererIsNeeded
2299 // is false, otherwise we could continously create and destroy PseudoElements
2300 // when RenderObject::isChildAllowed on our parent returns false for the
2301 // PseudoElement's renderer for each style recalc.
2302 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
2303 setPseudoElement(pseudoId, 0);
2304 } else if (change >= Inherit || needsStyleRecalc())
2305 createPseudoElementIfNeeded(pseudoId);
2306}
2307
2308void Element::createPseudoElementIfNeeded(PseudoId pseudoId)
2309{
2310 if (!document()->styleSheetCollection()->usesBeforeAfterRules())
2311 return;
2312
2313 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
2314 return;
2315
2316 if (!renderer()->canHaveGeneratedChildren())
2317 return;
2318
2319 ASSERT(!isPseudoElement());
2320 RefPtr<PseudoElement> element = PseudoElement::create(this, pseudoId);
2321 element->attach();
2322 setPseudoElement(pseudoId, element.release());
2323}
2324
2325bool Element::hasPseudoElements() const
2326{
2327 return hasRareData() && elementRareData()->hasPseudoElements();
2328}
2329
2330PseudoElement* Element::pseudoElement(PseudoId pseudoId) const
2331{
2332 return hasRareData() ? elementRareData()->pseudoElement(pseudoId) : 0;
2333}
2334
2335void Element::setPseudoElement(PseudoId pseudoId, PassRefPtr<PseudoElement> element)
2336{
2337 ensureElementRareData()->setPseudoElement(pseudoId, element);
2338 resetNeedsShadowTreeWalker();
2339}
2340
2341RenderObject* Element::pseudoElementRenderer(PseudoId pseudoId) const
2342{
2343 if (PseudoElement* element = pseudoElement(pseudoId))
2344 return element->renderer();
2345 return 0;
2346}
2347
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002348bool Element::matchesReadOnlyPseudoClass() const
2349{
2350 return false;
2351}
2352
2353bool Element::matchesReadWritePseudoClass() const
2354{
2355 return false;
2356}
2357
2358bool Element::webkitMatchesSelector(const String& selector, ExceptionCode& ec)
2359{
2360 if (selector.isEmpty()) {
2361 ec = SYNTAX_ERR;
2362 return false;
2363 }
2364
2365 SelectorQuery* selectorQuery = document()->selectorQueryCache()->add(selector, document(), ec);
2366 if (!selectorQuery)
2367 return false;
2368 return selectorQuery->matches(this);
2369}
2370
2371bool Element::shouldAppearIndeterminate() const
2372{
2373 return false;
2374}
2375
2376DOMTokenList* Element::classList()
2377{
2378 ElementRareData* data = ensureElementRareData();
2379 if (!data->classList())
2380 data->setClassList(ClassList::create(this));
2381 return data->classList();
2382}
2383
2384DOMStringMap* Element::dataset()
2385{
2386 ElementRareData* data = ensureElementRareData();
2387 if (!data->dataset())
2388 data->setDataset(DatasetDOMStringMap::create(this));
2389 return data->dataset();
2390}
2391
2392KURL Element::getURLAttribute(const QualifiedName& name) const
2393{
2394#if !ASSERT_DISABLED
2395 if (elementData()) {
2396 if (const Attribute* attribute = getAttributeItem(name))
2397 ASSERT(isURLAttribute(*attribute));
2398 }
2399#endif
2400 return document()->completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
2401}
2402
2403KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
2404{
2405#if !ASSERT_DISABLED
2406 if (elementData()) {
2407 if (const Attribute* attribute = getAttributeItem(name))
2408 ASSERT(isURLAttribute(*attribute));
2409 }
2410#endif
2411 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
2412 if (value.isEmpty())
2413 return KURL();
2414 return document()->completeURL(value);
2415}
2416
2417int Element::getIntegralAttribute(const QualifiedName& attributeName) const
2418{
2419 return getAttribute(attributeName).string().toInt();
2420}
2421
2422void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
2423{
2424 // FIXME: Need an AtomicString version of String::number.
2425 setAttribute(attributeName, String::number(value));
2426}
2427
2428unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
2429{
2430 return getAttribute(attributeName).string().toUInt();
2431}
2432
2433void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
2434{
2435 // FIXME: Need an AtomicString version of String::number.
2436 setAttribute(attributeName, String::number(value));
2437}
2438
2439#if ENABLE(SVG)
2440bool Element::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
2441{
2442 // Only create renderers for SVG elements whose parents are SVG elements, or for proper <svg xmlns="svgNS"> subdocuments.
2443 if (childContext.node()->isSVGElement())
2444 return childContext.node()->hasTagName(SVGNames::svgTag) || isSVGElement();
2445
2446 return ContainerNode::childShouldCreateRenderer(childContext);
2447}
2448#endif
2449
2450void Element::webkitRequestFullscreen()
2451{
2452 document()->requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, Document::EnforceIFrameAllowFullScreenRequirement);
2453}
2454
2455void Element::webkitRequestFullScreen(unsigned short flags)
2456{
2457 document()->requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), Document::EnforceIFrameAllowFullScreenRequirement);
2458}
2459
2460bool Element::containsFullScreenElement() const
2461{
2462 return hasRareData() && elementRareData()->containsFullScreenElement();
2463}
2464
2465void Element::setContainsFullScreenElement(bool flag)
2466{
2467 ensureElementRareData()->setContainsFullScreenElement(flag);
2468 setNeedsStyleRecalc(SyntheticStyleChange);
2469}
2470
2471static Element* parentCrossingFrameBoundaries(Element* element)
2472{
2473 ASSERT(element);
2474 return element->parentElement() ? element->parentElement() : element->document()->ownerElement();
2475}
2476
2477void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool flag)
2478{
2479 Element* element = this;
2480 while ((element = parentCrossingFrameBoundaries(element)))
2481 element->setContainsFullScreenElement(flag);
2482}
2483
2484bool Element::isInTopLayer() const
2485{
2486 return hasRareData() && elementRareData()->isInTopLayer();
2487}
2488
2489void Element::setIsInTopLayer(bool inTopLayer)
2490{
2491 if (isInTopLayer() == inTopLayer)
2492 return;
2493 ensureElementRareData()->setIsInTopLayer(inTopLayer);
2494
2495 // We must ensure a reattach occurs so the renderer is inserted in the correct sibling order under RenderView according to its
2496 // top layer position, or in its usual place if not in the top layer.
2497 reattachIfAttached();
2498}
2499
2500void Element::webkitRequestPointerLock()
2501{
2502 if (document()->page())
2503 document()->page()->pointerLockController()->requestPointerLock(this);
2504}
2505
2506SpellcheckAttributeState Element::spellcheckAttributeState() const
2507{
2508 const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
2509 if (value == nullAtom)
2510 return SpellcheckAttributeDefault;
2511 if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
2512 return SpellcheckAttributeTrue;
2513 if (equalIgnoringCase(value, "false"))
2514 return SpellcheckAttributeFalse;
2515
2516 return SpellcheckAttributeDefault;
2517}
2518
2519bool Element::isSpellCheckingEnabled() const
2520{
2521 for (const Element* element = this; element; element = element->parentOrShadowHostElement()) {
2522 switch (element->spellcheckAttributeState()) {
2523 case SpellcheckAttributeTrue:
2524 return true;
2525 case SpellcheckAttributeFalse:
2526 return false;
2527 case SpellcheckAttributeDefault:
2528 break;
2529 }
2530 }
2531
2532 return true;
2533}
2534
2535RenderRegion* Element::renderRegion() const
2536{
2537 if (renderer() && renderer()->isRenderRegion())
2538 return toRenderRegion(renderer());
2539
2540 return 0;
2541}
2542
2543const AtomicString& Element::webkitRegionOverset() const
2544{
2545 document()->updateLayoutIgnorePendingStylesheets();
2546
2547 DEFINE_STATIC_LOCAL(AtomicString, undefinedState, ("undefined", AtomicString::ConstructFromLiteral));
2548 if (!RuntimeEnabledFeatures::cssRegionsEnabled() || !renderRegion())
2549 return undefinedState;
2550
2551 switch (renderRegion()->regionState()) {
2552 case RenderRegion::RegionFit: {
2553 DEFINE_STATIC_LOCAL(AtomicString, fitState, ("fit", AtomicString::ConstructFromLiteral));
2554 return fitState;
2555 }
2556 case RenderRegion::RegionEmpty: {
2557 DEFINE_STATIC_LOCAL(AtomicString, emptyState, ("empty", AtomicString::ConstructFromLiteral));
2558 return emptyState;
2559 }
2560 case RenderRegion::RegionOverset: {
2561 DEFINE_STATIC_LOCAL(AtomicString, overflowState, ("overset", AtomicString::ConstructFromLiteral));
2562 return overflowState;
2563 }
2564 case RenderRegion::RegionUndefined:
2565 return undefinedState;
2566 }
2567
2568 ASSERT_NOT_REACHED();
2569 return undefinedState;
2570}
2571
2572Vector<RefPtr<Range> > Element::webkitGetRegionFlowRanges() const
2573{
2574 document()->updateLayoutIgnorePendingStylesheets();
2575
2576 Vector<RefPtr<Range> > rangeObjects;
2577 if (RuntimeEnabledFeatures::cssRegionsEnabled() && renderer() && renderer()->isRenderRegion()) {
2578 RenderRegion* region = toRenderRegion(renderer());
2579 if (region->isValid())
2580 region->getRanges(rangeObjects);
2581 }
2582
2583 return rangeObjects;
2584}
2585
2586#ifndef NDEBUG
2587bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
2588{
2589 if (name == HTMLNames::styleAttr)
2590 return false;
2591
2592#if ENABLE(SVG)
2593 if (isSVGElement())
2594 return !static_cast<const SVGElement*>(this)->isAnimatableAttribute(name);
2595#endif
2596
2597 return true;
2598}
2599#endif
2600
2601#ifdef DUMP_NODE_STATISTICS
2602bool Element::hasNamedNodeMap() const
2603{
2604 return hasRareData() && elementRareData()->attributeMap();
2605}
2606#endif
2607
2608inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName)
2609{
2610 if (!inDocument() || isInShadowTree())
2611 return;
2612
2613 if (oldName == newName)
2614 return;
2615
2616 if (shouldRegisterAsNamedItem())
2617 updateNamedItemRegistration(oldName, newName);
2618}
2619
2620inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
2621{
2622 if (!isInTreeScope())
2623 return;
2624
2625 if (oldId == newId)
2626 return;
2627
2628 updateId(treeScope(), oldId, newId);
2629}
2630
2631inline void Element::updateId(TreeScope* scope, const AtomicString& oldId, const AtomicString& newId)
2632{
2633 ASSERT(isInTreeScope());
2634 ASSERT(oldId != newId);
2635
2636 if (!oldId.isEmpty())
2637 scope->removeElementById(oldId, this);
2638 if (!newId.isEmpty())
2639 scope->addElementById(newId, this);
2640
2641 if (shouldRegisterAsExtraNamedItem())
2642 updateExtraNamedItemRegistration(oldId, newId);
2643}
2644
2645void Element::updateLabel(TreeScope* scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
2646{
2647 ASSERT(hasTagName(labelTag));
2648
2649 if (!inDocument())
2650 return;
2651
2652 if (oldForAttributeValue == newForAttributeValue)
2653 return;
2654
2655 if (!oldForAttributeValue.isEmpty())
2656 scope->removeLabel(oldForAttributeValue, static_cast<HTMLLabelElement*>(this));
2657 if (!newForAttributeValue.isEmpty())
2658 scope->addLabel(newForAttributeValue, static_cast<HTMLLabelElement*>(this));
2659}
2660
2661void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
2662{
2663 if (isIdAttributeName(name))
2664 updateId(oldValue, newValue);
2665 else if (name == HTMLNames::nameAttr)
2666 updateName(oldValue, newValue);
2667 else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
2668 TreeScope* scope = treeScope();
2669 if (scope->shouldCacheLabelsByForAttribute())
2670 updateLabel(scope, oldValue, newValue);
2671 }
2672
2673 if (oldValue != newValue) {
2674 if (attached() && document()->styleResolver() && document()->styleResolver()->hasSelectorForAttribute(name.localName()))
2675 setNeedsStyleRecalc();
2676 }
2677
2678 if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(this, name))
2679 recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue));
2680
2681 InspectorInstrumentation::willModifyDOMAttr(document(), this, oldValue, newValue);
2682}
2683
2684void Element::didAddAttribute(const QualifiedName& name, const AtomicString& value)
2685{
2686 attributeChanged(name, value);
2687 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value);
2688 dispatchSubtreeModifiedEvent();
2689}
2690
2691void Element::didModifyAttribute(const QualifiedName& name, const AtomicString& value)
2692{
2693 attributeChanged(name, value);
2694 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value);
2695 // Do not dispatch a DOMSubtreeModified event here; see bug 81141.
2696}
2697
2698void Element::didRemoveAttribute(const QualifiedName& name)
2699{
2700 attributeChanged(name, nullAtom);
2701 InspectorInstrumentation::didRemoveDOMAttr(document(), this, name.localName());
2702 dispatchSubtreeModifiedEvent();
2703}
2704
2705
2706void Element::updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName)
2707{
2708 if (!document()->isHTMLDocument())
2709 return;
2710
2711 if (!oldName.isEmpty())
2712 toHTMLDocument(document())->removeNamedItem(oldName);
2713
2714 if (!newName.isEmpty())
2715 toHTMLDocument(document())->addNamedItem(newName);
2716}
2717
2718void Element::updateExtraNamedItemRegistration(const AtomicString& oldId, const AtomicString& newId)
2719{
2720 if (!document()->isHTMLDocument())
2721 return;
2722
2723 if (!oldId.isEmpty())
2724 toHTMLDocument(document())->removeExtraNamedItem(oldId);
2725
2726 if (!newId.isEmpty())
2727 toHTMLDocument(document())->addExtraNamedItem(newId);
2728}
2729
2730PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
2731{
2732 if (HTMLCollection* collection = cachedHTMLCollection(type))
2733 return collection;
2734
2735 RefPtr<HTMLCollection> collection;
2736 if (type == TableRows) {
2737 ASSERT(hasTagName(tableTag));
2738 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
2739 } else if (type == SelectOptions) {
2740 ASSERT(hasTagName(selectTag));
2741 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
2742 } else if (type == FormControls) {
2743 ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
2744 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
2745 }
2746 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLCollection>(this, type);
2747}
2748
2749HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
2750{
2751 return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0;
2752}
2753
2754IntSize Element::savedLayerScrollOffset() const
2755{
2756 return hasRareData() ? elementRareData()->savedLayerScrollOffset() : IntSize();
2757}
2758
2759void Element::setSavedLayerScrollOffset(const IntSize& size)
2760{
2761 if (size.isZero() && !hasRareData())
2762 return;
2763 ensureElementRareData()->setSavedLayerScrollOffset(size);
2764}
2765
2766PassRefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
2767{
2768 if (AttrNodeList* attrNodeList = attrNodeListForElement(this))
2769 return findAttrNodeInList(attrNodeList, name);
2770 return 0;
2771}
2772
2773PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name)
2774{
2775 AttrNodeList* attrNodeList = ensureAttrNodeListForElement(this);
2776 RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
2777 if (!attrNode) {
2778 attrNode = Attr::create(this, name);
2779 treeScope()->adoptIfNeeded(attrNode.get());
2780 attrNodeList->append(attrNode);
2781 }
2782 return attrNode.release();
2783}
2784
2785void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value)
2786{
2787 ASSERT(hasSyntheticAttrChildNodes());
2788 attrNode->detachFromElementWithValue(value);
2789
2790 AttrNodeList* attrNodeList = attrNodeListForElement(this);
2791 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
2792 if (attrNodeList->at(i)->qualifiedName() == attrNode->qualifiedName()) {
2793 attrNodeList->remove(i);
2794 if (attrNodeList->isEmpty())
2795 removeAttrNodeListForElement(this);
2796 return;
2797 }
2798 }
2799 ASSERT_NOT_REACHED();
2800}
2801
2802void Element::detachAllAttrNodesFromElement()
2803{
2804 AttrNodeList* attrNodeList = attrNodeListForElement(this);
2805 ASSERT(attrNodeList);
2806
2807 for (unsigned i = 0; i < attributeCount(); ++i) {
2808 const Attribute* attribute = attributeItem(i);
2809 if (RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, attribute->name()))
2810 attrNode->detachFromElementWithValue(attribute->value());
2811 }
2812
2813 removeAttrNodeListForElement(this);
2814}
2815
2816void Element::willRecalcStyle(StyleChange)
2817{
2818 ASSERT(hasCustomStyleCallbacks());
2819}
2820
2821void Element::didRecalcStyle(StyleChange)
2822{
2823 ASSERT(hasCustomStyleCallbacks());
2824}
2825
2826
2827PassRefPtr<RenderStyle> Element::customStyleForRenderer()
2828{
2829 ASSERT(hasCustomStyleCallbacks());
2830 return 0;
2831}
2832
2833void Element::cloneAttributesFromElement(const Element& other)
2834{
2835 if (hasSyntheticAttrChildNodes())
2836 detachAllAttrNodesFromElement();
2837
2838 other.synchronizeAllAttributes();
2839 if (!other.m_elementData) {
2840 m_elementData.clear();
2841 return;
2842 }
2843
2844 const AtomicString& oldID = getIdAttribute();
2845 const AtomicString& newID = other.getIdAttribute();
2846
2847 if (!oldID.isNull() || !newID.isNull())
2848 updateId(oldID, newID);
2849
2850 const AtomicString& oldName = getNameAttribute();
2851 const AtomicString& newName = other.getNameAttribute();
2852
2853 if (!oldName.isNull() || !newName.isNull())
2854 updateName(oldName, newName);
2855
2856 // If 'other' has a mutable ElementData, convert it to an immutable one so we can share it between both elements.
2857 // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes.
2858 if (other.m_elementData->isUnique()
2859 && !other.m_elementData->presentationAttributeStyle()
2860 && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper()))
2861 const_cast<Element&>(other).m_elementData = static_cast<const UniqueElementData*>(other.m_elementData.get())->makeShareableCopy();
2862
2863 if (!other.m_elementData->isUnique())
2864 m_elementData = other.m_elementData;
2865 else
2866 m_elementData = other.m_elementData->makeUniqueCopy();
2867
2868 for (unsigned i = 0; i < m_elementData->length(); ++i) {
2869 const Attribute* attribute = const_cast<const ElementData*>(m_elementData.get())->attributeItem(i);
2870 attributeChangedFromParserOrByCloning(attribute->name(), attribute->value(), ModifiedByCloning);
2871 }
2872}
2873
2874void Element::cloneDataFromElement(const Element& other)
2875{
2876 cloneAttributesFromElement(other);
2877 copyNonAttributePropertiesFromElement(other);
2878}
2879
2880void Element::createUniqueElementData()
2881{
2882 if (!m_elementData)
2883 m_elementData = UniqueElementData::create();
2884 else {
2885 ASSERT(!m_elementData->isUnique());
2886 m_elementData = static_cast<ShareableElementData*>(m_elementData.get())->makeUniqueCopy();
2887 }
2888}
2889
2890void Element::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
2891{
2892 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
2893 ContainerNode::reportMemoryUsage(memoryObjectInfo);
2894 info.addMember(m_tagName, "tagName");
2895 info.addMember(m_elementData, "elementData");
2896}
2897
Torne (Richard Coles)81a51572013-05-13 16:52:28 +01002898InputMethodContext* Element::getInputContext()
2899{
2900 return ensureElementRareData()->ensureInputMethodContext(toHTMLElement(this));
2901}
2902
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002903#if ENABLE(SVG)
2904bool Element::hasPendingResources() const
2905{
2906 return hasRareData() && elementRareData()->hasPendingResources();
2907}
2908
2909void Element::setHasPendingResources()
2910{
2911 ensureElementRareData()->setHasPendingResources(true);
2912}
2913
2914void Element::clearHasPendingResources()
2915{
2916 ensureElementRareData()->setHasPendingResources(false);
2917}
2918#endif
2919
2920void ElementData::deref()
2921{
2922 if (!derefBase())
2923 return;
2924
2925 if (m_isUnique)
2926 delete static_cast<UniqueElementData*>(this);
2927 else
2928 delete static_cast<ShareableElementData*>(this);
2929}
2930
2931ElementData::ElementData()
2932 : m_isUnique(true)
2933 , m_arraySize(0)
2934 , m_presentationAttributeStyleIsDirty(false)
2935 , m_styleAttributeIsDirty(false)
2936#if ENABLE(SVG)
2937 , m_animatedSVGAttributesAreDirty(false)
2938#endif
2939{
2940}
2941
2942ElementData::ElementData(unsigned arraySize)
2943 : m_isUnique(false)
2944 , m_arraySize(arraySize)
2945 , m_presentationAttributeStyleIsDirty(false)
2946 , m_styleAttributeIsDirty(false)
2947#if ENABLE(SVG)
2948 , m_animatedSVGAttributesAreDirty(false)
2949#endif
2950{
2951}
2952
2953struct SameSizeAsElementData : public RefCounted<SameSizeAsElementData> {
2954 unsigned bitfield;
2955 void* refPtrs[3];
2956};
2957
2958COMPILE_ASSERT(sizeof(ElementData) == sizeof(SameSizeAsElementData), element_attribute_data_should_stay_small);
2959
2960static size_t sizeForShareableElementDataWithAttributeCount(unsigned count)
2961{
2962 return sizeof(ShareableElementData) + sizeof(Attribute) * count;
2963}
2964
2965PassRefPtr<ShareableElementData> ShareableElementData::createWithAttributes(const Vector<Attribute>& attributes)
2966{
2967 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(attributes.size()));
2968 return adoptRef(new (slot) ShareableElementData(attributes));
2969}
2970
2971PassRefPtr<UniqueElementData> UniqueElementData::create()
2972{
2973 return adoptRef(new UniqueElementData);
2974}
2975
2976ShareableElementData::ShareableElementData(const Vector<Attribute>& attributes)
2977 : ElementData(attributes.size())
2978{
2979 for (unsigned i = 0; i < m_arraySize; ++i)
2980 new (&m_attributeArray[i]) Attribute(attributes[i]);
2981}
2982
2983ShareableElementData::~ShareableElementData()
2984{
2985 for (unsigned i = 0; i < m_arraySize; ++i)
2986 m_attributeArray[i].~Attribute();
2987}
2988
2989ShareableElementData::ShareableElementData(const UniqueElementData& other)
2990 : ElementData(other, false)
2991{
2992 ASSERT(!other.m_presentationAttributeStyle);
2993
2994 if (other.m_inlineStyle) {
2995 ASSERT(!other.m_inlineStyle->hasCSSOMWrapper());
2996 m_inlineStyle = other.m_inlineStyle->immutableCopyIfNeeded();
2997 }
2998
2999 for (unsigned i = 0; i < m_arraySize; ++i)
3000 new (&m_attributeArray[i]) Attribute(other.m_attributeVector.at(i));
3001}
3002
3003ElementData::ElementData(const ElementData& other, bool isUnique)
3004 : m_isUnique(isUnique)
3005 , m_arraySize(isUnique ? 0 : other.length())
3006 , m_presentationAttributeStyleIsDirty(other.m_presentationAttributeStyleIsDirty)
3007 , m_styleAttributeIsDirty(other.m_styleAttributeIsDirty)
3008#if ENABLE(SVG)
3009 , m_animatedSVGAttributesAreDirty(other.m_animatedSVGAttributesAreDirty)
3010#endif
3011 , m_classNames(other.m_classNames)
3012 , m_idForStyleResolution(other.m_idForStyleResolution)
3013{
3014 // NOTE: The inline style is copied by the subclass copy constructor since we don't know what to do with it here.
3015}
3016
3017UniqueElementData::UniqueElementData()
3018{
3019}
3020
3021UniqueElementData::UniqueElementData(const UniqueElementData& other)
3022 : ElementData(other, true)
3023 , m_presentationAttributeStyle(other.m_presentationAttributeStyle)
3024 , m_attributeVector(other.m_attributeVector)
3025{
3026 m_inlineStyle = other.m_inlineStyle ? other.m_inlineStyle->copy() : 0;
3027}
3028
3029UniqueElementData::UniqueElementData(const ShareableElementData& other)
3030 : ElementData(other, true)
3031{
3032 // An ShareableElementData should never have a mutable inline StylePropertySet attached.
3033 ASSERT(!other.m_inlineStyle || !other.m_inlineStyle->isMutable());
3034 m_inlineStyle = other.m_inlineStyle;
3035
3036 m_attributeVector.reserveCapacity(other.length());
3037 for (unsigned i = 0; i < other.length(); ++i)
3038 m_attributeVector.uncheckedAppend(other.m_attributeArray[i]);
3039}
3040
3041PassRefPtr<UniqueElementData> ElementData::makeUniqueCopy() const
3042{
3043 if (isUnique())
3044 return adoptRef(new UniqueElementData(static_cast<const UniqueElementData&>(*this)));
3045 return adoptRef(new UniqueElementData(static_cast<const ShareableElementData&>(*this)));
3046}
3047
3048PassRefPtr<ShareableElementData> UniqueElementData::makeShareableCopy() const
3049{
3050 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(m_attributeVector.size()));
3051 return adoptRef(new (slot) ShareableElementData(*this));
3052}
3053
3054void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value)
3055{
3056 m_attributeVector.append(Attribute(attributeName, value));
3057}
3058
3059void UniqueElementData::removeAttribute(size_t index)
3060{
3061 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
3062 m_attributeVector.remove(index);
3063}
3064
3065bool ElementData::isEquivalent(const ElementData* other) const
3066{
3067 if (!other)
3068 return isEmpty();
3069
3070 unsigned len = length();
3071 if (len != other->length())
3072 return false;
3073
3074 for (unsigned i = 0; i < len; i++) {
3075 const Attribute* attribute = attributeItem(i);
3076 const Attribute* otherAttr = other->getAttributeItem(attribute->name());
3077 if (!otherAttr || attribute->value() != otherAttr->value())
3078 return false;
3079 }
3080
3081 return true;
3082}
3083
3084void ElementData::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
3085{
3086 size_t actualSize = m_isUnique ? sizeof(ElementData) : sizeForShareableElementDataWithAttributeCount(m_arraySize);
3087 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM, actualSize);
3088 info.addMember(m_inlineStyle, "inlineStyle");
3089 info.addMember(m_classNames, "classNames");
3090 info.addMember(m_idForStyleResolution, "idForStyleResolution");
3091 if (m_isUnique) {
3092 const UniqueElementData* uniqueThis = static_cast<const UniqueElementData*>(this);
3093 info.addMember(uniqueThis->m_presentationAttributeStyle, "presentationAttributeStyle");
3094 info.addMember(uniqueThis->m_attributeVector, "attributeVector");
3095 }
3096 for (unsigned i = 0, len = length(); i < len; i++)
3097 info.addMember(*attributeItem(i), "*attributeItem");
3098}
3099
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01003100size_t ElementData::getAttrIndex(Attr* attr) const
3101{
3102 // This relies on the fact that Attr's QualifiedName == the Attribute's name.
3103 for (unsigned i = 0; i < length(); ++i) {
3104 if (attributeItem(i)->name() == attr->qualifiedName())
3105 return i;
3106 }
3107 return notFound;
3108}
3109
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003110size_t ElementData::getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const
3111{
3112 // Continue to checking case-insensitively and/or full namespaced names if necessary:
3113 for (unsigned i = 0; i < length(); ++i) {
3114 const Attribute* attribute = attributeItem(i);
3115 if (!attribute->name().hasPrefix()) {
3116 if (shouldIgnoreAttributeCase && equalIgnoringCase(name, attribute->localName()))
3117 return i;
3118 } else {
3119 // FIXME: Would be faster to do this comparison without calling toString, which
3120 // generates a temporary string by concatenation. But this branch is only reached
3121 // if the attribute name has a prefix, which is rare in HTML.
3122 if (equalPossiblyIgnoringCase(name, attribute->name().toString(), shouldIgnoreAttributeCase))
3123 return i;
3124 }
3125 }
3126 return notFound;
3127}
3128
3129Attribute* UniqueElementData::getAttributeItem(const QualifiedName& name)
3130{
3131 for (unsigned i = 0; i < length(); ++i) {
3132 if (m_attributeVector.at(i).name().matches(name))
3133 return &m_attributeVector.at(i);
3134 }
3135 return 0;
3136}
3137
3138Attribute* UniqueElementData::attributeItem(unsigned index)
3139{
3140 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
3141 return &m_attributeVector.at(index);
3142}
3143
3144} // namespace WebCore