blob: 41c734aa68083ac7e8da55ccc916ff6d1dcdfd13 [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
Ben Murdoch591b9582013-07-10 11:41:44 +010029#include "CSSPropertyNames.h"
30#include "CSSValueKeywords.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010031#include "HTMLNames.h"
Ben Murdoch7757ec22013-07-23 11:17:36 +010032#include "RuntimeEnabledFeatures.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010033#include "SVGNames.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010034#include "XMLNames.h"
Ben Murdochdf957042013-08-06 11:01:27 +010035#include "bindings/v8/ExceptionState.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010036#include "core/accessibility/AXObjectCache.h"
Ben Murdoch83750172013-07-24 10:36:59 +010037#include "core/animation/DocumentTimeline.h"
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +010038#include "core/animation/css/CSSAnimations.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010039#include "core/css/CSSParser.h"
40#include "core/css/CSSStyleSheet.h"
41#include "core/css/CSSValuePool.h"
42#include "core/css/PropertySetCSSStyleDeclaration.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010043#include "core/css/StylePropertySet.h"
Torne (Richard Coles)81a51572013-05-13 16:52:28 +010044#include "core/css/resolver/StyleResolver.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010045#include "core/dom/Attr.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010046#include "core/dom/Attribute.h"
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010047#include "core/dom/CSSSelectorWatch.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010048#include "core/dom/ClientRect.h"
49#include "core/dom/ClientRectList.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010050#include "core/dom/DatasetDOMStringMap.h"
51#include "core/dom/Document.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010052#include "core/dom/DocumentSharedObjectPool.h"
53#include "core/dom/ElementRareData.h"
54#include "core/dom/ExceptionCode.h"
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +010055#include "core/dom/FullscreenElementStack.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010056#include "core/dom/MutationObserverInterestGroup.h"
57#include "core/dom/MutationRecord.h"
58#include "core/dom/NamedNodeMap.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010059#include "core/dom/NodeRenderStyle.h"
60#include "core/dom/NodeRenderingContext.h"
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +010061#include "core/dom/PostAttachCallbacks.h"
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +010062#include "core/dom/PresentationAttributeStyle.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010063#include "core/dom/PseudoElement.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010064#include "core/dom/ScriptableDocumentParser.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010065#include "core/dom/SelectorQuery.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010066#include "core/dom/Text.h"
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010067#include "core/dom/WhitespaceChildList.h"
68#include "core/dom/custom/CustomElement.h"
69#include "core/dom/custom/CustomElementRegistrationContext.h"
Torne (Richard Coles)e5249552013-05-15 11:35:13 +010070#include "core/dom/shadow/InsertionPoint.h"
71#include "core/dom/shadow/ShadowRoot.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010072#include "core/editing/FrameSelection.h"
73#include "core/editing/TextIterator.h"
74#include "core/editing/htmlediting.h"
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010075#include "core/events/EventDispatcher.h"
76#include "core/events/FocusEvent.h"
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +010077#include "core/frame/ContentSecurityPolicy.h"
78#include "core/frame/Frame.h"
79#include "core/frame/FrameView.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010080#include "core/html/ClassList.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010081#include "core/html/HTMLCollection.h"
82#include "core/html/HTMLDocument.h"
83#include "core/html/HTMLElement.h"
84#include "core/html/HTMLFormControlsCollection.h"
85#include "core/html/HTMLFrameOwnerElement.h"
86#include "core/html/HTMLLabelElement.h"
87#include "core/html/HTMLOptionsCollection.h"
88#include "core/html/HTMLTableRowsCollection.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010089#include "core/html/parser/HTMLParserIdioms.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010090#include "core/page/FocusController.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010091#include "core/page/Page.h"
92#include "core/page/PointerLockController.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010093#include "core/rendering/FlowThreadController.h"
94#include "core/rendering/RenderRegion.h"
95#include "core/rendering/RenderView.h"
96#include "core/rendering/RenderWidget.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010097#include "core/svg/SVGDocumentExtensions.h"
98#include "core/svg/SVGElement.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010099#include "wtf/BitVector.h"
Ben Murdoch591b9582013-07-10 11:41:44 +0100100#include "wtf/HashFunctions.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100101#include "wtf/text/CString.h"
Ben Murdoch591b9582013-07-10 11:41:44 +0100102#include "wtf/text/TextPosition.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100103
104namespace WebCore {
105
106using namespace HTMLNames;
107using namespace XMLNames;
108
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100109class StyleResolverParentPusher {
110public:
111 StyleResolverParentPusher(Element* parent)
112 : m_parent(parent)
113 , m_pushedStyleResolver(0)
114 {
115 }
116 void push()
117 {
118 if (m_pushedStyleResolver)
119 return;
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100120 m_pushedStyleResolver = m_parent->document().styleResolver();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100121 m_pushedStyleResolver->pushParentElement(m_parent);
122 }
123 ~StyleResolverParentPusher()
124 {
125
126 if (!m_pushedStyleResolver)
127 return;
128
129 // This tells us that our pushed style selector is in a bad state,
130 // so we should just bail out in that scenario.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100131 ASSERT(m_pushedStyleResolver == m_parent->document().styleResolver());
132 if (m_pushedStyleResolver != m_parent->document().styleResolver())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100133 return;
134
135 m_pushedStyleResolver->popParentElement(m_parent);
136 }
137
138private:
139 Element* m_parent;
140 StyleResolver* m_pushedStyleResolver;
141};
142
143typedef Vector<RefPtr<Attr> > AttrNodeList;
144typedef HashMap<Element*, OwnPtr<AttrNodeList> > AttrNodeListMap;
145
146static AttrNodeListMap& attrNodeListMap()
147{
148 DEFINE_STATIC_LOCAL(AttrNodeListMap, map, ());
149 return map;
150}
151
152static AttrNodeList* attrNodeListForElement(Element* element)
153{
154 if (!element->hasSyntheticAttrChildNodes())
155 return 0;
156 ASSERT(attrNodeListMap().contains(element));
157 return attrNodeListMap().get(element);
158}
159
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100160static AttrNodeList& ensureAttrNodeListForElement(Element* element)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100161{
162 if (element->hasSyntheticAttrChildNodes()) {
163 ASSERT(attrNodeListMap().contains(element));
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100164 return *attrNodeListMap().get(element);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100165 }
166 ASSERT(!attrNodeListMap().contains(element));
167 element->setHasSyntheticAttrChildNodes(true);
168 AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList));
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100169 return *result.iterator->value;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100170}
171
172static void removeAttrNodeListForElement(Element* element)
173{
174 ASSERT(element->hasSyntheticAttrChildNodes());
175 ASSERT(attrNodeListMap().contains(element));
176 attrNodeListMap().remove(element);
177 element->setHasSyntheticAttrChildNodes(false);
178}
179
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100180static Attr* findAttrNodeInList(AttrNodeList& attrNodeList, const QualifiedName& name)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100181{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100182 for (unsigned i = 0; i < attrNodeList.size(); ++i) {
183 if (attrNodeList[i]->qualifiedName() == name)
184 return attrNodeList[i].get();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100185 }
186 return 0;
187}
188
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100189PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document)
190{
191 return adoptRef(new Element(tagName, document, CreateElement));
192}
193
194Element::~Element()
195{
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000196 // When the document is not destroyed, an element that was part of a named flow
197 // content nodes should have been removed from the content nodes collection
198 // and the inNamedFlow flag reset.
199 ASSERT(!document().renderView() || !inNamedFlow());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100200
Ben Murdoch591b9582013-07-10 11:41:44 +0100201 if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
202 cssomWrapper->clearParentElement();
203
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100204 if (hasRareData()) {
205 ElementRareData* data = elementRareData();
206 data->setPseudoElement(BEFORE, 0);
207 data->setPseudoElement(AFTER, 0);
Ben Murdoche69819b2013-07-17 14:56:49 +0100208 data->setPseudoElement(BACKDROP, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100209 data->clearShadow();
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100210
211 if (RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
212 if (ActiveAnimations* activeAnimations = data->activeAnimations())
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000213 activeAnimations->cssAnimations().cancel();
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100214 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100215 }
216
Ben Murdoch83750172013-07-24 10:36:59 +0100217 if (isCustomElement())
218 CustomElement::wasDestroyed(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100219
220 if (hasSyntheticAttrChildNodes())
221 detachAllAttrNodesFromElement();
222
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100223 if (hasPendingResources()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100224 document().accessSVGExtensions()->removeElementFromPendingResources(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100225 ASSERT(!hasPendingResources());
226 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100227}
228
229inline ElementRareData* Element::elementRareData() const
230{
231 ASSERT(hasRareData());
232 return static_cast<ElementRareData*>(rareData());
233}
234
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100235inline ElementRareData& Element::ensureElementRareData()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100236{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100237 return static_cast<ElementRareData&>(ensureRareData());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100238}
239
240void Element::clearTabIndexExplicitlyIfNeeded()
241{
242 if (hasRareData())
243 elementRareData()->clearTabIndexExplicitly();
244}
245
246void Element::setTabIndexExplicitly(short tabIndex)
247{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100248 ensureElementRareData().setTabIndexExplicitly(tabIndex);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100249}
250
251bool Element::supportsFocus() const
252{
253 return hasRareData() && elementRareData()->tabIndexSetExplicitly();
254}
255
256short Element::tabIndex() const
257{
258 return hasRareData() ? elementRareData()->tabIndex() : 0;
259}
260
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100261bool Element::rendererIsFocusable() const
262{
263 // Elements in canvas fallback content are not rendered, but they are allowed to be
264 // focusable as long as their canvas is displayed and visible.
265 if (isInCanvasSubtree()) {
266 const Element* e = this;
267 while (e && !e->hasLocalName(canvasTag))
268 e = e->parentElement();
269 ASSERT(e);
270 return e->renderer() && e->renderer()->style()->visibility() == VISIBLE;
271 }
272
273 // FIXME: These asserts should be in Node::isFocusable, but there are some
Ben Murdoche69819b2013-07-17 14:56:49 +0100274 // callsites like Document::setFocusedElement that would currently fail on
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100275 // them. See crbug.com/251163
276 if (renderer()) {
277 ASSERT(!renderer()->needsLayout());
278 } else {
279 // We can't just use needsStyleRecalc() because if the node is in a
280 // display:none tree it might say it needs style recalc but the whole
281 // document is actually up to date.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100282 ASSERT(!document().childNeedsStyleRecalc());
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100283 }
284
285 // FIXME: Even if we are not visible, we might have a child that is visible.
286 // Hyatt wants to fix that some day with a "has visible content" flag or the like.
287 if (!renderer() || renderer()->style()->visibility() != VISIBLE)
288 return false;
289
290 return true;
291}
292
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100293PassRefPtr<Node> Element::cloneNode(bool deep)
294{
295 return deep ? cloneElementWithChildren() : cloneElementWithoutChildren();
296}
297
298PassRefPtr<Element> Element::cloneElementWithChildren()
299{
300 RefPtr<Element> clone = cloneElementWithoutChildren();
301 cloneChildNodes(clone.get());
302 return clone.release();
303}
304
305PassRefPtr<Element> Element::cloneElementWithoutChildren()
306{
307 RefPtr<Element> clone = cloneElementWithoutAttributesAndChildren();
308 // This will catch HTML elements in the wrong namespace that are not correctly copied.
309 // This is a sanity check as HTML overloads some of the DOM methods.
310 ASSERT(isHTMLElement() == clone->isHTMLElement());
311
312 clone->cloneDataFromElement(*this);
313 return clone.release();
314}
315
316PassRefPtr<Element> Element::cloneElementWithoutAttributesAndChildren()
317{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100318 return document().createElement(tagQName(), false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100319}
320
321PassRefPtr<Attr> Element::detachAttribute(size_t index)
322{
323 ASSERT(elementData());
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100324 const Attribute* attribute = elementData()->attributeItem(index);
325 RefPtr<Attr> attrNode = attrIfExists(attribute->name());
326 if (attrNode)
327 detachAttrNodeAtIndex(attrNode.get(), index);
328 else {
329 attrNode = Attr::create(document(), attribute->name(), attribute->value());
330 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
331 }
332 return attrNode.release();
333}
334
335void Element::detachAttrNodeAtIndex(Attr* attr, size_t index)
336{
337 ASSERT(attr);
338 ASSERT(elementData());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100339
340 const Attribute* attribute = elementData()->attributeItem(index);
341 ASSERT(attribute);
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100342 ASSERT(attribute->name() == attr->qualifiedName());
343 detachAttrNodeFromElementWithValue(attr, attribute->value());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100344 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100345}
346
347void Element::removeAttribute(const QualifiedName& name)
348{
349 if (!elementData())
350 return;
351
352 size_t index = elementData()->getAttributeItemIndex(name);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100353 if (index == kNotFound)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100354 return;
355
356 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
357}
358
359void Element::setBooleanAttribute(const QualifiedName& name, bool value)
360{
361 if (value)
362 setAttribute(name, emptyAtom);
363 else
364 removeAttribute(name);
365}
366
367NamedNodeMap* Element::attributes() const
368{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100369 ElementRareData& rareData = const_cast<Element*>(this)->ensureElementRareData();
370 if (NamedNodeMap* attributeMap = rareData.attributeMap())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100371 return attributeMap;
372
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100373 rareData.setAttributeMap(NamedNodeMap::create(const_cast<Element*>(this)));
374 return rareData.attributeMap();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100375}
376
Ben Murdoch83750172013-07-24 10:36:59 +0100377ActiveAnimations* Element::activeAnimations() const
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100378{
Ben Murdoch83750172013-07-24 10:36:59 +0100379 if (hasActiveAnimations())
380 return elementRareData()->activeAnimations();
381 return 0;
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100382}
383
Ben Murdoch83750172013-07-24 10:36:59 +0100384ActiveAnimations* Element::ensureActiveAnimations()
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100385{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100386 ElementRareData& rareData = ensureElementRareData();
387 if (!rareData.activeAnimations())
388 rareData.setActiveAnimations(adoptPtr(new ActiveAnimations()));
389 return rareData.activeAnimations();
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100390}
391
392bool Element::hasActiveAnimations() const
393{
Ben Murdoch83750172013-07-24 10:36:59 +0100394 if (!RuntimeEnabledFeatures::webAnimationsEnabled())
395 return false;
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100396
Ben Murdoch83750172013-07-24 10:36:59 +0100397 if (!hasRareData())
398 return false;
399
400 ActiveAnimations* activeAnimations = elementRareData()->activeAnimations();
401 return activeAnimations && !activeAnimations->isEmpty();
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100402}
403
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100404Node::NodeType Element::nodeType() const
405{
406 return ELEMENT_NODE;
407}
408
409bool Element::hasAttribute(const QualifiedName& name) const
410{
411 return hasAttributeNS(name.namespaceURI(), name.localName());
412}
413
414void Element::synchronizeAllAttributes() const
415{
416 if (!elementData())
417 return;
418 if (elementData()->m_styleAttributeIsDirty) {
419 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100420 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100421 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100422 if (elementData()->m_animatedSVGAttributesAreDirty) {
423 ASSERT(isSVGElement());
424 toSVGElement(this)->synchronizeAnimatedSVGAttribute(anyQName());
425 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100426}
427
428inline void Element::synchronizeAttribute(const QualifiedName& name) const
429{
430 if (!elementData())
431 return;
432 if (UNLIKELY(name == styleAttr && elementData()->m_styleAttributeIsDirty)) {
433 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100434 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100435 return;
436 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100437 if (UNLIKELY(elementData()->m_animatedSVGAttributesAreDirty)) {
438 ASSERT(isSVGElement());
439 toSVGElement(this)->synchronizeAnimatedSVGAttribute(name);
440 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100441}
442
443inline void Element::synchronizeAttribute(const AtomicString& localName) const
444{
445 // This version of synchronizeAttribute() is streamlined for the case where you don't have a full QualifiedName,
446 // e.g when called from DOM API.
447 if (!elementData())
448 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100449 if (elementData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(localName, styleAttr.localName(), shouldIgnoreAttributeCase())) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100450 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100451 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100452 return;
453 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100454 if (elementData()->m_animatedSVGAttributesAreDirty) {
455 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
456 ASSERT(isSVGElement());
457 static_cast<const SVGElement*>(this)->synchronizeAnimatedSVGAttribute(QualifiedName(nullAtom, localName, nullAtom));
458 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100459}
460
461const AtomicString& Element::getAttribute(const QualifiedName& name) const
462{
463 if (!elementData())
464 return nullAtom;
465 synchronizeAttribute(name);
466 if (const Attribute* attribute = getAttributeItem(name))
467 return attribute->value();
468 return nullAtom;
469}
470
Ben Murdoch591b9582013-07-10 11:41:44 +0100471void Element::scrollIntoView(bool alignToTop)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100472{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100473 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100474
475 if (!renderer())
476 return;
477
478 LayoutRect bounds = boundingBox();
479 // Align to the top / bottom and to the closest edge.
480 if (alignToTop)
481 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
482 else
483 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
484}
485
486void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
487{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100488 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100489
490 if (!renderer())
491 return;
492
493 LayoutRect bounds = boundingBox();
494 if (centerIfNeeded)
495 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
496 else
497 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
498}
499
500void Element::scrollByUnits(int units, ScrollGranularity granularity)
501{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100502 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100503
504 if (!renderer())
505 return;
506
507 if (!renderer()->hasOverflowClip())
508 return;
509
510 ScrollDirection direction = ScrollDown;
511 if (units < 0) {
512 direction = ScrollUp;
513 units = -units;
514 }
515 Node* stopNode = this;
516 toRenderBox(renderer())->scroll(direction, granularity, units, &stopNode);
517}
518
519void Element::scrollByLines(int lines)
520{
521 scrollByUnits(lines, ScrollByLine);
522}
523
524void Element::scrollByPages(int pages)
525{
526 scrollByUnits(pages, ScrollByPage);
527}
528
529static float localZoomForRenderer(RenderObject* renderer)
530{
531 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
532 // other out, but the alternative is that we'd have to crawl up the whole render tree every
533 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
534 float zoomFactor = 1;
535 if (renderer->style()->effectiveZoom() != 1) {
536 // Need to find the nearest enclosing RenderObject that set up
537 // a differing zoom, and then we divide our result by it to eliminate the zoom.
538 RenderObject* prev = renderer;
539 for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) {
540 if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) {
541 zoomFactor = prev->style()->zoom();
542 break;
543 }
544 prev = curr;
545 }
546 if (prev->isRenderView())
547 zoomFactor = prev->style()->zoom();
548 }
549 return zoomFactor;
550}
551
552static int adjustForLocalZoom(LayoutUnit value, RenderObject* renderer)
553{
554 float zoomFactor = localZoomForRenderer(renderer);
555 if (zoomFactor == 1)
556 return value;
557 return lroundf(value / zoomFactor);
558}
559
560int Element::offsetLeft()
561{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100562 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100563 if (RenderBoxModelObject* renderer = renderBoxModelObject())
564 return adjustForLocalZoom(renderer->pixelSnappedOffsetLeft(), renderer);
565 return 0;
566}
567
568int Element::offsetTop()
569{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100570 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100571 if (RenderBoxModelObject* renderer = renderBoxModelObject())
572 return adjustForLocalZoom(renderer->pixelSnappedOffsetTop(), renderer);
573 return 0;
574}
575
576int Element::offsetWidth()
577{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100578 document().updateStyleForNodeIfNeeded(this);
Ben Murdoch591b9582013-07-10 11:41:44 +0100579
580 if (RenderBox* renderer = renderBox()) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100581 if (renderer->canDetermineWidthWithoutLayout())
Ben Murdoch591b9582013-07-10 11:41:44 +0100582 return adjustLayoutUnitForAbsoluteZoom(renderer->fixedOffsetWidth(), renderer).round();
583 }
584
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100585 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100586 if (RenderBoxModelObject* renderer = renderBoxModelObject())
587 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetWidth(), renderer).round();
588 return 0;
589}
590
591int Element::offsetHeight()
592{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100593 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100594 if (RenderBoxModelObject* renderer = renderBoxModelObject())
595 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetHeight(), renderer).round();
596 return 0;
597}
598
599Element* Element::bindingsOffsetParent()
600{
601 Element* element = offsetParent();
602 if (!element || !element->isInShadowTree())
603 return element;
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100604 return element->containingShadowRoot()->shouldExposeToBindings() ? element : 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100605}
606
607Element* Element::offsetParent()
608{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100609 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100610 if (RenderObject* renderer = this->renderer())
611 return renderer->offsetParent();
612 return 0;
613}
614
615int Element::clientLeft()
616{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100617 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100618
619 if (RenderBox* renderer = renderBox())
620 return adjustForAbsoluteZoom(roundToInt(renderer->clientLeft()), renderer);
621 return 0;
622}
623
624int Element::clientTop()
625{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100626 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100627
628 if (RenderBox* renderer = renderBox())
629 return adjustForAbsoluteZoom(roundToInt(renderer->clientTop()), renderer);
630 return 0;
631}
632
633int Element::clientWidth()
634{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100635 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100636
637 // When in strict mode, clientWidth for the document element should return the width of the containing frame.
638 // When in quirks mode, clientWidth for the body element should return the width of the containing frame.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100639 bool inQuirksMode = document().inQuirksMode();
640 if ((!inQuirksMode && document().documentElement() == this)
641 || (inQuirksMode && isHTMLElement() && document().body() == this)) {
642 if (FrameView* view = document().view()) {
643 if (RenderView* renderView = document().renderView())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100644 return adjustForAbsoluteZoom(view->layoutSize().width(), renderView);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100645 }
646 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100647
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100648 if (RenderBox* renderer = renderBox())
649 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientWidth(), renderer).round();
650 return 0;
651}
652
653int Element::clientHeight()
654{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100655 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100656
657 // When in strict mode, clientHeight for the document element should return the height of the containing frame.
658 // When in quirks mode, clientHeight for the body element should return the height of the containing frame.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100659 bool inQuirksMode = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100660
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100661 if ((!inQuirksMode && document().documentElement() == this)
662 || (inQuirksMode && isHTMLElement() && document().body() == this)) {
663 if (FrameView* view = document().view()) {
664 if (RenderView* renderView = document().renderView())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100665 return adjustForAbsoluteZoom(view->layoutSize().height(), renderView);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100666 }
667 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100668
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100669 if (RenderBox* renderer = renderBox())
670 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientHeight(), renderer).round();
671 return 0;
672}
673
674int Element::scrollLeft()
675{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100676 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100677
678 if (document().documentElement() == this) {
679 if (document().inQuirksMode())
680 return 0;
681
682 if (FrameView* view = document().view()) {
683 if (RenderView* renderView = document().renderView())
684 return adjustForAbsoluteZoom(view->scrollX(), renderView);
685 }
686 }
687
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100688 if (RenderBox* rend = renderBox())
689 return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
690 return 0;
691}
692
693int Element::scrollTop()
694{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100695 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100696
697 if (document().documentElement() == this) {
698 if (document().inQuirksMode())
699 return 0;
700
701 if (FrameView* view = document().view()) {
702 if (RenderView* renderView = document().renderView())
703 return adjustForAbsoluteZoom(view->scrollY(), renderView);
704 }
705 }
706
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100707 if (RenderBox* rend = renderBox())
708 return adjustForAbsoluteZoom(rend->scrollTop(), rend);
709 return 0;
710}
711
712void Element::setScrollLeft(int newLeft)
713{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100714 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100715
716 if (document().documentElement() == this) {
717 if (document().inQuirksMode())
718 return;
719
720 Frame* frame = document().frame();
721 if (!frame)
722 return;
723 FrameView* view = frame->view();
724 if (!view)
725 return;
726
727 // WHATWG spec says [1]: "If the element is the root element invoke scroll()
728 // with x as first argument and zero as second". Blink intentionally matches
729 // other engine's behaviors here, instead, where the 'y' scroll position is
730 // preversed. See [2].
731 // [1] http://dev.w3.org/csswg/cssom-view/#dom-element-scrollleft
732 // [2] https://www.w3.org/Bugs/Public/show_bug.cgi?id=23448
733 view->setScrollPosition(IntPoint(static_cast<int>(newLeft * frame->pageZoomFactor()), view->scrollY()));
734 }
735
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100736 if (RenderBox* rend = renderBox())
737 rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
738}
739
740void Element::setScrollTop(int newTop)
741{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100742 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100743
744 if (document().documentElement() == this) {
745 if (document().inQuirksMode())
746 return;
747
748 Frame* frame = document().frame();
749 if (!frame)
750 return;
751 FrameView* view = frame->view();
752 if (!view)
753 return;
754
755 // WHATWG spec says [1]: "If the element is the root element invoke scroll()
756 // with zero as first argument and y as second". Blink intentionally
757 // matches other engine's behaviors here, instead, where the 'x' scroll
758 // position is preversed. See [2].
759 // [1] http://dev.w3.org/csswg/cssom-view/#dom-element-scrolltop
760 // [2] https://www.w3.org/Bugs/Public/show_bug.cgi?id=23448
761 view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(newTop * frame->pageZoomFactor())));
762 }
763
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100764 if (RenderBox* rend = renderBox())
765 rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
766}
767
768int Element::scrollWidth()
769{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100770 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100771 if (RenderBox* rend = renderBox())
772 return adjustForAbsoluteZoom(rend->scrollWidth(), rend);
773 return 0;
774}
775
776int Element::scrollHeight()
777{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100778 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100779 if (RenderBox* rend = renderBox())
780 return adjustForAbsoluteZoom(rend->scrollHeight(), rend);
781 return 0;
782}
783
784IntRect Element::boundsInRootViewSpace()
785{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100786 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100787
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100788 FrameView* view = document().view();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100789 if (!view)
790 return IntRect();
791
792 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100793 if (isSVGElement() && renderer()) {
794 // Get the bounding rectangle from the SVG model.
795 SVGElement* svgElement = toSVGElement(this);
796 FloatRect localRect;
797 if (svgElement->getBoundingBox(localRect))
798 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100799 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100800 // Get the bounding rectangle from the box model.
801 if (renderBoxModelObject())
802 renderBoxModelObject()->absoluteQuads(quads);
803 }
804
805 if (quads.isEmpty())
806 return IntRect();
807
808 IntRect result = quads[0].enclosingBoundingBox();
809 for (size_t i = 1; i < quads.size(); ++i)
810 result.unite(quads[i].enclosingBoundingBox());
811
812 result = view->contentsToRootView(result);
813 return result;
814}
815
816PassRefPtr<ClientRectList> Element::getClientRects()
817{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100818 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100819
820 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject();
821 if (!renderBoxModelObject)
822 return ClientRectList::create();
823
824 // FIXME: Handle SVG elements.
825 // FIXME: Handle table/inline-table with a caption.
826
827 Vector<FloatQuad> quads;
828 renderBoxModelObject->absoluteQuads(quads);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100829 document().adjustFloatQuadsForScrollAndAbsoluteZoom(quads, renderBoxModelObject);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100830 return ClientRectList::create(quads);
831}
832
833PassRefPtr<ClientRect> Element::getBoundingClientRect()
834{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100835 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100836
837 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100838 if (isSVGElement() && renderer() && !renderer()->isSVGRoot()) {
839 // Get the bounding rectangle from the SVG model.
840 SVGElement* svgElement = toSVGElement(this);
841 FloatRect localRect;
842 if (svgElement->getBoundingBox(localRect))
843 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100844 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100845 // Get the bounding rectangle from the box model.
846 if (renderBoxModelObject())
847 renderBoxModelObject()->absoluteQuads(quads);
848 }
849
850 if (quads.isEmpty())
851 return ClientRect::create();
852
853 FloatRect result = quads[0].boundingBox();
854 for (size_t i = 1; i < quads.size(); ++i)
855 result.unite(quads[i].boundingBox());
856
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100857 document().adjustFloatRectForScrollAndAbsoluteZoom(result, renderer());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100858 return ClientRect::create(result);
859}
Ben Murdoch591b9582013-07-10 11:41:44 +0100860
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100861IntRect Element::screenRect() const
862{
863 if (!renderer())
864 return IntRect();
865 // FIXME: this should probably respect transforms
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100866 return document().view()->contentsToScreen(renderer()->absoluteBoundingBoxRectIgnoringTransforms());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100867}
868
869const AtomicString& Element::getAttribute(const AtomicString& localName) const
870{
871 if (!elementData())
872 return nullAtom;
873 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100874 if (const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100875 return attribute->value();
876 return nullAtom;
877}
878
879const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
880{
881 return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
882}
883
Ben Murdochdf957042013-08-06 11:01:27 +0100884void Element::setAttribute(const AtomicString& localName, const AtomicString& value, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100885{
886 if (!Document::isValidName(localName)) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100887 es.throwUninformativeAndGenericDOMException(InvalidCharacterError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100888 return;
889 }
890
891 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100892 const AtomicString& caseAdjustedLocalName = shouldIgnoreAttributeCase() ? localName.lower() : localName;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100893
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100894 size_t index = elementData() ? elementData()->getAttributeItemIndex(caseAdjustedLocalName, false) : kNotFound;
895 const QualifiedName& qName = index != kNotFound ? attributeItem(index)->name() : QualifiedName(nullAtom, caseAdjustedLocalName, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100896 setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute);
897}
898
899void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
900{
901 synchronizeAttribute(name);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100902 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : kNotFound;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100903 setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute);
904}
905
906void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value)
907{
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100908 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : kNotFound;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100909 setAttributeInternal(index, name, value, InSynchronizationOfLazyAttribute);
910}
911
912inline void Element::setAttributeInternal(size_t index, const QualifiedName& name, const AtomicString& newValue, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
913{
914 if (newValue.isNull()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100915 if (index != kNotFound)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100916 removeAttributeInternal(index, inSynchronizationOfLazyAttribute);
917 return;
918 }
919
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100920 if (index == kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100921 addAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute);
922 return;
923 }
924
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100925 QualifiedName existingAttributeName = attributeItem(index)->name();
926
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100927 if (!inSynchronizationOfLazyAttribute)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100928 willModifyAttribute(existingAttributeName, attributeItem(index)->value(), newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100929
930 if (newValue != attributeItem(index)->value()) {
931 // If there is an Attr node hooked to this attribute, the Attr::setValue() call below
932 // will write into the ElementData.
933 // FIXME: Refactor this so it makes some sense.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100934 if (RefPtr<Attr> attrNode = inSynchronizationOfLazyAttribute ? 0 : attrIfExists(existingAttributeName))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100935 attrNode->setValue(newValue);
936 else
937 ensureUniqueElementData()->attributeItem(index)->setValue(newValue);
938 }
939
940 if (!inSynchronizationOfLazyAttribute)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100941 didModifyAttribute(existingAttributeName, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100942}
943
944static inline AtomicString makeIdForStyleResolution(const AtomicString& value, bool inQuirksMode)
945{
946 if (inQuirksMode)
947 return value.lower();
948 return value;
949}
950
Ben Murdoch7757ec22013-07-23 11:17:36 +0100951static bool checkNeedsStyleInvalidationForIdChange(const AtomicString& oldId, const AtomicString& newId, const RuleFeatureSet& features)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100952{
953 ASSERT(newId != oldId);
Ben Murdoch7757ec22013-07-23 11:17:36 +0100954 if (!oldId.isEmpty() && features.hasSelectorForId(oldId))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100955 return true;
Ben Murdoch7757ec22013-07-23 11:17:36 +0100956 if (!newId.isEmpty() && features.hasSelectorForId(newId))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100957 return true;
958 return false;
959}
960
Ben Murdoch591b9582013-07-10 11:41:44 +0100961void Element::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100962{
963 if (ElementShadow* parentElementShadow = shadowOfParentForDistribution(this)) {
964 if (shouldInvalidateDistributionWhenAttributeChanged(parentElementShadow, name, newValue))
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100965 parentElementShadow->setNeedsDistributionRecalc();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100966 }
967
968 parseAttribute(name, newValue);
969
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100970 document().incDOMTreeVersion();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100971
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100972 StyleResolver* styleResolver = document().styleResolverIfExists();
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000973 bool testShouldInvalidateStyle = inActiveDocument() && styleResolver && styleChangeType() < SubtreeStyleChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100974 bool shouldInvalidateStyle = false;
975
Ben Murdoch591b9582013-07-10 11:41:44 +0100976 if (isStyledElement() && name == styleAttr) {
977 styleAttributeChanged(newValue, reason);
978 } else if (isStyledElement() && isPresentationAttribute(name)) {
979 elementData()->m_presentationAttributeStyleIsDirty = true;
Ben Murdoche69819b2013-07-17 14:56:49 +0100980 setNeedsStyleRecalc(LocalStyleChange);
Ben Murdoch591b9582013-07-10 11:41:44 +0100981 }
982
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100983 if (isIdAttributeName(name)) {
984 AtomicString oldId = elementData()->idForStyleResolution();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100985 AtomicString newId = makeIdForStyleResolution(newValue, document().inQuirksMode());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100986 if (newId != oldId) {
987 elementData()->setIdForStyleResolution(newId);
Ben Murdoch7757ec22013-07-23 11:17:36 +0100988 shouldInvalidateStyle = testShouldInvalidateStyle && checkNeedsStyleInvalidationForIdChange(oldId, newId, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100989 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100990 } else if (name == classAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100991 classAttributeChanged(newValue);
Ben Murdoch591b9582013-07-10 11:41:44 +0100992 } else if (name == HTMLNames::nameAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100993 setHasName(!newValue.isNull());
Ben Murdoch591b9582013-07-10 11:41:44 +0100994 } else if (name == HTMLNames::pseudoAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100995 shouldInvalidateStyle |= testShouldInvalidateStyle && isInShadowTree();
Ben Murdoch591b9582013-07-10 11:41:44 +0100996 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100997
998 invalidateNodeListCachesInAncestors(&name, this);
999
1000 // If there is currently no StyleResolver, we can't be sure that this attribute change won't affect style.
1001 shouldInvalidateStyle |= !styleResolver;
1002
1003 if (shouldInvalidateStyle)
1004 setNeedsStyleRecalc();
1005
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001006 if (AXObjectCache* cache = document().existingAXObjectCache())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001007 cache->handleAttributeChanged(name, this);
1008}
1009
1010inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
1011{
Ben Murdoche69819b2013-07-17 14:56:49 +01001012 if (name == isAttr)
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001013 CustomElementRegistrationContext::setTypeExtension(this, newValue, reason == ModifiedDirectly ? CustomElementRegistrationContext::CreatedByParser : CustomElementRegistrationContext::NotCreatedByParser);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001014 attributeChanged(name, newValue, reason);
1015}
1016
1017template <typename CharacterType>
1018static inline bool classStringHasClassName(const CharacterType* characters, unsigned length)
1019{
1020 ASSERT(length > 0);
1021
1022 unsigned i = 0;
1023 do {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001024 if (isNotHTMLSpace<CharacterType>(characters[i]))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001025 break;
1026 ++i;
1027 } while (i < length);
1028
1029 return i < length;
1030}
1031
1032static inline bool classStringHasClassName(const AtomicString& newClassString)
1033{
1034 unsigned length = newClassString.length();
1035
1036 if (!length)
1037 return false;
1038
1039 if (newClassString.is8Bit())
1040 return classStringHasClassName(newClassString.characters8(), length);
1041 return classStringHasClassName(newClassString.characters16(), length);
1042}
1043
1044template<typename Checker>
1045static bool checkSelectorForClassChange(const SpaceSplitString& changedClasses, const Checker& checker)
1046{
1047 unsigned changedSize = changedClasses.size();
1048 for (unsigned i = 0; i < changedSize; ++i) {
1049 if (checker.hasSelectorForClass(changedClasses[i]))
1050 return true;
1051 }
1052 return false;
1053}
1054
1055template<typename Checker>
1056static bool checkSelectorForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, const Checker& checker)
1057{
1058 unsigned oldSize = oldClasses.size();
1059 if (!oldSize)
1060 return checkSelectorForClassChange(newClasses, checker);
1061 BitVector remainingClassBits;
1062 remainingClassBits.ensureSize(oldSize);
1063 // Class vectors tend to be very short. This is faster than using a hash table.
1064 unsigned newSize = newClasses.size();
1065 for (unsigned i = 0; i < newSize; ++i) {
1066 for (unsigned j = 0; j < oldSize; ++j) {
1067 if (newClasses[i] == oldClasses[j]) {
1068 remainingClassBits.quickSet(j);
1069 continue;
1070 }
1071 }
1072 if (checker.hasSelectorForClass(newClasses[i]))
1073 return true;
1074 }
1075 for (unsigned i = 0; i < oldSize; ++i) {
1076 // If the bit is not set the the corresponding class has been removed.
1077 if (remainingClassBits.quickGet(i))
1078 continue;
1079 if (checker.hasSelectorForClass(oldClasses[i]))
1080 return true;
1081 }
1082 return false;
1083}
1084
1085void Element::classAttributeChanged(const AtomicString& newClassString)
1086{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001087 StyleResolver* styleResolver = document().styleResolverIfExists();
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001088 bool testShouldInvalidateStyle = inActiveDocument() && styleResolver && styleChangeType() < SubtreeStyleChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001089 bool shouldInvalidateStyle = false;
1090
1091 if (classStringHasClassName(newClassString)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001092 const bool shouldFoldCase = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001093 const SpaceSplitString oldClasses = elementData()->classNames();
1094 elementData()->setClass(newClassString, shouldFoldCase);
1095 const SpaceSplitString& newClasses = elementData()->classNames();
Ben Murdoch7757ec22013-07-23 11:17:36 +01001096 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, newClasses, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001097 } else {
1098 const SpaceSplitString& oldClasses = elementData()->classNames();
Ben Murdoch7757ec22013-07-23 11:17:36 +01001099 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001100 elementData()->clearClass();
1101 }
1102
1103 if (hasRareData())
1104 elementRareData()->clearClassListValueForQuirksMode();
1105
1106 if (shouldInvalidateStyle)
1107 setNeedsStyleRecalc();
1108}
1109
1110bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
1111{
1112 ASSERT(elementShadow);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001113 const SelectRuleFeatureSet& featureSet = elementShadow->ensureSelectFeatureSet();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001114
1115 if (isIdAttributeName(name)) {
1116 AtomicString oldId = elementData()->idForStyleResolution();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001117 AtomicString newId = makeIdForStyleResolution(newValue, document().inQuirksMode());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001118 if (newId != oldId) {
1119 if (!oldId.isEmpty() && featureSet.hasSelectorForId(oldId))
1120 return true;
1121 if (!newId.isEmpty() && featureSet.hasSelectorForId(newId))
1122 return true;
1123 }
1124 }
1125
1126 if (name == HTMLNames::classAttr) {
1127 const AtomicString& newClassString = newValue;
1128 if (classStringHasClassName(newClassString)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001129 const bool shouldFoldCase = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001130 const SpaceSplitString& oldClasses = elementData()->classNames();
1131 const SpaceSplitString newClasses(newClassString, shouldFoldCase);
1132 if (checkSelectorForClassChange(oldClasses, newClasses, featureSet))
1133 return true;
1134 } else {
1135 const SpaceSplitString& oldClasses = elementData()->classNames();
1136 if (checkSelectorForClassChange(oldClasses, featureSet))
1137 return true;
1138 }
1139 }
1140
1141 return featureSet.hasSelectorForAttribute(name.localName());
1142}
1143
1144// Returns true is the given attribute is an event handler.
1145// We consider an event handler any attribute that begins with "on".
1146// It is a simple solution that has the advantage of not requiring any
1147// code or configuration change if a new event handler is defined.
1148
1149static inline bool isEventHandlerAttribute(const Attribute& attribute)
1150{
1151 return attribute.name().namespaceURI().isNull() && attribute.name().localName().startsWith("on");
1152}
1153
1154bool Element::isJavaScriptURLAttribute(const Attribute& attribute) const
1155{
1156 return isURLAttribute(attribute) && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(attribute.value()));
1157}
1158
1159void Element::stripScriptingAttributes(Vector<Attribute>& attributeVector) const
1160{
1161 size_t destination = 0;
1162 for (size_t source = 0; source < attributeVector.size(); ++source) {
1163 if (isEventHandlerAttribute(attributeVector[source])
1164 || isJavaScriptURLAttribute(attributeVector[source])
1165 || isHTMLContentAttribute(attributeVector[source]))
1166 continue;
1167
1168 if (source != destination)
1169 attributeVector[destination] = attributeVector[source];
1170
1171 ++destination;
1172 }
1173 attributeVector.shrink(destination);
1174}
1175
1176void Element::parserSetAttributes(const Vector<Attribute>& attributeVector)
1177{
1178 ASSERT(!inDocument());
1179 ASSERT(!parentNode());
1180 ASSERT(!m_elementData);
1181
1182 if (attributeVector.isEmpty())
1183 return;
1184
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001185 if (document().sharedObjectPool())
1186 m_elementData = document().sharedObjectPool()->cachedShareableElementDataWithAttributes(attributeVector);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001187 else
1188 m_elementData = ShareableElementData::createWithAttributes(attributeVector);
1189
1190 // Use attributeVector instead of m_elementData because attributeChanged might modify m_elementData.
1191 for (unsigned i = 0; i < attributeVector.size(); ++i)
1192 attributeChangedFromParserOrByCloning(attributeVector[i].name(), attributeVector[i].value(), ModifiedDirectly);
1193}
1194
1195bool Element::hasAttributes() const
1196{
1197 synchronizeAllAttributes();
1198 return elementData() && elementData()->length();
1199}
1200
1201bool Element::hasEquivalentAttributes(const Element* other) const
1202{
1203 synchronizeAllAttributes();
1204 other->synchronizeAllAttributes();
1205 if (elementData() == other->elementData())
1206 return true;
1207 if (elementData())
1208 return elementData()->isEquivalent(other->elementData());
1209 if (other->elementData())
1210 return other->elementData()->isEquivalent(elementData());
1211 return true;
1212}
1213
1214String Element::nodeName() const
1215{
1216 return m_tagName.toString();
1217}
1218
1219String Element::nodeNamePreservingCase() const
1220{
1221 return m_tagName.toString();
1222}
1223
Ben Murdochdf957042013-08-06 11:01:27 +01001224void Element::setPrefix(const AtomicString& prefix, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001225{
Ben Murdochdf957042013-08-06 11:01:27 +01001226 checkSetPrefix(prefix, es);
1227 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001228 return;
1229
1230 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
1231}
1232
1233KURL Element::baseURI() const
1234{
1235 const AtomicString& baseAttribute = getAttribute(baseAttr);
1236 KURL base(KURL(), baseAttribute);
1237 if (!base.protocol().isEmpty())
1238 return base;
1239
1240 ContainerNode* parent = parentNode();
1241 if (!parent)
1242 return base;
1243
1244 const KURL& parentBase = parent->baseURI();
1245 if (parentBase.isNull())
1246 return base;
1247
1248 return KURL(parentBase, baseAttribute);
1249}
1250
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001251const AtomicString Element::imageSourceURL() const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001252{
1253 return getAttribute(srcAttr);
1254}
1255
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001256bool Element::rendererIsNeeded(const RenderStyle& style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001257{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001258 return style.display() != NONE;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001259}
1260
Ben Murdoch591b9582013-07-10 11:41:44 +01001261RenderObject* Element::createRenderer(RenderStyle* style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001262{
1263 return RenderObject::createObject(this, style);
1264}
1265
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001266Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertionPoint)
1267{
1268 // need to do superclass processing first so inDocument() is true
1269 // by the time we reach updateId
1270 ContainerNode::insertedInto(insertionPoint);
1271
1272 if (containsFullScreenElement() && parentElement() && !parentElement()->containsFullScreenElement())
1273 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
1274
1275 if (Element* before = pseudoElement(BEFORE))
1276 before->insertedInto(insertionPoint);
1277
1278 if (Element* after = pseudoElement(AFTER))
1279 after->insertedInto(insertionPoint);
1280
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001281 if (Element* backdrop = pseudoElement(BACKDROP))
1282 backdrop->insertedInto(insertionPoint);
1283
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001284 if (!insertionPoint->isInTreeScope())
1285 return InsertionDone;
1286
1287 if (hasRareData())
1288 elementRareData()->clearClassListValueForQuirksMode();
1289
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001290 if (isUpgradedCustomElement() && inDocument())
1291 CustomElement::didEnterDocument(this, document());
1292
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001293 TreeScope& scope = insertionPoint->treeScope();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001294 if (scope != treeScope())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001295 return InsertionDone;
1296
1297 const AtomicString& idValue = getIdAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001298 if (!idValue.isNull())
1299 updateId(scope, nullAtom, idValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001300
1301 const AtomicString& nameValue = getNameAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001302 if (!nameValue.isNull())
1303 updateName(nullAtom, nameValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001304
1305 if (hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001306 if (scope.shouldCacheLabelsByForAttribute())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001307 updateLabel(scope, nullAtom, fastGetAttribute(forAttr));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001308 }
1309
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001310 if (parentElement() && parentElement()->isInCanvasSubtree())
1311 setIsInCanvasSubtree(true);
1312
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001313 return InsertionDone;
1314}
1315
1316void Element::removedFrom(ContainerNode* insertionPoint)
1317{
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001318 bool wasInDocument = insertionPoint->inDocument();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001319
1320 if (Element* before = pseudoElement(BEFORE))
1321 before->removedFrom(insertionPoint);
1322
1323 if (Element* after = pseudoElement(AFTER))
1324 after->removedFrom(insertionPoint);
1325
Ben Murdoche69819b2013-07-17 14:56:49 +01001326 if (Element* backdrop = pseudoElement(BACKDROP))
1327 backdrop->removedFrom(insertionPoint);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001328 document().removeFromTopLayer(this);
Ben Murdoche69819b2013-07-17 14:56:49 +01001329
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001330 if (containsFullScreenElement())
1331 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
1332
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001333 if (document().page())
1334 document().page()->pointerLockController().elementRemoved(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001335
1336 setSavedLayerScrollOffset(IntSize());
1337
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001338 if (insertionPoint->isInTreeScope() && treeScope() == document()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001339 const AtomicString& idValue = getIdAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001340 if (!idValue.isNull())
1341 updateId(insertionPoint->treeScope(), idValue, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001342
1343 const AtomicString& nameValue = getNameAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001344 if (!nameValue.isNull())
1345 updateName(nameValue, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001346
1347 if (hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001348 TreeScope& treeScope = insertionPoint->treeScope();
1349 if (treeScope.shouldCacheLabelsByForAttribute())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001350 updateLabel(treeScope, fastGetAttribute(forAttr), nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001351 }
1352 }
1353
1354 ContainerNode::removedFrom(insertionPoint);
Ben Murdoche69819b2013-07-17 14:56:49 +01001355 if (wasInDocument) {
1356 if (hasPendingResources())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001357 document().accessSVGExtensions()->removeElementFromPendingResources(this);
Ben Murdoche69819b2013-07-17 14:56:49 +01001358
Ben Murdoch83750172013-07-24 10:36:59 +01001359 if (isUpgradedCustomElement())
Ben Murdochfff88842013-07-30 15:20:09 +01001360 CustomElement::didLeaveDocument(this, insertionPoint->document());
Ben Murdoche69819b2013-07-17 14:56:49 +01001361 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001362
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001363 if (hasRareData())
1364 elementRareData()->setIsInCanvasSubtree(false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001365}
1366
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001367void Element::attach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001368{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001369 ASSERT(document().inStyleRecalc());
1370
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001371 StyleResolverParentPusher parentPusher(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001372
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001373 // We've already been through detach when doing a lazyAttach, but we might
1374 // need to clear any state that's been added since then.
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001375 if (hasRareData() && styleChangeType() == NeedsReattachStyleChange) {
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001376 ElementRareData* data = elementRareData();
1377 data->clearComputedStyle();
1378 data->resetDynamicRestyleObservations();
1379 if (!context.resolvedStyle)
1380 data->resetStyleState();
1381 }
1382
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001383 NodeRenderingContext(this, context.resolvedStyle).createRendererForElementIfNeeded();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001384
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001385 if (RenderStyle* style = renderStyle())
1386 updateCallbackSelectors(0, style);
1387
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001388 createPseudoElementIfNeeded(BEFORE);
1389
1390 // When a shadow root exists, it does the work of attaching the children.
1391 if (ElementShadow* shadow = this->shadow()) {
1392 parentPusher.push();
Ben Murdoch591b9582013-07-10 11:41:44 +01001393 shadow->attach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001394 } else if (firstChild())
1395 parentPusher.push();
1396
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001397 ContainerNode::attach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001398
1399 createPseudoElementIfNeeded(AFTER);
Ben Murdoche69819b2013-07-17 14:56:49 +01001400 createPseudoElementIfNeeded(BACKDROP);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001401
Ben Murdoch591b9582013-07-10 11:41:44 +01001402 if (hasRareData()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001403 ElementRareData* data = elementRareData();
1404 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001405 if (isFocusable() && document().focusedElement() == this)
1406 document().updateFocusAppearanceSoon(false /* don't restore selection */);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001407 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1408 }
1409 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001410
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001411 InspectorInstrumentation::didRecalculateStyleForElement(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001412}
1413
1414void Element::unregisterNamedFlowContentNode()
1415{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001416 if (RuntimeEnabledFeatures::cssRegionsEnabled() && inNamedFlow() && document().renderView())
1417 document().renderView()->flowThreadController()->unregisterNamedFlowContentNode(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001418}
1419
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001420void Element::detach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001421{
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001422 RenderWidget::UpdateSuspendScope suspendWidgetHierarchyUpdates;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001423 unregisterNamedFlowContentNode();
1424 cancelFocusAppearanceUpdate();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001425 if (RenderStyle* style = renderStyle()) {
1426 if (!style->callbackSelectors().isEmpty())
1427 updateCallbackSelectors(style, 0);
1428 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001429 if (hasRareData()) {
1430 ElementRareData* data = elementRareData();
1431 data->setPseudoElement(BEFORE, 0);
1432 data->setPseudoElement(AFTER, 0);
Ben Murdoche69819b2013-07-17 14:56:49 +01001433 data->setPseudoElement(BACKDROP, 0);
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001434 data->clearComputedStyle();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001435 data->resetDynamicRestyleObservations();
Ben Murdoch591b9582013-07-10 11:41:44 +01001436 data->setIsInsideRegion(false);
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001437
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001438 // Only clear the style state if we're not going to reuse the style from recalcStyle.
1439 if (!context.resolvedStyle)
1440 data->resetStyleState();
1441
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001442 if (RuntimeEnabledFeatures::webAnimationsCSSEnabled() && !context.performingReattach) {
1443 if (ActiveAnimations* activeAnimations = data->activeAnimations())
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001444 activeAnimations->cssAnimations().cancel();
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001445 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001446 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001447 if (ElementShadow* shadow = this->shadow())
1448 shadow->detach(context);
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001449 ContainerNode::detach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001450}
1451
1452bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle)
1453{
1454 ASSERT(currentStyle == renderStyle());
1455 ASSERT(renderer());
1456
1457 if (!currentStyle)
1458 return false;
1459
1460 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles();
1461 if (!pseudoStyleCache)
1462 return false;
1463
1464 size_t cacheSize = pseudoStyleCache->size();
1465 for (size_t i = 0; i < cacheSize; ++i) {
1466 RefPtr<RenderStyle> newPseudoStyle;
1467 PseudoId pseudoId = pseudoStyleCache->at(i)->styleType();
1468 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
1469 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle);
1470 else
1471 newPseudoStyle = renderer()->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
1472 if (!newPseudoStyle)
1473 return true;
1474 if (*newPseudoStyle != *pseudoStyleCache->at(i)) {
1475 if (pseudoId < FIRST_INTERNAL_PSEUDOID)
1476 newStyle->setHasPseudoStyle(pseudoId);
1477 newStyle->addCachedPseudoStyle(newPseudoStyle);
1478 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
1479 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
1480 // is needed, but for now just assume a layout will be required. The diff code
1481 // in RenderObject::setStyle would need to be factored out so that it could be reused.
1482 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
1483 }
1484 return true;
1485 }
1486 }
1487 return false;
1488}
1489
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001490PassRefPtr<RenderStyle> Element::styleForRenderer()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001491{
1492 if (hasCustomStyleCallbacks()) {
1493 if (RefPtr<RenderStyle> style = customStyleForRenderer())
1494 return style.release();
1495 }
1496
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001497 return originalStyleForRenderer();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001498}
1499
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001500PassRefPtr<RenderStyle> Element::originalStyleForRenderer()
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001501{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001502 return document().styleResolver()->styleForElement(this);
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001503}
1504
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001505bool Element::recalcStyle(StyleRecalcChange change)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001506{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001507 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001508
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001509 if (hasCustomStyleCallbacks())
1510 willRecalcStyle(change);
1511
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001512 if (hasRareData() && (change > NoChange || needsStyleRecalc())) {
1513 ElementRareData* data = elementRareData();
1514 data->resetStyleState();
1515 data->clearComputedStyle();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001516 }
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001517
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001518 // Active InsertionPoints have no renderers so they never need to go through a recalc.
1519 if ((change >= Inherit || needsStyleRecalc()) && parentRenderStyle() && !isActiveInsertionPoint(this))
1520 change = recalcOwnStyle(change);
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001521
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001522 // If we reattached we don't need to recalc the style of our descendants anymore.
1523 if (change < Reattach)
1524 recalcChildStyle(change);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001525
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001526 clearNeedsStyleRecalc();
1527 clearChildNeedsStyleRecalc();
Ben Murdoch591b9582013-07-10 11:41:44 +01001528
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001529 if (hasCustomStyleCallbacks())
1530 didRecalcStyle(change);
1531
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001532 return change == Reattach;
1533}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001534
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001535static bool callbackSelectorsDiffer(RenderStyle* style1, RenderStyle* style2)
1536{
1537 const Vector<String> emptyVector;
1538 const Vector<String>& callbackSelectors1 = style1 ? style1->callbackSelectors() : emptyVector;
1539 const Vector<String>& callbackSelectors2 = style2 ? style2->callbackSelectors() : emptyVector;
1540 if (callbackSelectors1.isEmpty() && callbackSelectors2.isEmpty()) {
1541 // Help the inliner with this common case.
1542 return false;
1543 }
1544 return callbackSelectors1 != callbackSelectors2;
1545}
1546
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001547StyleRecalcChange Element::recalcOwnStyle(StyleRecalcChange change)
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001548{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001549 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001550
1551 CSSAnimationUpdateScope cssAnimationUpdateScope(this);
1552 RefPtr<RenderStyle> oldStyle = renderStyle();
1553 RefPtr<RenderStyle> newStyle = styleForRenderer();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001554 StyleRecalcChange localChange = RenderStyle::compare(oldStyle.get(), newStyle.get());
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001555
1556 if (localChange == Reattach) {
1557 AttachContext reattachContext;
1558 reattachContext.resolvedStyle = newStyle.get();
1559 reattach(reattachContext);
1560 return Reattach;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001561 }
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001562
1563 InspectorInstrumentation::didRecalculateStyleForElement(this);
1564
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001565 if (localChange != NoChange && callbackSelectorsDiffer(oldStyle.get(), newStyle.get()))
1566 updateCallbackSelectors(oldStyle.get(), newStyle.get());
1567
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001568 if (RenderObject* renderer = this->renderer()) {
1569 if (localChange != NoChange || pseudoStyleCacheIsInvalid(oldStyle.get(), newStyle.get()) || (change == Force && renderer->requiresForcedStyleRecalcPropagation()) || shouldNotifyRendererWithIdenticalStyles()) {
1570 renderer->setAnimatableStyle(newStyle.get());
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001571 } else {
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001572 // Although no change occurred, we use the new style so that the cousin style sharing code won't get
1573 // fooled into believing this style is the same.
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001574 // FIXME: We may be able to remove this hack, see discussion in
1575 // https://codereview.chromium.org/30453002/
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001576 renderer->setStyleInternal(newStyle.get());
1577 }
1578 }
1579
1580 // 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
1581 // 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).
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01001582 if (document().styleEngine()->usesRemUnits() && document().documentElement() == this && oldStyle && newStyle && oldStyle->fontSize() != newStyle->fontSize()) {
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001583 // Cached RenderStyles may depend on the re units.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001584 document().styleResolver()->invalidateMatchedPropertiesCache();
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001585 return Force;
1586 }
1587
1588 if (styleChangeType() >= SubtreeStyleChange)
1589 return Force;
1590
1591 return max(localChange, change);
1592}
1593
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001594void Element::recalcChildStyle(StyleRecalcChange change)
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001595{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001596 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001597
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001598 StyleResolverParentPusher parentPusher(this);
1599
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001600 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
1601 if (shouldRecalcStyle(change, root)) {
1602 parentPusher.push();
1603 root->recalcStyle(change);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001604 }
1605 }
1606
1607 if (shouldRecalcStyle(change, this))
1608 updatePseudoElement(BEFORE, change);
1609
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001610 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
1611 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001612 unsigned forceCheckOfNextElementCount = 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001613 bool forceCheckOfAnyElementSibling = false;
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001614 if (hasDirectAdjacentRules || hasIndirectAdjacentRules) {
1615 for (Node* child = firstChild(); child; child = child->nextSibling()) {
1616 if (!child->isElementNode())
1617 continue;
Ben Murdoche69819b2013-07-17 14:56:49 +01001618 Element* element = toElement(child);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001619 bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() >= SubtreeStyleChange;
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001620
1621 if (forceCheckOfNextElementCount || forceCheckOfAnyElementSibling)
Ben Murdoche69819b2013-07-17 14:56:49 +01001622 element->setNeedsStyleRecalc();
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001623
1624 if (forceCheckOfNextElementCount)
1625 forceCheckOfNextElementCount--;
1626
1627 if (childRulesChanged && hasDirectAdjacentRules)
1628 forceCheckOfNextElementCount = document().styleEngine()->maxDirectAdjacentSelectors();
1629
Ben Murdoche69819b2013-07-17 14:56:49 +01001630 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001631 }
1632 }
1633 // This loop is deliberately backwards because we use insertBefore in the rendering tree, and want to avoid
1634 // a potentially n^2 loop to find the insertion point while resolving style. Having us start from the last
1635 // child and work our way back means in the common case, we'll find the insertion point in O(1) time.
1636 // Reversing this loop can lead to non-deterministic results in our code to optimize out empty whitespace
1637 // RenderTexts. We try to put off recalcing their style until the end to avoid this issue.
1638 // See crbug.com/288225
1639 WhitespaceChildList whitespaceChildList(change);
1640 for (Node* child = lastChild(); child; child = child->previousSibling()) {
1641 if (child->isTextNode()) {
1642 Text* textChild = toText(child);
1643 // FIXME: This check is expensive and may negate the performance gained by the optimization of
1644 // avoiding whitespace renderers.
1645 if (textChild->containsOnlyWhitespace())
1646 whitespaceChildList.append(textChild);
1647 else
1648 textChild->recalcTextStyle(change);
1649 } else if (child->isElementNode()) {
1650 Element* element = toElement(child);
Ben Murdoche69819b2013-07-17 14:56:49 +01001651 if (shouldRecalcStyle(change, element)) {
1652 parentPusher.push();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001653 element->recalcStyle(change);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001654 } else if (element->supportsStyleSharing()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001655 document().styleResolver()->addToStyleSharingList(element);
Ben Murdoche69819b2013-07-17 14:56:49 +01001656 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001657 }
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001658 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001659
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001660 whitespaceChildList.recalcStyle();
1661
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001662 if (shouldRecalcStyle(change, this)) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001663 updatePseudoElement(AFTER, change);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001664 updatePseudoElement(BACKDROP, change);
1665 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001666}
1667
1668ElementShadow* Element::shadow() const
1669{
1670 return hasRareData() ? elementRareData()->shadow() : 0;
1671}
1672
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001673ElementShadow& Element::ensureShadow()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001674{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001675 return ensureElementRareData().ensureShadow();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001676}
1677
1678void Element::didAffectSelector(AffectedSelectorMask mask)
1679{
1680 setNeedsStyleRecalc();
1681 if (ElementShadow* elementShadow = shadowOfParentForDistribution(this))
1682 elementShadow->didAffectSelector(mask);
1683}
1684
Ben Murdochdf957042013-08-06 11:01:27 +01001685PassRefPtr<ShadowRoot> Element::createShadowRoot(ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001686{
1687 if (alwaysCreateUserAgentShadowRoot())
1688 ensureUserAgentShadowRoot();
1689
1690 if (RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled())
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001691 return ensureShadow().addShadowRoot(*this, ShadowRoot::AuthorShadowRoot);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001692
1693 // Since some elements recreates shadow root dynamically, multiple shadow
1694 // subtrees won't work well in that element. Until they are fixed, we disable
1695 // adding author shadow root for them.
1696 if (!areAuthorShadowsAllowed()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001697 es.throwUninformativeAndGenericDOMException(HierarchyRequestError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001698 return 0;
1699 }
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001700 return ensureShadow().addShadowRoot(*this, ShadowRoot::AuthorShadowRoot);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001701}
1702
1703ShadowRoot* Element::shadowRoot() const
1704{
1705 ElementShadow* elementShadow = shadow();
1706 if (!elementShadow)
1707 return 0;
1708 ShadowRoot* shadowRoot = elementShadow->youngestShadowRoot();
1709 if (shadowRoot->type() == ShadowRoot::AuthorShadowRoot)
1710 return shadowRoot;
1711 return 0;
1712}
1713
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001714void Element::didAddShadowRoot(ShadowRoot&)
1715{
1716}
1717
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001718ShadowRoot* Element::userAgentShadowRoot() const
1719{
1720 if (ElementShadow* elementShadow = shadow()) {
1721 if (ShadowRoot* shadowRoot = elementShadow->oldestShadowRoot()) {
1722 ASSERT(shadowRoot->type() == ShadowRoot::UserAgentShadowRoot);
1723 return shadowRoot;
1724 }
1725 }
1726
1727 return 0;
1728}
1729
1730ShadowRoot* Element::ensureUserAgentShadowRoot()
1731{
1732 if (ShadowRoot* shadowRoot = userAgentShadowRoot())
1733 return shadowRoot;
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001734 ShadowRoot* shadowRoot = ensureShadow().addShadowRoot(*this, ShadowRoot::UserAgentShadowRoot);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001735 didAddUserAgentShadowRoot(shadowRoot);
1736 return shadowRoot;
1737}
1738
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001739bool Element::childTypeAllowed(NodeType type) const
1740{
1741 switch (type) {
1742 case ELEMENT_NODE:
1743 case TEXT_NODE:
1744 case COMMENT_NODE:
1745 case PROCESSING_INSTRUCTION_NODE:
1746 case CDATA_SECTION_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001747 return true;
1748 default:
1749 break;
1750 }
1751 return false;
1752}
1753
Ben Murdoch83750172013-07-24 10:36:59 +01001754static void inline checkForEmptyStyleChange(Element* element, RenderStyle* style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001755{
1756 if (!style && !element->styleAffectedByEmpty())
1757 return;
1758
1759 if (!style || (element->styleAffectedByEmpty() && (!style->emptyState() || element->hasChildNodes())))
1760 element->setNeedsStyleRecalc();
1761}
1762
1763static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
1764 Node* beforeChange, Node* afterChange, int childCountDelta)
1765{
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001766 if (!e->inActiveDocument() || e->document().hasPendingForcedStyleRecalc() || e->styleChangeType() >= SubtreeStyleChange)
Ben Murdoch83750172013-07-24 10:36:59 +01001767 return;
1768
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001769 // :empty selector.
1770 checkForEmptyStyleChange(e, style);
Ben Murdoch591b9582013-07-10 11:41:44 +01001771
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001772 if (!style || (e->needsStyleRecalc() && e->childrenAffectedByPositionalRules()))
1773 return;
1774
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001775 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
1776 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1777 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
1778 // backward case.
1779 // |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.
1780 // 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
Ben Murdoch83750172013-07-24 10:36:59 +01001781 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
1782 if ((e->childrenAffectedByForwardPositionalRules() && afterChange) || (e->childrenAffectedByBackwardPositionalRules() && beforeChange)) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001783 e->setNeedsStyleRecalc();
Ben Murdoch83750172013-07-24 10:36:59 +01001784 return;
1785 }
1786
1787 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1788 // In the DOM case, we only need to do something if |afterChange| is not 0.
1789 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
1790 if (e->childrenAffectedByFirstChildRules() && afterChange) {
1791 // Find our new first child.
1792 Node* newFirstChild = e->firstElementChild();
1793 RenderStyle* newFirstChildStyle = newFirstChild ? newFirstChild->renderStyle() : 0;
1794
1795 // Find the first element node following |afterChange|
1796 Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling();
1797 RenderStyle* firstElementAfterInsertionStyle = firstElementAfterInsertion ? firstElementAfterInsertion->renderStyle() : 0;
1798
1799 // This is the insert/append case.
1800 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertionStyle && firstElementAfterInsertionStyle->firstChildState())
1801 firstElementAfterInsertion->setNeedsStyleRecalc();
1802
1803 // We also have to handle node removal.
1804 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChildStyle || !newFirstChildStyle->firstChildState()))
1805 newFirstChild->setNeedsStyleRecalc();
1806 }
1807
1808 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1809 // In the DOM case, we only need to do something if |afterChange| is not 0.
1810 if (e->childrenAffectedByLastChildRules() && beforeChange) {
1811 // Find our new last child.
1812 Node* newLastChild = e->lastElementChild();
1813 RenderStyle* newLastChildStyle = newLastChild ? newLastChild->renderStyle() : 0;
1814
1815 // Find the last element node going backwards from |beforeChange|
1816 Node* lastElementBeforeInsertion = beforeChange->isElementNode() ? beforeChange : beforeChange->previousElementSibling();
1817 RenderStyle* lastElementBeforeInsertionStyle = lastElementBeforeInsertion ? lastElementBeforeInsertion->renderStyle() : 0;
1818
1819 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertionStyle && lastElementBeforeInsertionStyle->lastChildState())
1820 lastElementBeforeInsertion->setNeedsStyleRecalc();
1821
1822 // 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
1823 // to match now.
1824 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChildStyle || !newLastChildStyle->lastChildState()))
1825 newLastChild->setNeedsStyleRecalc();
1826 }
1827
1828 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
1829 // that could be affected by this DOM change.
1830 if (e->childrenAffectedByDirectAdjacentRules() && afterChange) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001831 if (Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling())
Ben Murdoch83750172013-07-24 10:36:59 +01001832 firstElementAfterInsertion->setNeedsStyleRecalc();
1833 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001834}
1835
1836void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
1837{
1838 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
1839 if (changedByParser)
1840 checkForEmptyStyleChange(this, renderStyle());
1841 else
1842 checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
1843
Ben Murdoch83750172013-07-24 10:36:59 +01001844 if (ElementShadow* shadow = this->shadow())
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001845 shadow->setNeedsDistributionRecalc();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001846}
1847
1848void Element::removeAllEventListeners()
1849{
1850 ContainerNode::removeAllEventListeners();
1851 if (ElementShadow* shadow = this->shadow())
1852 shadow->removeAllEventListeners();
1853}
1854
1855void Element::beginParsingChildren()
1856{
1857 clearIsParsingChildrenFinished();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001858}
1859
1860void Element::finishParsingChildren()
1861{
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001862 setIsParsingChildrenFinished();
1863 checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001864 if (isCustomElement())
1865 CustomElement::didFinishParsingChildren(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001866}
1867
1868#ifndef NDEBUG
1869void Element::formatForDebugger(char* buffer, unsigned length) const
1870{
1871 StringBuilder result;
1872 String s;
1873
1874 result.append(nodeName());
1875
1876 s = getIdAttribute();
1877 if (s.length() > 0) {
1878 if (result.length() > 0)
1879 result.appendLiteral("; ");
1880 result.appendLiteral("id=");
1881 result.append(s);
1882 }
1883
1884 s = getAttribute(classAttr);
1885 if (s.length() > 0) {
1886 if (result.length() > 0)
1887 result.appendLiteral("; ");
1888 result.appendLiteral("class=");
1889 result.append(s);
1890 }
1891
1892 strncpy(buffer, result.toString().utf8().data(), length - 1);
1893}
1894#endif
1895
1896const Vector<RefPtr<Attr> >& Element::attrNodeList()
1897{
1898 ASSERT(hasSyntheticAttrChildNodes());
1899 return *attrNodeListForElement(this);
1900}
1901
Ben Murdochdf957042013-08-06 11:01:27 +01001902PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001903{
1904 if (!attrNode) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001905 es.throwUninformativeAndGenericDOMException(TypeMismatchError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001906 return 0;
1907 }
1908
1909 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName());
1910 if (oldAttrNode.get() == attrNode)
1911 return attrNode; // This Attr is already attached to the element.
1912
Ben Murdoche69819b2013-07-17 14:56:49 +01001913 // InUseAttributeError: Raised if node is an Attr that is already an attribute of another Element object.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001914 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
1915 if (attrNode->ownerElement()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001916 es.throwUninformativeAndGenericDOMException(InUseAttributeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001917 return 0;
1918 }
1919
1920 synchronizeAllAttributes();
1921 UniqueElementData* elementData = ensureUniqueElementData();
1922
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001923 size_t index = elementData->getAttributeItemIndex(attrNode->qualifiedName(), shouldIgnoreAttributeCase());
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001924 if (index != kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001925 if (oldAttrNode)
1926 detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData->attributeItem(index)->value());
1927 else
1928 oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), elementData->attributeItem(index)->value());
1929 }
1930
1931 setAttributeInternal(index, attrNode->qualifiedName(), attrNode->value(), NotInSynchronizationOfLazyAttribute);
1932
1933 attrNode->attachToElement(this);
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001934 treeScope().adoptIfNeeded(*attrNode);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001935 ensureAttrNodeListForElement(this).append(attrNode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001936
1937 return oldAttrNode.release();
1938}
1939
Ben Murdochdf957042013-08-06 11:01:27 +01001940PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001941{
Ben Murdochdf957042013-08-06 11:01:27 +01001942 return setAttributeNode(attr, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001943}
1944
Ben Murdochdf957042013-08-06 11:01:27 +01001945PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001946{
1947 if (!attr) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001948 es.throwUninformativeAndGenericDOMException(TypeMismatchError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001949 return 0;
1950 }
1951 if (attr->ownerElement() != this) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001952 es.throwUninformativeAndGenericDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001953 return 0;
1954 }
1955
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001956 ASSERT(document() == attr->document());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001957
1958 synchronizeAttribute(attr->qualifiedName());
1959
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001960 size_t index = elementData()->getAttrIndex(attr);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001961 if (index == kNotFound) {
1962 es.throwUninformativeAndGenericDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001963 return 0;
1964 }
1965
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001966 RefPtr<Attr> guard(attr);
1967 detachAttrNodeAtIndex(attr, index);
1968 return guard.release();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001969}
1970
Ben Murdochdf957042013-08-06 11:01:27 +01001971bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001972{
1973 String prefix, localName;
Ben Murdochdf957042013-08-06 11:01:27 +01001974 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, es))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001975 return false;
Ben Murdochdf957042013-08-06 11:01:27 +01001976 ASSERT(!es.hadException());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001977
1978 QualifiedName qName(prefix, localName, namespaceURI);
1979
1980 if (!Document::hasValidNamespaceForAttributes(qName)) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001981 es.throwUninformativeAndGenericDOMException(NamespaceError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001982 return false;
1983 }
1984
1985 out = qName;
1986 return true;
1987}
1988
Ben Murdochdf957042013-08-06 11:01:27 +01001989void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001990{
1991 QualifiedName parsedName = anyName;
Ben Murdochdf957042013-08-06 11:01:27 +01001992 if (!parseAttributeName(parsedName, namespaceURI, qualifiedName, es))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001993 return;
1994 setAttribute(parsedName, value);
1995}
1996
1997void Element::removeAttributeInternal(size_t index, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1998{
1999 ASSERT_WITH_SECURITY_IMPLICATION(index < attributeCount());
2000
2001 UniqueElementData* elementData = ensureUniqueElementData();
2002
2003 QualifiedName name = elementData->attributeItem(index)->name();
2004 AtomicString valueBeingRemoved = elementData->attributeItem(index)->value();
2005
2006 if (!inSynchronizationOfLazyAttribute) {
2007 if (!valueBeingRemoved.isNull())
2008 willModifyAttribute(name, valueBeingRemoved, nullAtom);
2009 }
2010
2011 if (RefPtr<Attr> attrNode = attrIfExists(name))
2012 detachAttrNodeFromElementWithValue(attrNode.get(), elementData->attributeItem(index)->value());
2013
2014 elementData->removeAttribute(index);
2015
2016 if (!inSynchronizationOfLazyAttribute)
2017 didRemoveAttribute(name);
2018}
2019
2020void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
2021{
2022 if (!inSynchronizationOfLazyAttribute)
2023 willModifyAttribute(name, nullAtom, value);
2024 ensureUniqueElementData()->addAttribute(name, value);
2025 if (!inSynchronizationOfLazyAttribute)
2026 didAddAttribute(name, value);
2027}
2028
2029void Element::removeAttribute(const AtomicString& name)
2030{
2031 if (!elementData())
2032 return;
2033
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002034 AtomicString localName = shouldIgnoreAttributeCase() ? name.lower() : name;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002035 size_t index = elementData()->getAttributeItemIndex(localName, false);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01002036 if (index == kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002037 if (UNLIKELY(localName == styleAttr) && elementData()->m_styleAttributeIsDirty && isStyledElement())
Ben Murdoch591b9582013-07-10 11:41:44 +01002038 removeAllInlineStyleProperties();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002039 return;
2040 }
2041
2042 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
2043}
2044
2045void Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName)
2046{
2047 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI));
2048}
2049
2050PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& localName)
2051{
2052 if (!elementData())
2053 return 0;
2054 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002055 const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002056 if (!attribute)
2057 return 0;
2058 return ensureAttr(attribute->name());
2059}
2060
2061PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
2062{
2063 if (!elementData())
2064 return 0;
2065 QualifiedName qName(nullAtom, localName, namespaceURI);
2066 synchronizeAttribute(qName);
2067 const Attribute* attribute = elementData()->getAttributeItem(qName);
2068 if (!attribute)
2069 return 0;
2070 return ensureAttr(attribute->name());
2071}
2072
2073bool Element::hasAttribute(const AtomicString& localName) const
2074{
2075 if (!elementData())
2076 return false;
2077 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002078 return elementData()->getAttributeItem(shouldIgnoreAttributeCase() ? localName.lower() : localName, false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002079}
2080
2081bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
2082{
2083 if (!elementData())
2084 return false;
2085 QualifiedName qName(nullAtom, localName, namespaceURI);
2086 synchronizeAttribute(qName);
2087 return elementData()->getAttributeItem(qName);
2088}
2089
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002090void Element::focus(bool restorePreviousSelection, FocusDirection direction)
2091{
2092 if (!inDocument())
2093 return;
2094
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002095 Document& doc = document();
2096 if (doc.focusedElement() == this)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002097 return;
2098
2099 // If the stylesheets have already been loaded we can reliably check isFocusable.
2100 // If not, we continue and set the focused node on the focus controller below so
Ben Murdoch591b9582013-07-10 11:41:44 +01002101 // that it can be updated soon after attach.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002102 if (doc.haveStylesheetsLoaded()) {
2103 doc.updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002104 if (!isFocusable())
2105 return;
2106 }
2107
2108 if (!supportsFocus())
2109 return;
2110
2111 RefPtr<Node> protect;
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002112 if (Page* page = doc.page()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002113 // Focus and change event handlers can cause us to lose our last ref.
2114 // If a focus event handler changes the focus to a different node it
2115 // does not make sense to continue and update appearence.
2116 protect = this;
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002117 if (!page->focusController().setFocusedElement(this, doc.frame(), direction))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002118 return;
2119 }
2120
2121 // Setting the focused node above might have invalidated the layout due to scripts.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002122 doc.updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002123
2124 if (!isFocusable()) {
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002125 ensureElementRareData().setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002126 return;
2127 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002128
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002129 cancelFocusAppearanceUpdate();
2130 updateFocusAppearance(restorePreviousSelection);
2131}
2132
2133void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
2134{
2135 if (isRootEditableElement()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002136 Frame* frame = document().frame();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002137 if (!frame)
2138 return;
Ben Murdoch591b9582013-07-10 11:41:44 +01002139
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002140 // When focusing an editable element in an iframe, don't reset the selection if it already contains a selection.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002141 if (this == frame->selection().rootEditableElement())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002142 return;
2143
2144 // FIXME: We should restore the previous selection if there is one.
2145 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002146 frame->selection().setSelection(newSelection);
2147 frame->selection().revealSelection();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002148 } else if (renderer() && !renderer()->isWidget())
2149 renderer()->scrollRectToVisible(boundingBox());
2150}
2151
2152void Element::blur()
2153{
2154 cancelFocusAppearanceUpdate();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002155 if (treeScope().adjustedFocusedElement() == this) {
2156 Document& doc = document();
2157 if (doc.page())
2158 doc.page()->focusController().setFocusedElement(0, doc.frame());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002159 else
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002160 doc.setFocusedElement(0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002161 }
2162}
2163
Ben Murdochdf957042013-08-06 11:01:27 +01002164bool Element::isFocusable() const
2165{
2166 return inDocument() && supportsFocus() && !isInert() && rendererIsFocusable();
2167}
2168
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002169bool Element::isKeyboardFocusable() const
2170{
2171 return isFocusable() && tabIndex() >= 0;
2172}
2173
2174bool Element::isMouseFocusable() const
2175{
2176 return isFocusable();
2177}
2178
Ben Murdoch02772c62013-07-26 10:21:05 +01002179void Element::dispatchFocusEvent(Element* oldFocusedElement, FocusDirection)
2180{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002181 RefPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::focus, false, false, document().domWindow(), 0, oldFocusedElement);
Ben Murdoch02772c62013-07-26 10:21:05 +01002182 EventDispatcher::dispatchEvent(this, FocusEventDispatchMediator::create(event.release()));
2183}
2184
2185void Element::dispatchBlurEvent(Element* newFocusedElement)
2186{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002187 RefPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::blur, false, false, document().domWindow(), 0, newFocusedElement);
Ben Murdoch02772c62013-07-26 10:21:05 +01002188 EventDispatcher::dispatchEvent(this, BlurEventDispatchMediator::create(event.release()));
2189}
2190
2191void Element::dispatchFocusInEvent(const AtomicString& eventType, Element* oldFocusedElement)
2192{
2193 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002194 ASSERT(eventType == EventTypeNames::focusin || eventType == EventTypeNames::DOMFocusIn);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002195 dispatchScopedEventDispatchMediator(FocusInEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document().domWindow(), 0, oldFocusedElement)));
Ben Murdoch02772c62013-07-26 10:21:05 +01002196}
2197
2198void Element::dispatchFocusOutEvent(const AtomicString& eventType, Element* newFocusedElement)
2199{
2200 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002201 ASSERT(eventType == EventTypeNames::focusout || eventType == EventTypeNames::DOMFocusOut);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002202 dispatchScopedEventDispatchMediator(FocusOutEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document().domWindow(), 0, newFocusedElement)));
Ben Murdoch02772c62013-07-26 10:21:05 +01002203}
2204
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002205String Element::innerText()
2206{
2207 // We need to update layout, since plainText uses line boxes in the render tree.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002208 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002209
2210 if (!renderer())
2211 return textContent(true);
2212
2213 return plainText(rangeOfContents(const_cast<Element*>(this)).get());
2214}
2215
2216String Element::outerText()
2217{
2218 // Getting outerText is the same as getting innerText, only
2219 // setting is different. You would think this should get the plain
2220 // text for the outer range, but this is wrong, <br> for instance
2221 // would return different values for inner and outer text by such
2222 // a rule, but it doesn't in WinIE, and we want to match that.
2223 return innerText();
2224}
2225
Ben Murdoch591b9582013-07-10 11:41:44 +01002226String Element::textFromChildren()
2227{
2228 Text* firstTextNode = 0;
2229 bool foundMultipleTextNodes = false;
2230 unsigned totalLength = 0;
2231
2232 for (Node* child = firstChild(); child; child = child->nextSibling()) {
2233 if (!child->isTextNode())
2234 continue;
2235 Text* text = toText(child);
2236 if (!firstTextNode)
2237 firstTextNode = text;
2238 else
2239 foundMultipleTextNodes = true;
2240 unsigned length = text->data().length();
2241 if (length > std::numeric_limits<unsigned>::max() - totalLength)
2242 return emptyString();
2243 totalLength += length;
2244 }
2245
2246 if (!firstTextNode)
2247 return emptyString();
2248
2249 if (firstTextNode && !foundMultipleTextNodes) {
2250 firstTextNode->atomize();
2251 return firstTextNode->data();
2252 }
2253
2254 StringBuilder content;
2255 content.reserveCapacity(totalLength);
2256 for (Node* child = firstTextNode; child; child = child->nextSibling()) {
2257 if (!child->isTextNode())
2258 continue;
2259 content.append(toText(child)->data());
2260 }
2261
2262 ASSERT(content.length() == totalLength);
2263 return content.toString();
2264}
2265
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01002266// pseudo is used via shadowPseudoId.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002267const AtomicString& Element::pseudo() const
2268{
2269 return getAttribute(pseudoAttr);
2270}
2271
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002272const AtomicString& Element::part() const
2273{
2274 return getAttribute(partAttr);
2275}
2276
2277void Element::setPart(const AtomicString& value)
2278{
2279 setAttribute(partAttr, value);
2280}
2281
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002282LayoutSize Element::minimumSizeForResizing() const
2283{
2284 return hasRareData() ? elementRareData()->minimumSizeForResizing() : defaultMinimumSizeForResizing();
2285}
2286
2287void Element::setMinimumSizeForResizing(const LayoutSize& size)
2288{
2289 if (!hasRareData() && size == defaultMinimumSizeForResizing())
2290 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002291 ensureElementRareData().setMinimumSizeForResizing(size);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002292}
2293
2294RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
2295{
2296 if (PseudoElement* element = pseudoElement(pseudoElementSpecifier))
2297 return element->computedStyle();
2298
2299 // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
2300 // properties, which are only known by the renderer because it did the layout, will be correct and so that the
2301 // values returned for the ":selection" pseudo-element will be correct.
2302 if (RenderStyle* usedStyle = renderStyle()) {
2303 if (pseudoElementSpecifier) {
2304 RenderStyle* cachedPseudoStyle = usedStyle->getCachedPseudoStyle(pseudoElementSpecifier);
2305 return cachedPseudoStyle ? cachedPseudoStyle : usedStyle;
2306 } else
2307 return usedStyle;
2308 }
2309
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00002310 if (!inActiveDocument())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002311 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
2312 // document tree and figure out when to destroy the computed style for such elements.
2313 return 0;
2314
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002315 ElementRareData& rareData = ensureElementRareData();
2316 if (!rareData.computedStyle())
2317 rareData.setComputedStyle(document().styleForElementIgnoringPendingStylesheets(this));
2318 return pseudoElementSpecifier ? rareData.computedStyle()->getCachedPseudoStyle(pseudoElementSpecifier) : rareData.computedStyle();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002319}
2320
2321void Element::setStyleAffectedByEmpty()
2322{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002323 ensureElementRareData().setStyleAffectedByEmpty(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002324}
2325
2326void Element::setChildrenAffectedByHover(bool value)
2327{
2328 if (value || hasRareData())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002329 ensureElementRareData().setChildrenAffectedByHover(value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002330}
2331
2332void Element::setChildrenAffectedByActive(bool value)
2333{
2334 if (value || hasRareData())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002335 ensureElementRareData().setChildrenAffectedByActive(value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002336}
2337
2338void Element::setChildrenAffectedByDrag(bool value)
2339{
2340 if (value || hasRareData())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002341 ensureElementRareData().setChildrenAffectedByDrag(value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002342}
2343
2344void Element::setChildrenAffectedByFirstChildRules()
2345{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002346 ensureElementRareData().setChildrenAffectedByFirstChildRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002347}
2348
2349void Element::setChildrenAffectedByLastChildRules()
2350{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002351 ensureElementRareData().setChildrenAffectedByLastChildRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002352}
2353
2354void Element::setChildrenAffectedByDirectAdjacentRules()
2355{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002356 ensureElementRareData().setChildrenAffectedByDirectAdjacentRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002357}
2358
2359void Element::setChildrenAffectedByForwardPositionalRules()
2360{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002361 ensureElementRareData().setChildrenAffectedByForwardPositionalRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002362}
2363
2364void Element::setChildrenAffectedByBackwardPositionalRules()
2365{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002366 ensureElementRareData().setChildrenAffectedByBackwardPositionalRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002367}
2368
2369void Element::setChildIndex(unsigned index)
2370{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002371 ElementRareData& rareData = ensureElementRareData();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002372 if (RenderStyle* style = renderStyle())
2373 style->setUnique();
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002374 rareData.setChildIndex(index);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002375}
2376
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002377bool Element::childrenSupportStyleSharing() const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002378{
2379 if (!hasRareData())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002380 return true;
2381 return !rareDataChildrenAffectedByHover()
2382 && !rareDataChildrenAffectedByActive()
2383 && !rareDataChildrenAffectedByDrag()
2384 && !rareDataChildrenAffectedByFirstChildRules()
2385 && !rareDataChildrenAffectedByLastChildRules()
2386 && !rareDataChildrenAffectedByDirectAdjacentRules()
2387 && !rareDataChildrenAffectedByForwardPositionalRules()
2388 && !rareDataChildrenAffectedByBackwardPositionalRules();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002389}
2390
2391bool Element::rareDataStyleAffectedByEmpty() const
2392{
2393 ASSERT(hasRareData());
2394 return elementRareData()->styleAffectedByEmpty();
2395}
2396
2397bool Element::rareDataChildrenAffectedByHover() const
2398{
2399 ASSERT(hasRareData());
2400 return elementRareData()->childrenAffectedByHover();
2401}
2402
2403bool Element::rareDataChildrenAffectedByActive() const
2404{
2405 ASSERT(hasRareData());
2406 return elementRareData()->childrenAffectedByActive();
2407}
2408
2409bool Element::rareDataChildrenAffectedByDrag() const
2410{
2411 ASSERT(hasRareData());
2412 return elementRareData()->childrenAffectedByDrag();
2413}
2414
2415bool Element::rareDataChildrenAffectedByFirstChildRules() const
2416{
2417 ASSERT(hasRareData());
2418 return elementRareData()->childrenAffectedByFirstChildRules();
2419}
2420
2421bool Element::rareDataChildrenAffectedByLastChildRules() const
2422{
2423 ASSERT(hasRareData());
2424 return elementRareData()->childrenAffectedByLastChildRules();
2425}
2426
2427bool Element::rareDataChildrenAffectedByDirectAdjacentRules() const
2428{
2429 ASSERT(hasRareData());
2430 return elementRareData()->childrenAffectedByDirectAdjacentRules();
2431}
2432
2433bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
2434{
2435 ASSERT(hasRareData());
2436 return elementRareData()->childrenAffectedByForwardPositionalRules();
2437}
2438
2439bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
2440{
2441 ASSERT(hasRareData());
2442 return elementRareData()->childrenAffectedByBackwardPositionalRules();
2443}
2444
2445unsigned Element::rareDataChildIndex() const
2446{
2447 ASSERT(hasRareData());
2448 return elementRareData()->childIndex();
2449}
2450
2451void Element::setIsInCanvasSubtree(bool isInCanvasSubtree)
2452{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002453 ensureElementRareData().setIsInCanvasSubtree(isInCanvasSubtree);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002454}
2455
2456bool Element::isInCanvasSubtree() const
2457{
2458 return hasRareData() && elementRareData()->isInCanvasSubtree();
2459}
2460
Ben Murdoch591b9582013-07-10 11:41:44 +01002461void Element::setIsInsideRegion(bool value)
2462{
2463 if (value == isInsideRegion())
2464 return;
2465
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002466 ensureElementRareData().setIsInsideRegion(value);
Ben Murdoch591b9582013-07-10 11:41:44 +01002467}
2468
2469bool Element::isInsideRegion() const
2470{
2471 return hasRareData() ? elementRareData()->isInsideRegion() : false;
2472}
2473
2474void Element::setRegionOversetState(RegionOversetState state)
2475{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002476 ensureElementRareData().setRegionOversetState(state);
Ben Murdoch591b9582013-07-10 11:41:44 +01002477}
2478
2479RegionOversetState Element::regionOversetState() const
2480{
2481 return hasRareData() ? elementRareData()->regionOversetState() : RegionUndefined;
2482}
2483
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002484AtomicString Element::computeInheritedLanguage() const
2485{
2486 const Node* n = this;
2487 AtomicString value;
2488 // The language property is inherited, so we iterate over the parents to find the first language.
2489 do {
2490 if (n->isElementNode()) {
2491 if (const ElementData* elementData = toElement(n)->elementData()) {
2492 // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7
2493 if (const Attribute* attribute = elementData->getAttributeItem(XMLNames::langAttr))
2494 value = attribute->value();
2495 else if (const Attribute* attribute = elementData->getAttributeItem(HTMLNames::langAttr))
2496 value = attribute->value();
2497 }
2498 } else if (n->isDocumentNode()) {
2499 // checking the MIME content-language
2500 value = toDocument(n)->contentLanguage();
2501 }
2502
2503 n = n->parentNode();
2504 } while (n && value.isNull());
2505
2506 return value;
2507}
2508
2509Locale& Element::locale() const
2510{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002511 return document().getCachedLocale(computeInheritedLanguage());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002512}
2513
2514void Element::cancelFocusAppearanceUpdate()
2515{
2516 if (hasRareData())
2517 elementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002518 if (document().focusedElement() == this)
2519 document().cancelFocusAppearanceUpdate();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002520}
2521
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002522void Element::updateCallbackSelectors(RenderStyle* oldStyle, RenderStyle* newStyle)
2523{
2524 const Vector<String> emptyVector;
2525 const Vector<String>& oldCallbackSelectors = oldStyle ? oldStyle->callbackSelectors() : emptyVector;
2526 const Vector<String>& newCallbackSelectors = newStyle ? newStyle->callbackSelectors() : emptyVector;
2527
2528 CSSSelectorWatch::from(document()).updateSelectorMatches(oldCallbackSelectors, newCallbackSelectors);
2529}
2530
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002531void Element::normalizeAttributes()
2532{
2533 if (!hasAttributes())
2534 return;
2535 for (unsigned i = 0; i < attributeCount(); ++i) {
2536 if (RefPtr<Attr> attr = attrIfExists(attributeItem(i)->name()))
2537 attr->normalize();
2538 }
2539}
2540
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002541void Element::updatePseudoElement(PseudoId pseudoId, StyleRecalcChange change)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002542{
2543 PseudoElement* element = pseudoElement(pseudoId);
2544 if (element && (needsStyleRecalc() || shouldRecalcStyle(change, element))) {
2545 // PseudoElement styles hang off their parent element's style so if we needed
2546 // a style recalc we should Force one on the pseudo.
2547 element->recalcStyle(needsStyleRecalc() ? Force : change);
2548
2549 // Wait until our parent is not displayed or pseudoElementRendererIsNeeded
2550 // is false, otherwise we could continously create and destroy PseudoElements
2551 // when RenderObject::isChildAllowed on our parent returns false for the
2552 // PseudoElement's renderer for each style recalc.
2553 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01002554 elementRareData()->setPseudoElement(pseudoId, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002555 } else if (change >= Inherit || needsStyleRecalc())
2556 createPseudoElementIfNeeded(pseudoId);
2557}
2558
2559void Element::createPseudoElementIfNeeded(PseudoId pseudoId)
2560{
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002561 if (needsPseudoElement(pseudoId))
2562 createPseudoElement(pseudoId);
2563}
2564
2565bool Element::needsPseudoElement(PseudoId pseudoId) const
2566{
Ben Murdoche69819b2013-07-17 14:56:49 +01002567 if (pseudoId == BACKDROP && !isInTopLayer())
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002568 return false;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002569 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002570 return false;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002571 if (!renderer()->canHaveGeneratedChildren())
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002572 return false;
2573 return true;
2574}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002575
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002576void Element::createPseudoElement(PseudoId pseudoId)
2577{
2578 ASSERT(needsPseudoElement(pseudoId));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002579 ASSERT(!isPseudoElement());
2580 RefPtr<PseudoElement> element = PseudoElement::create(this, pseudoId);
Ben Murdoche69819b2013-07-17 14:56:49 +01002581 if (pseudoId == BACKDROP)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002582 document().addToTopLayer(element.get(), this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002583 element->attach();
Ben Murdoche69819b2013-07-17 14:56:49 +01002584
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002585 ensureElementRareData().setPseudoElement(pseudoId, element.release());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002586}
2587
2588PseudoElement* Element::pseudoElement(PseudoId pseudoId) const
2589{
2590 return hasRareData() ? elementRareData()->pseudoElement(pseudoId) : 0;
2591}
2592
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002593RenderObject* Element::pseudoElementRenderer(PseudoId pseudoId) const
2594{
2595 if (PseudoElement* element = pseudoElement(pseudoId))
2596 return element->renderer();
2597 return 0;
2598}
2599
Ben Murdochdf957042013-08-06 11:01:27 +01002600bool Element::webkitMatchesSelector(const String& selector, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002601{
2602 if (selector.isEmpty()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01002603 es.throwUninformativeAndGenericDOMException(SyntaxError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002604 return false;
2605 }
2606
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00002607 SelectorQuery* selectorQuery = document().selectorQueryCache().add(selector, document(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002608 if (!selectorQuery)
2609 return false;
2610 return selectorQuery->matches(this);
2611}
2612
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002613DOMTokenList* Element::classList()
2614{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002615 ElementRareData& rareData = ensureElementRareData();
2616 if (!rareData.classList())
2617 rareData.setClassList(ClassList::create(this));
2618 return rareData.classList();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002619}
2620
2621DOMStringMap* Element::dataset()
2622{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002623 ElementRareData& rareData = ensureElementRareData();
2624 if (!rareData.dataset())
2625 rareData.setDataset(DatasetDOMStringMap::create(this));
2626 return rareData.dataset();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002627}
2628
2629KURL Element::getURLAttribute(const QualifiedName& name) const
2630{
2631#if !ASSERT_DISABLED
2632 if (elementData()) {
2633 if (const Attribute* attribute = getAttributeItem(name))
2634 ASSERT(isURLAttribute(*attribute));
2635 }
2636#endif
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002637 return document().completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002638}
2639
2640KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
2641{
2642#if !ASSERT_DISABLED
2643 if (elementData()) {
2644 if (const Attribute* attribute = getAttributeItem(name))
2645 ASSERT(isURLAttribute(*attribute));
2646 }
2647#endif
2648 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
2649 if (value.isEmpty())
2650 return KURL();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002651 return document().completeURL(value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002652}
2653
2654int Element::getIntegralAttribute(const QualifiedName& attributeName) const
2655{
2656 return getAttribute(attributeName).string().toInt();
2657}
2658
2659void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
2660{
2661 // FIXME: Need an AtomicString version of String::number.
2662 setAttribute(attributeName, String::number(value));
2663}
2664
2665unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
2666{
2667 return getAttribute(attributeName).string().toUInt();
2668}
2669
2670void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
2671{
2672 // FIXME: Need an AtomicString version of String::number.
2673 setAttribute(attributeName, String::number(value));
2674}
2675
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002676bool Element::childShouldCreateRenderer(const Node& child) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002677{
2678 // Only create renderers for SVG elements whose parents are SVG elements, or for proper <svg xmlns="svgNS"> subdocuments.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002679 if (child.isSVGElement())
2680 return child.hasTagName(SVGNames::svgTag) || isSVGElement();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002681
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002682 return ContainerNode::childShouldCreateRenderer(child);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002683}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002684
2685void Element::webkitRequestFullscreen()
2686{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002687 FullscreenElementStack::from(&document())->requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002688}
2689
2690void Element::webkitRequestFullScreen(unsigned short flags)
2691{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002692 FullscreenElementStack::from(&document())->requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002693}
2694
2695bool Element::containsFullScreenElement() const
2696{
2697 return hasRareData() && elementRareData()->containsFullScreenElement();
2698}
2699
2700void Element::setContainsFullScreenElement(bool flag)
2701{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002702 ensureElementRareData().setContainsFullScreenElement(flag);
Ben Murdoche69819b2013-07-17 14:56:49 +01002703 setNeedsStyleRecalc(SubtreeStyleChange);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002704}
2705
2706static Element* parentCrossingFrameBoundaries(Element* element)
2707{
2708 ASSERT(element);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002709 return element->parentElement() ? element->parentElement() : element->document().ownerElement();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002710}
2711
2712void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool flag)
2713{
2714 Element* element = this;
2715 while ((element = parentCrossingFrameBoundaries(element)))
2716 element->setContainsFullScreenElement(flag);
2717}
2718
2719bool Element::isInTopLayer() const
2720{
2721 return hasRareData() && elementRareData()->isInTopLayer();
2722}
2723
2724void Element::setIsInTopLayer(bool inTopLayer)
2725{
2726 if (isInTopLayer() == inTopLayer)
2727 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002728 ensureElementRareData().setIsInTopLayer(inTopLayer);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002729
2730 // We must ensure a reattach occurs so the renderer is inserted in the correct sibling order under RenderView according to its
2731 // top layer position, or in its usual place if not in the top layer.
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002732 lazyReattachIfAttached();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002733}
2734
2735void Element::webkitRequestPointerLock()
2736{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002737 if (document().page())
2738 document().page()->pointerLockController().requestPointerLock(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002739}
2740
2741SpellcheckAttributeState Element::spellcheckAttributeState() const
2742{
2743 const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
2744 if (value == nullAtom)
2745 return SpellcheckAttributeDefault;
2746 if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
2747 return SpellcheckAttributeTrue;
2748 if (equalIgnoringCase(value, "false"))
2749 return SpellcheckAttributeFalse;
2750
2751 return SpellcheckAttributeDefault;
2752}
2753
2754bool Element::isSpellCheckingEnabled() const
2755{
2756 for (const Element* element = this; element; element = element->parentOrShadowHostElement()) {
2757 switch (element->spellcheckAttributeState()) {
2758 case SpellcheckAttributeTrue:
2759 return true;
2760 case SpellcheckAttributeFalse:
2761 return false;
2762 case SpellcheckAttributeDefault:
2763 break;
2764 }
2765 }
2766
2767 return true;
2768}
2769
2770RenderRegion* Element::renderRegion() const
2771{
2772 if (renderer() && renderer()->isRenderRegion())
2773 return toRenderRegion(renderer());
2774
2775 return 0;
2776}
2777
Ben Murdoch591b9582013-07-10 11:41:44 +01002778bool Element::shouldMoveToFlowThread(RenderStyle* styleToUse) const
2779{
2780 ASSERT(styleToUse);
2781
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002782 if (FullscreenElementStack::isActiveFullScreenElement(this))
Ben Murdoch591b9582013-07-10 11:41:44 +01002783 return false;
2784
2785 if (isInShadowTree())
2786 return false;
2787
2788 if (styleToUse->flowThread().isEmpty())
2789 return false;
2790
2791 return !isRegisteredWithNamedFlow();
2792}
2793
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002794const AtomicString& Element::webkitRegionOverset() const
2795{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002796 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002797
2798 DEFINE_STATIC_LOCAL(AtomicString, undefinedState, ("undefined", AtomicString::ConstructFromLiteral));
2799 if (!RuntimeEnabledFeatures::cssRegionsEnabled() || !renderRegion())
2800 return undefinedState;
2801
Ben Murdoch591b9582013-07-10 11:41:44 +01002802 switch (renderRegion()->regionOversetState()) {
2803 case RegionFit: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002804 DEFINE_STATIC_LOCAL(AtomicString, fitState, ("fit", AtomicString::ConstructFromLiteral));
2805 return fitState;
2806 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002807 case RegionEmpty: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002808 DEFINE_STATIC_LOCAL(AtomicString, emptyState, ("empty", AtomicString::ConstructFromLiteral));
2809 return emptyState;
2810 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002811 case RegionOverset: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002812 DEFINE_STATIC_LOCAL(AtomicString, overflowState, ("overset", AtomicString::ConstructFromLiteral));
2813 return overflowState;
2814 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002815 case RegionUndefined:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002816 return undefinedState;
2817 }
2818
2819 ASSERT_NOT_REACHED();
2820 return undefinedState;
2821}
2822
2823Vector<RefPtr<Range> > Element::webkitGetRegionFlowRanges() const
2824{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002825 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002826
2827 Vector<RefPtr<Range> > rangeObjects;
2828 if (RuntimeEnabledFeatures::cssRegionsEnabled() && renderer() && renderer()->isRenderRegion()) {
2829 RenderRegion* region = toRenderRegion(renderer());
2830 if (region->isValid())
2831 region->getRanges(rangeObjects);
2832 }
2833
2834 return rangeObjects;
2835}
2836
2837#ifndef NDEBUG
2838bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
2839{
2840 if (name == HTMLNames::styleAttr)
2841 return false;
2842
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002843 if (isSVGElement())
2844 return !static_cast<const SVGElement*>(this)->isAnimatableAttribute(name);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002845
2846 return true;
2847}
2848#endif
2849
2850#ifdef DUMP_NODE_STATISTICS
2851bool Element::hasNamedNodeMap() const
2852{
2853 return hasRareData() && elementRareData()->attributeMap();
2854}
2855#endif
2856
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002857inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002858{
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002859 if (!inDocument() || isInShadowTree())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002860 return;
2861
2862 if (oldName == newName)
2863 return;
2864
Ben Murdochdf957042013-08-06 11:01:27 +01002865 if (shouldRegisterAsNamedItem())
2866 updateNamedItemRegistration(oldName, newName);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002867}
2868
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002869inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002870{
2871 if (!isInTreeScope())
2872 return;
2873
2874 if (oldId == newId)
2875 return;
2876
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002877 updateId(treeScope(), oldId, newId);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002878}
2879
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002880inline void Element::updateId(TreeScope& scope, const AtomicString& oldId, const AtomicString& newId)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002881{
2882 ASSERT(isInTreeScope());
2883 ASSERT(oldId != newId);
2884
2885 if (!oldId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002886 scope.removeElementById(oldId, this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002887 if (!newId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002888 scope.addElementById(newId, this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002889
Ben Murdochdf957042013-08-06 11:01:27 +01002890 if (shouldRegisterAsExtraNamedItem())
2891 updateExtraNamedItemRegistration(oldId, newId);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002892}
2893
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002894void Element::updateLabel(TreeScope& scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002895{
2896 ASSERT(hasTagName(labelTag));
2897
2898 if (!inDocument())
2899 return;
2900
2901 if (oldForAttributeValue == newForAttributeValue)
2902 return;
2903
2904 if (!oldForAttributeValue.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002905 scope.removeLabel(oldForAttributeValue, toHTMLLabelElement(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002906 if (!newForAttributeValue.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002907 scope.addLabel(newForAttributeValue, toHTMLLabelElement(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002908}
2909
Ben Murdoch7757ec22013-07-23 11:17:36 +01002910static bool hasSelectorForAttribute(Document* document, const AtomicString& localName)
2911{
2912 return document->styleResolver() && document->styleResolver()->ruleFeatureSet().hasSelectorForAttribute(localName);
2913}
2914
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002915void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
2916{
2917 if (isIdAttributeName(name))
2918 updateId(oldValue, newValue);
2919 else if (name == HTMLNames::nameAttr)
2920 updateName(oldValue, newValue);
2921 else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002922 TreeScope& scope = treeScope();
2923 if (scope.shouldCacheLabelsByForAttribute())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002924 updateLabel(scope, oldValue, newValue);
2925 }
2926
2927 if (oldValue != newValue) {
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00002928 if (inActiveDocument() && hasSelectorForAttribute(&document(), name.localName()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002929 setNeedsStyleRecalc();
Ben Murdoche69819b2013-07-17 14:56:49 +01002930
2931 if (isUpgradedCustomElement())
Ben Murdoch83750172013-07-24 10:36:59 +01002932 CustomElement::attributeDidChange(this, name.localName(), oldValue, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002933 }
2934
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00002935 if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(*this, name))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002936 recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue));
2937
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002938 InspectorInstrumentation::willModifyDOMAttr(this, oldValue, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002939}
2940
2941void Element::didAddAttribute(const QualifiedName& name, const AtomicString& value)
2942{
2943 attributeChanged(name, value);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002944 InspectorInstrumentation::didModifyDOMAttr(this, name.localName(), value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002945 dispatchSubtreeModifiedEvent();
2946}
2947
2948void Element::didModifyAttribute(const QualifiedName& name, const AtomicString& value)
2949{
2950 attributeChanged(name, value);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002951 InspectorInstrumentation::didModifyDOMAttr(this, name.localName(), value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002952 // Do not dispatch a DOMSubtreeModified event here; see bug 81141.
2953}
2954
2955void Element::didRemoveAttribute(const QualifiedName& name)
2956{
2957 attributeChanged(name, nullAtom);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002958 InspectorInstrumentation::didRemoveDOMAttr(this, name.localName());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002959 dispatchSubtreeModifiedEvent();
2960}
2961
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002962void Element::didMoveToNewDocument(Document& oldDocument)
Ben Murdoche69819b2013-07-17 14:56:49 +01002963{
2964 Node::didMoveToNewDocument(oldDocument);
2965
2966 // If the documents differ by quirks mode then they differ by case sensitivity
2967 // for class and id names so we need to go through the attribute change logic
2968 // to pick up the new casing in the ElementData.
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002969 if (oldDocument.inQuirksMode() != document().inQuirksMode()) {
Ben Murdoche69819b2013-07-17 14:56:49 +01002970 if (hasID())
2971 setIdAttribute(getIdAttribute());
2972 if (hasClass())
2973 setAttribute(HTMLNames::classAttr, getClassAttribute());
2974 }
2975}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002976
Ben Murdochdf957042013-08-06 11:01:27 +01002977void Element::updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName)
2978{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002979 if (!document().isHTMLDocument())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002980 return;
Ben Murdochdf957042013-08-06 11:01:27 +01002981
2982 if (!oldName.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002983 toHTMLDocument(document()).removeNamedItem(oldName);
Ben Murdochdf957042013-08-06 11:01:27 +01002984
2985 if (!newName.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002986 toHTMLDocument(document()).addNamedItem(newName);
Ben Murdochdf957042013-08-06 11:01:27 +01002987}
2988
2989void Element::updateExtraNamedItemRegistration(const AtomicString& oldId, const AtomicString& newId)
2990{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002991 if (!document().isHTMLDocument())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002992 return;
Ben Murdochdf957042013-08-06 11:01:27 +01002993
2994 if (!oldId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002995 toHTMLDocument(document()).removeExtraNamedItem(oldId);
Ben Murdochdf957042013-08-06 11:01:27 +01002996
2997 if (!newId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002998 toHTMLDocument(document()).addExtraNamedItem(newId);
Ben Murdochdf957042013-08-06 11:01:27 +01002999}
3000
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003001PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
3002{
3003 if (HTMLCollection* collection = cachedHTMLCollection(type))
3004 return collection;
3005
3006 RefPtr<HTMLCollection> collection;
3007 if (type == TableRows) {
3008 ASSERT(hasTagName(tableTag));
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003009 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003010 } else if (type == SelectOptions) {
3011 ASSERT(hasTagName(selectTag));
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003012 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003013 } else if (type == FormControls) {
3014 ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003015 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003016 }
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003017 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003018}
3019
Ben Murdoch591b9582013-07-10 11:41:44 +01003020static void scheduleLayerUpdateCallback(Node* node)
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003021{
Ben Murdoche69819b2013-07-17 14:56:49 +01003022 // Notify the renderer even is the styles are identical since it may need to
3023 // create or destroy a RenderLayer.
3024 node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003025}
3026
Ben Murdoch591b9582013-07-10 11:41:44 +01003027void Element::scheduleLayerUpdate()
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003028{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003029 if (document().inStyleRecalc())
3030 PostAttachCallbacks::queueCallback(scheduleLayerUpdateCallback, this);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003031 else
Ben Murdoche69819b2013-07-17 14:56:49 +01003032 scheduleLayerUpdateCallback(this);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003033}
3034
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003035HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
3036{
3037 return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0;
3038}
3039
3040IntSize Element::savedLayerScrollOffset() const
3041{
3042 return hasRareData() ? elementRareData()->savedLayerScrollOffset() : IntSize();
3043}
3044
3045void Element::setSavedLayerScrollOffset(const IntSize& size)
3046{
3047 if (size.isZero() && !hasRareData())
3048 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003049 ensureElementRareData().setSavedLayerScrollOffset(size);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003050}
3051
3052PassRefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
3053{
3054 if (AttrNodeList* attrNodeList = attrNodeListForElement(this))
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003055 return findAttrNodeInList(*attrNodeList, name);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003056 return 0;
3057}
3058
3059PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name)
3060{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003061 AttrNodeList& attrNodeList = ensureAttrNodeListForElement(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003062 RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
3063 if (!attrNode) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003064 attrNode = Attr::create(*this, name);
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003065 treeScope().adoptIfNeeded(*attrNode);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003066 attrNodeList.append(attrNode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003067 }
3068 return attrNode.release();
3069}
3070
3071void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value)
3072{
3073 ASSERT(hasSyntheticAttrChildNodes());
3074 attrNode->detachFromElementWithValue(value);
3075
3076 AttrNodeList* attrNodeList = attrNodeListForElement(this);
3077 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
3078 if (attrNodeList->at(i)->qualifiedName() == attrNode->qualifiedName()) {
3079 attrNodeList->remove(i);
3080 if (attrNodeList->isEmpty())
3081 removeAttrNodeListForElement(this);
3082 return;
3083 }
3084 }
3085 ASSERT_NOT_REACHED();
3086}
3087
3088void Element::detachAllAttrNodesFromElement()
3089{
3090 AttrNodeList* attrNodeList = attrNodeListForElement(this);
3091 ASSERT(attrNodeList);
3092
3093 for (unsigned i = 0; i < attributeCount(); ++i) {
3094 const Attribute* attribute = attributeItem(i);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003095 if (RefPtr<Attr> attrNode = findAttrNodeInList(*attrNodeList, attribute->name()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003096 attrNode->detachFromElementWithValue(attribute->value());
3097 }
3098
3099 removeAttrNodeListForElement(this);
3100}
3101
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003102void Element::willRecalcStyle(StyleRecalcChange)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003103{
3104 ASSERT(hasCustomStyleCallbacks());
3105}
3106
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003107void Element::didRecalcStyle(StyleRecalcChange)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003108{
3109 ASSERT(hasCustomStyleCallbacks());
3110}
3111
3112
3113PassRefPtr<RenderStyle> Element::customStyleForRenderer()
3114{
3115 ASSERT(hasCustomStyleCallbacks());
3116 return 0;
3117}
3118
3119void Element::cloneAttributesFromElement(const Element& other)
3120{
3121 if (hasSyntheticAttrChildNodes())
3122 detachAllAttrNodesFromElement();
3123
3124 other.synchronizeAllAttributes();
3125 if (!other.m_elementData) {
3126 m_elementData.clear();
3127 return;
3128 }
3129
3130 const AtomicString& oldID = getIdAttribute();
3131 const AtomicString& newID = other.getIdAttribute();
3132
3133 if (!oldID.isNull() || !newID.isNull())
3134 updateId(oldID, newID);
3135
3136 const AtomicString& oldName = getNameAttribute();
3137 const AtomicString& newName = other.getNameAttribute();
3138
3139 if (!oldName.isNull() || !newName.isNull())
3140 updateName(oldName, newName);
3141
Ben Murdoche69819b2013-07-17 14:56:49 +01003142 // Quirks mode makes class and id not case sensitive. We can't share the ElementData
3143 // if the idForStyleResolution and the className need different casing.
3144 bool ownerDocumentsHaveDifferentCaseSensitivity = false;
3145 if (other.hasClass() || other.hasID())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003146 ownerDocumentsHaveDifferentCaseSensitivity = other.document().inQuirksMode() != document().inQuirksMode();
Ben Murdoche69819b2013-07-17 14:56:49 +01003147
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003148 // If 'other' has a mutable ElementData, convert it to an immutable one so we can share it between both elements.
Ben Murdoche69819b2013-07-17 14:56:49 +01003149 // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes,
3150 // and sharing the data won't result in different case sensitivity of class or id.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003151 if (other.m_elementData->isUnique()
Ben Murdoche69819b2013-07-17 14:56:49 +01003152 && !ownerDocumentsHaveDifferentCaseSensitivity
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003153 && !other.m_elementData->presentationAttributeStyle()
3154 && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper()))
3155 const_cast<Element&>(other).m_elementData = static_cast<const UniqueElementData*>(other.m_elementData.get())->makeShareableCopy();
3156
Ben Murdoche69819b2013-07-17 14:56:49 +01003157 if (!other.m_elementData->isUnique() && !ownerDocumentsHaveDifferentCaseSensitivity)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003158 m_elementData = other.m_elementData;
3159 else
3160 m_elementData = other.m_elementData->makeUniqueCopy();
3161
3162 for (unsigned i = 0; i < m_elementData->length(); ++i) {
3163 const Attribute* attribute = const_cast<const ElementData*>(m_elementData.get())->attributeItem(i);
3164 attributeChangedFromParserOrByCloning(attribute->name(), attribute->value(), ModifiedByCloning);
3165 }
3166}
3167
3168void Element::cloneDataFromElement(const Element& other)
3169{
3170 cloneAttributesFromElement(other);
3171 copyNonAttributePropertiesFromElement(other);
3172}
3173
3174void Element::createUniqueElementData()
3175{
3176 if (!m_elementData)
3177 m_elementData = UniqueElementData::create();
3178 else {
3179 ASSERT(!m_elementData->isUnique());
3180 m_elementData = static_cast<ShareableElementData*>(m_elementData.get())->makeUniqueCopy();
3181 }
3182}
3183
Ben Murdoch1fad5ca2013-08-07 11:05:11 +01003184InputMethodContext* Element::inputMethodContext()
Torne (Richard Coles)81a51572013-05-13 16:52:28 +01003185{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003186 return ensureElementRareData().ensureInputMethodContext(toHTMLElement(this));
Torne (Richard Coles)81a51572013-05-13 16:52:28 +01003187}
3188
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003189bool Element::hasPendingResources() const
3190{
3191 return hasRareData() && elementRareData()->hasPendingResources();
3192}
3193
3194void Element::setHasPendingResources()
3195{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003196 ensureElementRareData().setHasPendingResources(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003197}
3198
3199void Element::clearHasPendingResources()
3200{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003201 ensureElementRareData().setHasPendingResources(false);
Ben Murdoch591b9582013-07-10 11:41:44 +01003202}
3203
3204void Element::synchronizeStyleAttributeInternal() const
3205{
3206 ASSERT(isStyledElement());
3207 ASSERT(elementData());
3208 ASSERT(elementData()->m_styleAttributeIsDirty);
3209 elementData()->m_styleAttributeIsDirty = false;
3210 if (const StylePropertySet* inlineStyle = this->inlineStyle())
3211 const_cast<Element*>(this)->setSynchronizedLazyAttribute(styleAttr, inlineStyle->asText());
3212}
3213
3214CSSStyleDeclaration* Element::style()
3215{
3216 if (!isStyledElement())
3217 return 0;
3218 return ensureMutableInlineStyle()->ensureInlineCSSStyleDeclaration(this);
3219}
3220
3221MutableStylePropertySet* Element::ensureMutableInlineStyle()
3222{
3223 ASSERT(isStyledElement());
3224 RefPtr<StylePropertySet>& inlineStyle = ensureUniqueElementData()->m_inlineStyle;
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003225 if (!inlineStyle) {
3226 CSSParserMode mode = (!isHTMLElement() || document().inQuirksMode()) ? HTMLQuirksMode : HTMLStandardMode;
3227 inlineStyle = MutableStylePropertySet::create(mode);
3228 }
Ben Murdoch591b9582013-07-10 11:41:44 +01003229 else if (!inlineStyle->isMutable())
3230 inlineStyle = inlineStyle->mutableCopy();
3231 ASSERT(inlineStyle->isMutable());
3232 return static_cast<MutableStylePropertySet*>(inlineStyle.get());
3233}
3234
3235PropertySetCSSStyleDeclaration* Element::inlineStyleCSSOMWrapper()
3236{
3237 if (!inlineStyle() || !inlineStyle()->hasCSSOMWrapper())
3238 return 0;
3239 PropertySetCSSStyleDeclaration* cssomWrapper = ensureMutableInlineStyle()->cssStyleDeclaration();
3240 ASSERT(cssomWrapper && cssomWrapper->parentElement() == this);
3241 return cssomWrapper;
3242}
3243
3244inline void Element::setInlineStyleFromString(const AtomicString& newStyleString)
3245{
3246 ASSERT(isStyledElement());
3247 RefPtr<StylePropertySet>& inlineStyle = elementData()->m_inlineStyle;
3248
3249 // Avoid redundant work if we're using shared attribute data with already parsed inline style.
3250 if (inlineStyle && !elementData()->isUnique())
3251 return;
3252
3253 // We reconstruct the property set instead of mutating if there is no CSSOM wrapper.
3254 // This makes wrapperless property sets immutable and so cacheable.
3255 if (inlineStyle && !inlineStyle->isMutable())
3256 inlineStyle.clear();
3257
3258 if (!inlineStyle) {
3259 inlineStyle = CSSParser::parseInlineStyleDeclaration(newStyleString, this);
3260 } else {
3261 ASSERT(inlineStyle->isMutable());
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003262 static_pointer_cast<MutableStylePropertySet>(inlineStyle)->parseDeclaration(newStyleString, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003263 }
3264}
3265
3266void Element::styleAttributeChanged(const AtomicString& newStyleString, AttributeModificationReason modificationReason)
3267{
3268 ASSERT(isStyledElement());
3269 WTF::OrdinalNumber startLineNumber = WTF::OrdinalNumber::beforeFirst();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003270 if (document().scriptableDocumentParser() && !document().isInDocumentWrite())
3271 startLineNumber = document().scriptableDocumentParser()->lineNumber();
Ben Murdoch591b9582013-07-10 11:41:44 +01003272
3273 if (newStyleString.isNull()) {
3274 if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
3275 cssomWrapper->clearParentElement();
3276 ensureUniqueElementData()->m_inlineStyle.clear();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003277 } else if (modificationReason == ModifiedByCloning || document().contentSecurityPolicy()->allowInlineStyle(document().url(), startLineNumber)) {
Ben Murdoch591b9582013-07-10 11:41:44 +01003278 setInlineStyleFromString(newStyleString);
3279 }
3280
3281 elementData()->m_styleAttributeIsDirty = false;
3282
Ben Murdoche69819b2013-07-17 14:56:49 +01003283 setNeedsStyleRecalc(LocalStyleChange);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003284 InspectorInstrumentation::didInvalidateStyleAttr(this);
Ben Murdoch591b9582013-07-10 11:41:44 +01003285}
3286
3287void Element::inlineStyleChanged()
3288{
3289 ASSERT(isStyledElement());
Ben Murdoche69819b2013-07-17 14:56:49 +01003290 setNeedsStyleRecalc(LocalStyleChange);
Ben Murdoch591b9582013-07-10 11:41:44 +01003291 ASSERT(elementData());
3292 elementData()->m_styleAttributeIsDirty = true;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003293 InspectorInstrumentation::didInvalidateStyleAttr(this);
Ben Murdoch591b9582013-07-10 11:41:44 +01003294}
3295
3296bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
3297{
3298 ASSERT(isStyledElement());
3299 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
3300 inlineStyleChanged();
3301 return true;
3302}
3303
3304bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
3305{
3306 ASSERT(isStyledElement());
3307 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
3308 inlineStyleChanged();
3309 return true;
3310}
3311
3312bool Element::setInlineStyleProperty(CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit, bool important)
3313{
3314 ASSERT(isStyledElement());
3315 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createValue(value, unit), important);
3316 inlineStyleChanged();
3317 return true;
3318}
3319
3320bool Element::setInlineStyleProperty(CSSPropertyID propertyID, const String& value, bool important)
3321{
3322 ASSERT(isStyledElement());
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003323 bool changes = ensureMutableInlineStyle()->setProperty(propertyID, value, important, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003324 if (changes)
3325 inlineStyleChanged();
3326 return changes;
3327}
3328
3329bool Element::removeInlineStyleProperty(CSSPropertyID propertyID)
3330{
3331 ASSERT(isStyledElement());
3332 if (!inlineStyle())
3333 return false;
3334 bool changes = ensureMutableInlineStyle()->removeProperty(propertyID);
3335 if (changes)
3336 inlineStyleChanged();
3337 return changes;
3338}
3339
3340void Element::removeAllInlineStyleProperties()
3341{
3342 ASSERT(isStyledElement());
3343 if (!inlineStyle() || inlineStyle()->isEmpty())
3344 return;
3345 ensureMutableInlineStyle()->clear();
3346 inlineStyleChanged();
3347}
3348
3349void Element::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
3350{
3351 ASSERT(isStyledElement());
3352 if (const StylePropertySet* inlineStyle = elementData() ? elementData()->inlineStyle() : 0)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003353 inlineStyle->addSubresourceStyleURLs(urls, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003354}
3355
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003356void Element::updatePresentationAttributeStyle()
Ben Murdoch591b9582013-07-10 11:41:44 +01003357{
Ben Murdoch591b9582013-07-10 11:41:44 +01003358 // ShareableElementData doesn't store presentation attribute style, so make sure we have a UniqueElementData.
3359 UniqueElementData* elementData = ensureUniqueElementData();
Ben Murdoch591b9582013-07-10 11:41:44 +01003360 elementData->m_presentationAttributeStyleIsDirty = false;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003361 elementData->m_presentationAttributeStyle = computePresentationAttributeStyle(*this);
Ben Murdoch591b9582013-07-10 11:41:44 +01003362}
3363
3364void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, CSSValueID identifier)
3365{
3366 ASSERT(isStyledElement());
3367 style->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier));
3368}
3369
3370void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit)
3371{
3372 ASSERT(isStyledElement());
3373 style->setProperty(propertyID, cssValuePool().createValue(value, unit));
3374}
3375
3376void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, const String& value)
3377{
3378 ASSERT(isStyledElement());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01003379 style->setProperty(propertyID, value, false);
Ben Murdoch591b9582013-07-10 11:41:44 +01003380}
3381
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003382bool Element::supportsStyleSharing() const
3383{
3384 if (!isStyledElement() || !parentElement())
3385 return false;
3386 // If the element has inline style it is probably unique.
3387 if (inlineStyle())
3388 return false;
3389 if (isSVGElement() && toSVGElement(this)->animatedSMILStyleProperties())
3390 return false;
3391 // Ids stop style sharing if they show up in the stylesheets.
3392 if (hasID() && document().styleResolver()->hasRulesForId(idForStyleResolution()))
3393 return false;
3394 // Active and hovered elements always make a chain towards the document node
3395 // and no siblings or cousins will have the same state.
3396 if (hovered())
3397 return false;
3398 if (active())
3399 return false;
3400 if (focused())
3401 return false;
3402 if (!parentElement()->childrenSupportStyleSharing())
3403 return false;
3404 if (hasScopedHTMLStyleChild())
3405 return false;
3406 if (this == document().cssTarget())
3407 return false;
3408 if (isHTMLElement() && toHTMLElement(this)->hasDirectionAuto())
3409 return false;
3410 if (hasActiveAnimations())
3411 return false;
3412 if (shadow() && shadow()->containsActiveStyles())
3413 return false;
3414 // Turn off style sharing for elements that can gain layers for reasons outside of the style system.
3415 // See comments in RenderObject::setStyle().
3416 // FIXME: Why does gaining a layer from outside the style system require disabling sharing?
3417 if (hasTagName(iframeTag)
3418 || hasTagName(frameTag)
3419 || hasTagName(embedTag)
3420 || hasTagName(objectTag)
3421 || hasTagName(appletTag)
3422 || hasTagName(canvasTag))
3423 return false;
3424 // FIXME: We should share style for option and optgroup whenever possible.
3425 // Before doing so, we need to resolve issues in HTMLSelectElement::recalcListItems
3426 // and RenderMenuList::setText. See also https://bugs.webkit.org/show_bug.cgi?id=88405
3427 if (hasTagName(optionTag) || hasTagName(optgroupTag))
3428 return false;
3429 if (FullscreenElementStack::isActiveFullScreenElement(this))
3430 return false;
3431 return true;
3432}
3433
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003434} // namespace WebCore