blob: 36cdb7022590bc156fd843753bb02cae7ec3a14e [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)19cde672013-11-06 12:28:04 +000075#include "core/editing/markup.h"
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010076#include "core/events/EventDispatcher.h"
77#include "core/events/FocusEvent.h"
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +010078#include "core/frame/ContentSecurityPolicy.h"
79#include "core/frame/Frame.h"
80#include "core/frame/FrameView.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010081#include "core/html/ClassList.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010082#include "core/html/HTMLCollection.h"
83#include "core/html/HTMLDocument.h"
84#include "core/html/HTMLElement.h"
85#include "core/html/HTMLFormControlsCollection.h"
86#include "core/html/HTMLFrameOwnerElement.h"
87#include "core/html/HTMLLabelElement.h"
88#include "core/html/HTMLOptionsCollection.h"
89#include "core/html/HTMLTableRowsCollection.h"
Torne (Richard Coles)19cde672013-11-06 12:28:04 +000090#include "core/html/HTMLTemplateElement.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010091#include "core/html/parser/HTMLParserIdioms.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010092#include "core/page/FocusController.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010093#include "core/page/Page.h"
94#include "core/page/PointerLockController.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010095#include "core/rendering/FlowThreadController.h"
96#include "core/rendering/RenderRegion.h"
97#include "core/rendering/RenderView.h"
98#include "core/rendering/RenderWidget.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010099#include "core/svg/SVGDocumentExtensions.h"
100#include "core/svg/SVGElement.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100101#include "wtf/BitVector.h"
Ben Murdoch591b9582013-07-10 11:41:44 +0100102#include "wtf/HashFunctions.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100103#include "wtf/text/CString.h"
Ben Murdoch591b9582013-07-10 11:41:44 +0100104#include "wtf/text/TextPosition.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100105
106namespace WebCore {
107
108using namespace HTMLNames;
109using namespace XMLNames;
110
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100111class StyleResolverParentPusher {
112public:
113 StyleResolverParentPusher(Element* parent)
114 : m_parent(parent)
115 , m_pushedStyleResolver(0)
116 {
117 }
118 void push()
119 {
120 if (m_pushedStyleResolver)
121 return;
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100122 m_pushedStyleResolver = m_parent->document().styleResolver();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100123 m_pushedStyleResolver->pushParentElement(m_parent);
124 }
125 ~StyleResolverParentPusher()
126 {
127
128 if (!m_pushedStyleResolver)
129 return;
130
131 // This tells us that our pushed style selector is in a bad state,
132 // so we should just bail out in that scenario.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100133 ASSERT(m_pushedStyleResolver == m_parent->document().styleResolver());
134 if (m_pushedStyleResolver != m_parent->document().styleResolver())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100135 return;
136
137 m_pushedStyleResolver->popParentElement(m_parent);
138 }
139
140private:
141 Element* m_parent;
142 StyleResolver* m_pushedStyleResolver;
143};
144
145typedef Vector<RefPtr<Attr> > AttrNodeList;
146typedef HashMap<Element*, OwnPtr<AttrNodeList> > AttrNodeListMap;
147
148static AttrNodeListMap& attrNodeListMap()
149{
150 DEFINE_STATIC_LOCAL(AttrNodeListMap, map, ());
151 return map;
152}
153
154static AttrNodeList* attrNodeListForElement(Element* element)
155{
156 if (!element->hasSyntheticAttrChildNodes())
157 return 0;
158 ASSERT(attrNodeListMap().contains(element));
159 return attrNodeListMap().get(element);
160}
161
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100162static AttrNodeList& ensureAttrNodeListForElement(Element* element)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100163{
164 if (element->hasSyntheticAttrChildNodes()) {
165 ASSERT(attrNodeListMap().contains(element));
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100166 return *attrNodeListMap().get(element);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100167 }
168 ASSERT(!attrNodeListMap().contains(element));
169 element->setHasSyntheticAttrChildNodes(true);
170 AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList));
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100171 return *result.iterator->value;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100172}
173
174static void removeAttrNodeListForElement(Element* element)
175{
176 ASSERT(element->hasSyntheticAttrChildNodes());
177 ASSERT(attrNodeListMap().contains(element));
178 attrNodeListMap().remove(element);
179 element->setHasSyntheticAttrChildNodes(false);
180}
181
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100182static Attr* findAttrNodeInList(AttrNodeList& attrNodeList, const QualifiedName& name)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100183{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100184 for (unsigned i = 0; i < attrNodeList.size(); ++i) {
185 if (attrNodeList[i]->qualifiedName() == name)
186 return attrNodeList[i].get();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100187 }
188 return 0;
189}
190
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100191PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document)
192{
193 return adoptRef(new Element(tagName, document, CreateElement));
194}
195
196Element::~Element()
197{
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000198 // When the document is not destroyed, an element that was part of a named flow
199 // content nodes should have been removed from the content nodes collection
200 // and the inNamedFlow flag reset.
201 ASSERT(!document().renderView() || !inNamedFlow());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100202
Ben Murdoch591b9582013-07-10 11:41:44 +0100203 if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
204 cssomWrapper->clearParentElement();
205
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100206 if (hasRareData()) {
207 ElementRareData* data = elementRareData();
208 data->setPseudoElement(BEFORE, 0);
209 data->setPseudoElement(AFTER, 0);
Ben Murdoche69819b2013-07-17 14:56:49 +0100210 data->setPseudoElement(BACKDROP, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100211 data->clearShadow();
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100212
213 if (RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
214 if (ActiveAnimations* activeAnimations = data->activeAnimations())
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000215 activeAnimations->cssAnimations().cancel();
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100216 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100217 }
218
Ben Murdoch83750172013-07-24 10:36:59 +0100219 if (isCustomElement())
220 CustomElement::wasDestroyed(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100221
222 if (hasSyntheticAttrChildNodes())
223 detachAllAttrNodesFromElement();
224
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100225 if (hasPendingResources()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100226 document().accessSVGExtensions()->removeElementFromPendingResources(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100227 ASSERT(!hasPendingResources());
228 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100229}
230
231inline ElementRareData* Element::elementRareData() const
232{
233 ASSERT(hasRareData());
234 return static_cast<ElementRareData*>(rareData());
235}
236
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100237inline ElementRareData& Element::ensureElementRareData()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100238{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100239 return static_cast<ElementRareData&>(ensureRareData());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100240}
241
242void Element::clearTabIndexExplicitlyIfNeeded()
243{
244 if (hasRareData())
245 elementRareData()->clearTabIndexExplicitly();
246}
247
248void Element::setTabIndexExplicitly(short tabIndex)
249{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100250 ensureElementRareData().setTabIndexExplicitly(tabIndex);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100251}
252
253bool Element::supportsFocus() const
254{
255 return hasRareData() && elementRareData()->tabIndexSetExplicitly();
256}
257
258short Element::tabIndex() const
259{
260 return hasRareData() ? elementRareData()->tabIndex() : 0;
261}
262
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100263bool Element::rendererIsFocusable() const
264{
265 // Elements in canvas fallback content are not rendered, but they are allowed to be
266 // focusable as long as their canvas is displayed and visible.
267 if (isInCanvasSubtree()) {
268 const Element* e = this;
269 while (e && !e->hasLocalName(canvasTag))
270 e = e->parentElement();
271 ASSERT(e);
272 return e->renderer() && e->renderer()->style()->visibility() == VISIBLE;
273 }
274
275 // FIXME: These asserts should be in Node::isFocusable, but there are some
Ben Murdoche69819b2013-07-17 14:56:49 +0100276 // callsites like Document::setFocusedElement that would currently fail on
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100277 // them. See crbug.com/251163
278 if (renderer()) {
279 ASSERT(!renderer()->needsLayout());
280 } else {
281 // We can't just use needsStyleRecalc() because if the node is in a
282 // display:none tree it might say it needs style recalc but the whole
283 // document is actually up to date.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100284 ASSERT(!document().childNeedsStyleRecalc());
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100285 }
286
287 // FIXME: Even if we are not visible, we might have a child that is visible.
288 // Hyatt wants to fix that some day with a "has visible content" flag or the like.
289 if (!renderer() || renderer()->style()->visibility() != VISIBLE)
290 return false;
291
292 return true;
293}
294
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100295PassRefPtr<Node> Element::cloneNode(bool deep)
296{
297 return deep ? cloneElementWithChildren() : cloneElementWithoutChildren();
298}
299
300PassRefPtr<Element> Element::cloneElementWithChildren()
301{
302 RefPtr<Element> clone = cloneElementWithoutChildren();
303 cloneChildNodes(clone.get());
304 return clone.release();
305}
306
307PassRefPtr<Element> Element::cloneElementWithoutChildren()
308{
309 RefPtr<Element> clone = cloneElementWithoutAttributesAndChildren();
310 // This will catch HTML elements in the wrong namespace that are not correctly copied.
311 // This is a sanity check as HTML overloads some of the DOM methods.
312 ASSERT(isHTMLElement() == clone->isHTMLElement());
313
314 clone->cloneDataFromElement(*this);
315 return clone.release();
316}
317
318PassRefPtr<Element> Element::cloneElementWithoutAttributesAndChildren()
319{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100320 return document().createElement(tagQName(), false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100321}
322
323PassRefPtr<Attr> Element::detachAttribute(size_t index)
324{
325 ASSERT(elementData());
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100326 const Attribute* attribute = elementData()->attributeItem(index);
327 RefPtr<Attr> attrNode = attrIfExists(attribute->name());
328 if (attrNode)
329 detachAttrNodeAtIndex(attrNode.get(), index);
330 else {
331 attrNode = Attr::create(document(), attribute->name(), attribute->value());
332 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
333 }
334 return attrNode.release();
335}
336
337void Element::detachAttrNodeAtIndex(Attr* attr, size_t index)
338{
339 ASSERT(attr);
340 ASSERT(elementData());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100341
342 const Attribute* attribute = elementData()->attributeItem(index);
343 ASSERT(attribute);
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100344 ASSERT(attribute->name() == attr->qualifiedName());
345 detachAttrNodeFromElementWithValue(attr, attribute->value());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100346 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100347}
348
349void Element::removeAttribute(const QualifiedName& name)
350{
351 if (!elementData())
352 return;
353
354 size_t index = elementData()->getAttributeItemIndex(name);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100355 if (index == kNotFound)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100356 return;
357
358 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
359}
360
361void Element::setBooleanAttribute(const QualifiedName& name, bool value)
362{
363 if (value)
364 setAttribute(name, emptyAtom);
365 else
366 removeAttribute(name);
367}
368
369NamedNodeMap* Element::attributes() const
370{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100371 ElementRareData& rareData = const_cast<Element*>(this)->ensureElementRareData();
372 if (NamedNodeMap* attributeMap = rareData.attributeMap())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100373 return attributeMap;
374
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100375 rareData.setAttributeMap(NamedNodeMap::create(const_cast<Element*>(this)));
376 return rareData.attributeMap();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100377}
378
Ben Murdoch83750172013-07-24 10:36:59 +0100379ActiveAnimations* Element::activeAnimations() const
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100380{
Ben Murdoch83750172013-07-24 10:36:59 +0100381 if (hasActiveAnimations())
382 return elementRareData()->activeAnimations();
383 return 0;
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100384}
385
Ben Murdoch83750172013-07-24 10:36:59 +0100386ActiveAnimations* Element::ensureActiveAnimations()
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100387{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100388 ElementRareData& rareData = ensureElementRareData();
389 if (!rareData.activeAnimations())
390 rareData.setActiveAnimations(adoptPtr(new ActiveAnimations()));
391 return rareData.activeAnimations();
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100392}
393
394bool Element::hasActiveAnimations() const
395{
Ben Murdoch83750172013-07-24 10:36:59 +0100396 if (!RuntimeEnabledFeatures::webAnimationsEnabled())
397 return false;
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100398
Ben Murdoch83750172013-07-24 10:36:59 +0100399 if (!hasRareData())
400 return false;
401
402 ActiveAnimations* activeAnimations = elementRareData()->activeAnimations();
403 return activeAnimations && !activeAnimations->isEmpty();
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100404}
405
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100406Node::NodeType Element::nodeType() const
407{
408 return ELEMENT_NODE;
409}
410
411bool Element::hasAttribute(const QualifiedName& name) const
412{
413 return hasAttributeNS(name.namespaceURI(), name.localName());
414}
415
416void Element::synchronizeAllAttributes() const
417{
418 if (!elementData())
419 return;
420 if (elementData()->m_styleAttributeIsDirty) {
421 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100422 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100423 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100424 if (elementData()->m_animatedSVGAttributesAreDirty) {
425 ASSERT(isSVGElement());
426 toSVGElement(this)->synchronizeAnimatedSVGAttribute(anyQName());
427 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100428}
429
430inline void Element::synchronizeAttribute(const QualifiedName& name) const
431{
432 if (!elementData())
433 return;
434 if (UNLIKELY(name == styleAttr && elementData()->m_styleAttributeIsDirty)) {
435 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100436 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100437 return;
438 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100439 if (UNLIKELY(elementData()->m_animatedSVGAttributesAreDirty)) {
440 ASSERT(isSVGElement());
441 toSVGElement(this)->synchronizeAnimatedSVGAttribute(name);
442 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100443}
444
445inline void Element::synchronizeAttribute(const AtomicString& localName) const
446{
447 // This version of synchronizeAttribute() is streamlined for the case where you don't have a full QualifiedName,
448 // e.g when called from DOM API.
449 if (!elementData())
450 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100451 if (elementData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(localName, styleAttr.localName(), shouldIgnoreAttributeCase())) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100452 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100453 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100454 return;
455 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100456 if (elementData()->m_animatedSVGAttributesAreDirty) {
457 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
458 ASSERT(isSVGElement());
459 static_cast<const SVGElement*>(this)->synchronizeAnimatedSVGAttribute(QualifiedName(nullAtom, localName, nullAtom));
460 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100461}
462
463const AtomicString& Element::getAttribute(const QualifiedName& name) const
464{
465 if (!elementData())
466 return nullAtom;
467 synchronizeAttribute(name);
468 if (const Attribute* attribute = getAttributeItem(name))
469 return attribute->value();
470 return nullAtom;
471}
472
Ben Murdoch591b9582013-07-10 11:41:44 +0100473void Element::scrollIntoView(bool alignToTop)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100474{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100475 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100476
477 if (!renderer())
478 return;
479
480 LayoutRect bounds = boundingBox();
481 // Align to the top / bottom and to the closest edge.
482 if (alignToTop)
483 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
484 else
485 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
486}
487
488void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
489{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100490 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100491
492 if (!renderer())
493 return;
494
495 LayoutRect bounds = boundingBox();
496 if (centerIfNeeded)
497 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
498 else
499 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
500}
501
502void Element::scrollByUnits(int units, ScrollGranularity granularity)
503{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100504 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100505
506 if (!renderer())
507 return;
508
509 if (!renderer()->hasOverflowClip())
510 return;
511
512 ScrollDirection direction = ScrollDown;
513 if (units < 0) {
514 direction = ScrollUp;
515 units = -units;
516 }
517 Node* stopNode = this;
518 toRenderBox(renderer())->scroll(direction, granularity, units, &stopNode);
519}
520
521void Element::scrollByLines(int lines)
522{
523 scrollByUnits(lines, ScrollByLine);
524}
525
526void Element::scrollByPages(int pages)
527{
528 scrollByUnits(pages, ScrollByPage);
529}
530
531static float localZoomForRenderer(RenderObject* renderer)
532{
533 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
534 // other out, but the alternative is that we'd have to crawl up the whole render tree every
535 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
536 float zoomFactor = 1;
537 if (renderer->style()->effectiveZoom() != 1) {
538 // Need to find the nearest enclosing RenderObject that set up
539 // a differing zoom, and then we divide our result by it to eliminate the zoom.
540 RenderObject* prev = renderer;
541 for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) {
542 if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) {
543 zoomFactor = prev->style()->zoom();
544 break;
545 }
546 prev = curr;
547 }
548 if (prev->isRenderView())
549 zoomFactor = prev->style()->zoom();
550 }
551 return zoomFactor;
552}
553
554static int adjustForLocalZoom(LayoutUnit value, RenderObject* renderer)
555{
556 float zoomFactor = localZoomForRenderer(renderer);
557 if (zoomFactor == 1)
558 return value;
559 return lroundf(value / zoomFactor);
560}
561
562int Element::offsetLeft()
563{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100564 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100565 if (RenderBoxModelObject* renderer = renderBoxModelObject())
566 return adjustForLocalZoom(renderer->pixelSnappedOffsetLeft(), renderer);
567 return 0;
568}
569
570int Element::offsetTop()
571{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100572 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100573 if (RenderBoxModelObject* renderer = renderBoxModelObject())
574 return adjustForLocalZoom(renderer->pixelSnappedOffsetTop(), renderer);
575 return 0;
576}
577
578int Element::offsetWidth()
579{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100580 document().updateStyleForNodeIfNeeded(this);
Ben Murdoch591b9582013-07-10 11:41:44 +0100581
582 if (RenderBox* renderer = renderBox()) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100583 if (renderer->canDetermineWidthWithoutLayout())
Ben Murdoch591b9582013-07-10 11:41:44 +0100584 return adjustLayoutUnitForAbsoluteZoom(renderer->fixedOffsetWidth(), renderer).round();
585 }
586
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100587 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100588 if (RenderBoxModelObject* renderer = renderBoxModelObject())
589 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetWidth(), renderer).round();
590 return 0;
591}
592
593int Element::offsetHeight()
594{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100595 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100596 if (RenderBoxModelObject* renderer = renderBoxModelObject())
597 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetHeight(), renderer).round();
598 return 0;
599}
600
601Element* Element::bindingsOffsetParent()
602{
603 Element* element = offsetParent();
604 if (!element || !element->isInShadowTree())
605 return element;
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100606 return element->containingShadowRoot()->shouldExposeToBindings() ? element : 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100607}
608
609Element* Element::offsetParent()
610{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100611 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100612 if (RenderObject* renderer = this->renderer())
613 return renderer->offsetParent();
614 return 0;
615}
616
617int Element::clientLeft()
618{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100619 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100620
621 if (RenderBox* renderer = renderBox())
622 return adjustForAbsoluteZoom(roundToInt(renderer->clientLeft()), renderer);
623 return 0;
624}
625
626int Element::clientTop()
627{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100628 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100629
630 if (RenderBox* renderer = renderBox())
631 return adjustForAbsoluteZoom(roundToInt(renderer->clientTop()), renderer);
632 return 0;
633}
634
635int Element::clientWidth()
636{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100637 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100638
639 // When in strict mode, clientWidth for the document element should return the width of the containing frame.
640 // 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 +0100641 bool inQuirksMode = document().inQuirksMode();
642 if ((!inQuirksMode && document().documentElement() == this)
643 || (inQuirksMode && isHTMLElement() && document().body() == this)) {
644 if (FrameView* view = document().view()) {
645 if (RenderView* renderView = document().renderView())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100646 return adjustForAbsoluteZoom(view->layoutSize().width(), renderView);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100647 }
648 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100649
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100650 if (RenderBox* renderer = renderBox())
651 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientWidth(), renderer).round();
652 return 0;
653}
654
655int Element::clientHeight()
656{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100657 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100658
659 // When in strict mode, clientHeight for the document element should return the height of the containing frame.
660 // 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 +0100661 bool inQuirksMode = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100662
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100663 if ((!inQuirksMode && document().documentElement() == this)
664 || (inQuirksMode && isHTMLElement() && document().body() == this)) {
665 if (FrameView* view = document().view()) {
666 if (RenderView* renderView = document().renderView())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100667 return adjustForAbsoluteZoom(view->layoutSize().height(), renderView);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100668 }
669 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100670
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100671 if (RenderBox* renderer = renderBox())
672 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientHeight(), renderer).round();
673 return 0;
674}
675
676int Element::scrollLeft()
677{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100678 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100679
680 if (document().documentElement() == this) {
681 if (document().inQuirksMode())
682 return 0;
683
684 if (FrameView* view = document().view()) {
685 if (RenderView* renderView = document().renderView())
686 return adjustForAbsoluteZoom(view->scrollX(), renderView);
687 }
688 }
689
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100690 if (RenderBox* rend = renderBox())
691 return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
692 return 0;
693}
694
695int Element::scrollTop()
696{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100697 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100698
699 if (document().documentElement() == this) {
700 if (document().inQuirksMode())
701 return 0;
702
703 if (FrameView* view = document().view()) {
704 if (RenderView* renderView = document().renderView())
705 return adjustForAbsoluteZoom(view->scrollY(), renderView);
706 }
707 }
708
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100709 if (RenderBox* rend = renderBox())
710 return adjustForAbsoluteZoom(rend->scrollTop(), rend);
711 return 0;
712}
713
714void Element::setScrollLeft(int newLeft)
715{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100716 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100717
718 if (document().documentElement() == this) {
719 if (document().inQuirksMode())
720 return;
721
722 Frame* frame = document().frame();
723 if (!frame)
724 return;
725 FrameView* view = frame->view();
726 if (!view)
727 return;
728
729 // WHATWG spec says [1]: "If the element is the root element invoke scroll()
730 // with x as first argument and zero as second". Blink intentionally matches
731 // other engine's behaviors here, instead, where the 'y' scroll position is
732 // preversed. See [2].
733 // [1] http://dev.w3.org/csswg/cssom-view/#dom-element-scrollleft
734 // [2] https://www.w3.org/Bugs/Public/show_bug.cgi?id=23448
735 view->setScrollPosition(IntPoint(static_cast<int>(newLeft * frame->pageZoomFactor()), view->scrollY()));
736 }
737
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100738 if (RenderBox* rend = renderBox())
739 rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
740}
741
742void Element::setScrollTop(int newTop)
743{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100744 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100745
746 if (document().documentElement() == this) {
747 if (document().inQuirksMode())
748 return;
749
750 Frame* frame = document().frame();
751 if (!frame)
752 return;
753 FrameView* view = frame->view();
754 if (!view)
755 return;
756
757 // WHATWG spec says [1]: "If the element is the root element invoke scroll()
758 // with zero as first argument and y as second". Blink intentionally
759 // matches other engine's behaviors here, instead, where the 'x' scroll
760 // position is preversed. See [2].
761 // [1] http://dev.w3.org/csswg/cssom-view/#dom-element-scrolltop
762 // [2] https://www.w3.org/Bugs/Public/show_bug.cgi?id=23448
763 view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(newTop * frame->pageZoomFactor())));
764 }
765
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100766 if (RenderBox* rend = renderBox())
767 rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
768}
769
770int Element::scrollWidth()
771{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100772 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100773 if (RenderBox* rend = renderBox())
774 return adjustForAbsoluteZoom(rend->scrollWidth(), rend);
775 return 0;
776}
777
778int Element::scrollHeight()
779{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100780 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100781 if (RenderBox* rend = renderBox())
782 return adjustForAbsoluteZoom(rend->scrollHeight(), rend);
783 return 0;
784}
785
786IntRect Element::boundsInRootViewSpace()
787{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100788 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100789
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100790 FrameView* view = document().view();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100791 if (!view)
792 return IntRect();
793
794 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100795 if (isSVGElement() && renderer()) {
796 // Get the bounding rectangle from the SVG model.
797 SVGElement* svgElement = toSVGElement(this);
798 FloatRect localRect;
799 if (svgElement->getBoundingBox(localRect))
800 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100801 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100802 // Get the bounding rectangle from the box model.
803 if (renderBoxModelObject())
804 renderBoxModelObject()->absoluteQuads(quads);
805 }
806
807 if (quads.isEmpty())
808 return IntRect();
809
810 IntRect result = quads[0].enclosingBoundingBox();
811 for (size_t i = 1; i < quads.size(); ++i)
812 result.unite(quads[i].enclosingBoundingBox());
813
814 result = view->contentsToRootView(result);
815 return result;
816}
817
818PassRefPtr<ClientRectList> Element::getClientRects()
819{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100820 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100821
822 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject();
823 if (!renderBoxModelObject)
824 return ClientRectList::create();
825
826 // FIXME: Handle SVG elements.
827 // FIXME: Handle table/inline-table with a caption.
828
829 Vector<FloatQuad> quads;
830 renderBoxModelObject->absoluteQuads(quads);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100831 document().adjustFloatQuadsForScrollAndAbsoluteZoom(quads, renderBoxModelObject);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100832 return ClientRectList::create(quads);
833}
834
835PassRefPtr<ClientRect> Element::getBoundingClientRect()
836{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100837 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100838
839 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100840 if (isSVGElement() && renderer() && !renderer()->isSVGRoot()) {
841 // Get the bounding rectangle from the SVG model.
842 SVGElement* svgElement = toSVGElement(this);
843 FloatRect localRect;
844 if (svgElement->getBoundingBox(localRect))
845 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100846 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100847 // Get the bounding rectangle from the box model.
848 if (renderBoxModelObject())
849 renderBoxModelObject()->absoluteQuads(quads);
850 }
851
852 if (quads.isEmpty())
853 return ClientRect::create();
854
855 FloatRect result = quads[0].boundingBox();
856 for (size_t i = 1; i < quads.size(); ++i)
857 result.unite(quads[i].boundingBox());
858
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100859 document().adjustFloatRectForScrollAndAbsoluteZoom(result, renderer());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100860 return ClientRect::create(result);
861}
Ben Murdoch591b9582013-07-10 11:41:44 +0100862
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100863IntRect Element::screenRect() const
864{
865 if (!renderer())
866 return IntRect();
867 // FIXME: this should probably respect transforms
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100868 return document().view()->contentsToScreen(renderer()->absoluteBoundingBoxRectIgnoringTransforms());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100869}
870
871const AtomicString& Element::getAttribute(const AtomicString& localName) const
872{
873 if (!elementData())
874 return nullAtom;
875 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100876 if (const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100877 return attribute->value();
878 return nullAtom;
879}
880
881const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
882{
883 return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
884}
885
Ben Murdochdf957042013-08-06 11:01:27 +0100886void Element::setAttribute(const AtomicString& localName, const AtomicString& value, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100887{
888 if (!Document::isValidName(localName)) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100889 es.throwUninformativeAndGenericDOMException(InvalidCharacterError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100890 return;
891 }
892
893 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100894 const AtomicString& caseAdjustedLocalName = shouldIgnoreAttributeCase() ? localName.lower() : localName;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100895
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100896 size_t index = elementData() ? elementData()->getAttributeItemIndex(caseAdjustedLocalName, false) : kNotFound;
897 const QualifiedName& qName = index != kNotFound ? attributeItem(index)->name() : QualifiedName(nullAtom, caseAdjustedLocalName, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100898 setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute);
899}
900
901void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
902{
903 synchronizeAttribute(name);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100904 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : kNotFound;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100905 setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute);
906}
907
908void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value)
909{
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100910 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : kNotFound;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100911 setAttributeInternal(index, name, value, InSynchronizationOfLazyAttribute);
912}
913
914inline void Element::setAttributeInternal(size_t index, const QualifiedName& name, const AtomicString& newValue, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
915{
916 if (newValue.isNull()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100917 if (index != kNotFound)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100918 removeAttributeInternal(index, inSynchronizationOfLazyAttribute);
919 return;
920 }
921
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100922 if (index == kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100923 addAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute);
924 return;
925 }
926
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100927 QualifiedName existingAttributeName = attributeItem(index)->name();
928
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100929 if (!inSynchronizationOfLazyAttribute)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100930 willModifyAttribute(existingAttributeName, attributeItem(index)->value(), newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100931
932 if (newValue != attributeItem(index)->value()) {
933 // If there is an Attr node hooked to this attribute, the Attr::setValue() call below
934 // will write into the ElementData.
935 // FIXME: Refactor this so it makes some sense.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100936 if (RefPtr<Attr> attrNode = inSynchronizationOfLazyAttribute ? 0 : attrIfExists(existingAttributeName))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100937 attrNode->setValue(newValue);
938 else
939 ensureUniqueElementData()->attributeItem(index)->setValue(newValue);
940 }
941
942 if (!inSynchronizationOfLazyAttribute)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100943 didModifyAttribute(existingAttributeName, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100944}
945
946static inline AtomicString makeIdForStyleResolution(const AtomicString& value, bool inQuirksMode)
947{
948 if (inQuirksMode)
949 return value.lower();
950 return value;
951}
952
Ben Murdoch7757ec22013-07-23 11:17:36 +0100953static bool checkNeedsStyleInvalidationForIdChange(const AtomicString& oldId, const AtomicString& newId, const RuleFeatureSet& features)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100954{
955 ASSERT(newId != oldId);
Ben Murdoch7757ec22013-07-23 11:17:36 +0100956 if (!oldId.isEmpty() && features.hasSelectorForId(oldId))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100957 return true;
Ben Murdoch7757ec22013-07-23 11:17:36 +0100958 if (!newId.isEmpty() && features.hasSelectorForId(newId))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100959 return true;
960 return false;
961}
962
Ben Murdoch591b9582013-07-10 11:41:44 +0100963void Element::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100964{
Torne (Richard Coles)19cde672013-11-06 12:28:04 +0000965 if (ElementShadow* parentElementShadow = shadowWhereNodeCanBeDistributed(*this)) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100966 if (shouldInvalidateDistributionWhenAttributeChanged(parentElementShadow, name, newValue))
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100967 parentElementShadow->setNeedsDistributionRecalc();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100968 }
969
970 parseAttribute(name, newValue);
971
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100972 document().incDOMTreeVersion();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100973
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100974 StyleResolver* styleResolver = document().styleResolverIfExists();
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000975 bool testShouldInvalidateStyle = inActiveDocument() && styleResolver && styleChangeType() < SubtreeStyleChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100976 bool shouldInvalidateStyle = false;
977
Ben Murdoch591b9582013-07-10 11:41:44 +0100978 if (isStyledElement() && name == styleAttr) {
979 styleAttributeChanged(newValue, reason);
980 } else if (isStyledElement() && isPresentationAttribute(name)) {
981 elementData()->m_presentationAttributeStyleIsDirty = true;
Ben Murdoche69819b2013-07-17 14:56:49 +0100982 setNeedsStyleRecalc(LocalStyleChange);
Ben Murdoch591b9582013-07-10 11:41:44 +0100983 }
984
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100985 if (isIdAttributeName(name)) {
986 AtomicString oldId = elementData()->idForStyleResolution();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100987 AtomicString newId = makeIdForStyleResolution(newValue, document().inQuirksMode());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100988 if (newId != oldId) {
989 elementData()->setIdForStyleResolution(newId);
Ben Murdoch7757ec22013-07-23 11:17:36 +0100990 shouldInvalidateStyle = testShouldInvalidateStyle && checkNeedsStyleInvalidationForIdChange(oldId, newId, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100991 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100992 } else if (name == classAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100993 classAttributeChanged(newValue);
Ben Murdoch591b9582013-07-10 11:41:44 +0100994 } else if (name == HTMLNames::nameAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100995 setHasName(!newValue.isNull());
Ben Murdoch591b9582013-07-10 11:41:44 +0100996 } else if (name == HTMLNames::pseudoAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100997 shouldInvalidateStyle |= testShouldInvalidateStyle && isInShadowTree();
Ben Murdoch591b9582013-07-10 11:41:44 +0100998 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100999
1000 invalidateNodeListCachesInAncestors(&name, this);
1001
1002 // If there is currently no StyleResolver, we can't be sure that this attribute change won't affect style.
1003 shouldInvalidateStyle |= !styleResolver;
1004
1005 if (shouldInvalidateStyle)
1006 setNeedsStyleRecalc();
1007
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001008 if (AXObjectCache* cache = document().existingAXObjectCache())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001009 cache->handleAttributeChanged(name, this);
1010}
1011
1012inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
1013{
Ben Murdoche69819b2013-07-17 14:56:49 +01001014 if (name == isAttr)
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001015 CustomElementRegistrationContext::setTypeExtension(this, newValue, reason == ModifiedDirectly ? CustomElementRegistrationContext::CreatedByParser : CustomElementRegistrationContext::NotCreatedByParser);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001016 attributeChanged(name, newValue, reason);
1017}
1018
1019template <typename CharacterType>
1020static inline bool classStringHasClassName(const CharacterType* characters, unsigned length)
1021{
1022 ASSERT(length > 0);
1023
1024 unsigned i = 0;
1025 do {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001026 if (isNotHTMLSpace<CharacterType>(characters[i]))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001027 break;
1028 ++i;
1029 } while (i < length);
1030
1031 return i < length;
1032}
1033
1034static inline bool classStringHasClassName(const AtomicString& newClassString)
1035{
1036 unsigned length = newClassString.length();
1037
1038 if (!length)
1039 return false;
1040
1041 if (newClassString.is8Bit())
1042 return classStringHasClassName(newClassString.characters8(), length);
1043 return classStringHasClassName(newClassString.characters16(), length);
1044}
1045
1046template<typename Checker>
1047static bool checkSelectorForClassChange(const SpaceSplitString& changedClasses, const Checker& checker)
1048{
1049 unsigned changedSize = changedClasses.size();
1050 for (unsigned i = 0; i < changedSize; ++i) {
1051 if (checker.hasSelectorForClass(changedClasses[i]))
1052 return true;
1053 }
1054 return false;
1055}
1056
1057template<typename Checker>
1058static bool checkSelectorForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, const Checker& checker)
1059{
1060 unsigned oldSize = oldClasses.size();
1061 if (!oldSize)
1062 return checkSelectorForClassChange(newClasses, checker);
1063 BitVector remainingClassBits;
1064 remainingClassBits.ensureSize(oldSize);
1065 // Class vectors tend to be very short. This is faster than using a hash table.
1066 unsigned newSize = newClasses.size();
1067 for (unsigned i = 0; i < newSize; ++i) {
1068 for (unsigned j = 0; j < oldSize; ++j) {
1069 if (newClasses[i] == oldClasses[j]) {
1070 remainingClassBits.quickSet(j);
1071 continue;
1072 }
1073 }
1074 if (checker.hasSelectorForClass(newClasses[i]))
1075 return true;
1076 }
1077 for (unsigned i = 0; i < oldSize; ++i) {
1078 // If the bit is not set the the corresponding class has been removed.
1079 if (remainingClassBits.quickGet(i))
1080 continue;
1081 if (checker.hasSelectorForClass(oldClasses[i]))
1082 return true;
1083 }
1084 return false;
1085}
1086
1087void Element::classAttributeChanged(const AtomicString& newClassString)
1088{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001089 StyleResolver* styleResolver = document().styleResolverIfExists();
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001090 bool testShouldInvalidateStyle = inActiveDocument() && styleResolver && styleChangeType() < SubtreeStyleChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001091 bool shouldInvalidateStyle = false;
1092
1093 if (classStringHasClassName(newClassString)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001094 const bool shouldFoldCase = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001095 const SpaceSplitString oldClasses = elementData()->classNames();
1096 elementData()->setClass(newClassString, shouldFoldCase);
1097 const SpaceSplitString& newClasses = elementData()->classNames();
Ben Murdoch7757ec22013-07-23 11:17:36 +01001098 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, newClasses, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001099 } else {
1100 const SpaceSplitString& oldClasses = elementData()->classNames();
Ben Murdoch7757ec22013-07-23 11:17:36 +01001101 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001102 elementData()->clearClass();
1103 }
1104
1105 if (hasRareData())
1106 elementRareData()->clearClassListValueForQuirksMode();
1107
1108 if (shouldInvalidateStyle)
1109 setNeedsStyleRecalc();
1110}
1111
1112bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
1113{
1114 ASSERT(elementShadow);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001115 const SelectRuleFeatureSet& featureSet = elementShadow->ensureSelectFeatureSet();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001116
1117 if (isIdAttributeName(name)) {
1118 AtomicString oldId = elementData()->idForStyleResolution();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001119 AtomicString newId = makeIdForStyleResolution(newValue, document().inQuirksMode());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001120 if (newId != oldId) {
1121 if (!oldId.isEmpty() && featureSet.hasSelectorForId(oldId))
1122 return true;
1123 if (!newId.isEmpty() && featureSet.hasSelectorForId(newId))
1124 return true;
1125 }
1126 }
1127
1128 if (name == HTMLNames::classAttr) {
1129 const AtomicString& newClassString = newValue;
1130 if (classStringHasClassName(newClassString)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001131 const bool shouldFoldCase = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001132 const SpaceSplitString& oldClasses = elementData()->classNames();
1133 const SpaceSplitString newClasses(newClassString, shouldFoldCase);
1134 if (checkSelectorForClassChange(oldClasses, newClasses, featureSet))
1135 return true;
1136 } else {
1137 const SpaceSplitString& oldClasses = elementData()->classNames();
1138 if (checkSelectorForClassChange(oldClasses, featureSet))
1139 return true;
1140 }
1141 }
1142
1143 return featureSet.hasSelectorForAttribute(name.localName());
1144}
1145
1146// Returns true is the given attribute is an event handler.
1147// We consider an event handler any attribute that begins with "on".
1148// It is a simple solution that has the advantage of not requiring any
1149// code or configuration change if a new event handler is defined.
1150
1151static inline bool isEventHandlerAttribute(const Attribute& attribute)
1152{
1153 return attribute.name().namespaceURI().isNull() && attribute.name().localName().startsWith("on");
1154}
1155
1156bool Element::isJavaScriptURLAttribute(const Attribute& attribute) const
1157{
1158 return isURLAttribute(attribute) && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(attribute.value()));
1159}
1160
1161void Element::stripScriptingAttributes(Vector<Attribute>& attributeVector) const
1162{
1163 size_t destination = 0;
1164 for (size_t source = 0; source < attributeVector.size(); ++source) {
1165 if (isEventHandlerAttribute(attributeVector[source])
1166 || isJavaScriptURLAttribute(attributeVector[source])
1167 || isHTMLContentAttribute(attributeVector[source]))
1168 continue;
1169
1170 if (source != destination)
1171 attributeVector[destination] = attributeVector[source];
1172
1173 ++destination;
1174 }
1175 attributeVector.shrink(destination);
1176}
1177
1178void Element::parserSetAttributes(const Vector<Attribute>& attributeVector)
1179{
1180 ASSERT(!inDocument());
1181 ASSERT(!parentNode());
1182 ASSERT(!m_elementData);
1183
1184 if (attributeVector.isEmpty())
1185 return;
1186
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001187 if (document().sharedObjectPool())
1188 m_elementData = document().sharedObjectPool()->cachedShareableElementDataWithAttributes(attributeVector);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001189 else
1190 m_elementData = ShareableElementData::createWithAttributes(attributeVector);
1191
1192 // Use attributeVector instead of m_elementData because attributeChanged might modify m_elementData.
1193 for (unsigned i = 0; i < attributeVector.size(); ++i)
1194 attributeChangedFromParserOrByCloning(attributeVector[i].name(), attributeVector[i].value(), ModifiedDirectly);
1195}
1196
1197bool Element::hasAttributes() const
1198{
1199 synchronizeAllAttributes();
1200 return elementData() && elementData()->length();
1201}
1202
1203bool Element::hasEquivalentAttributes(const Element* other) const
1204{
1205 synchronizeAllAttributes();
1206 other->synchronizeAllAttributes();
1207 if (elementData() == other->elementData())
1208 return true;
1209 if (elementData())
1210 return elementData()->isEquivalent(other->elementData());
1211 if (other->elementData())
1212 return other->elementData()->isEquivalent(elementData());
1213 return true;
1214}
1215
1216String Element::nodeName() const
1217{
1218 return m_tagName.toString();
1219}
1220
1221String Element::nodeNamePreservingCase() const
1222{
1223 return m_tagName.toString();
1224}
1225
Ben Murdochdf957042013-08-06 11:01:27 +01001226void Element::setPrefix(const AtomicString& prefix, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001227{
Ben Murdochdf957042013-08-06 11:01:27 +01001228 checkSetPrefix(prefix, es);
1229 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001230 return;
1231
1232 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
1233}
1234
1235KURL Element::baseURI() const
1236{
1237 const AtomicString& baseAttribute = getAttribute(baseAttr);
1238 KURL base(KURL(), baseAttribute);
1239 if (!base.protocol().isEmpty())
1240 return base;
1241
1242 ContainerNode* parent = parentNode();
1243 if (!parent)
1244 return base;
1245
1246 const KURL& parentBase = parent->baseURI();
1247 if (parentBase.isNull())
1248 return base;
1249
1250 return KURL(parentBase, baseAttribute);
1251}
1252
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001253const AtomicString Element::imageSourceURL() const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001254{
1255 return getAttribute(srcAttr);
1256}
1257
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001258bool Element::rendererIsNeeded(const RenderStyle& style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001259{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001260 return style.display() != NONE;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001261}
1262
Ben Murdoch591b9582013-07-10 11:41:44 +01001263RenderObject* Element::createRenderer(RenderStyle* style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001264{
1265 return RenderObject::createObject(this, style);
1266}
1267
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001268Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertionPoint)
1269{
1270 // need to do superclass processing first so inDocument() is true
1271 // by the time we reach updateId
1272 ContainerNode::insertedInto(insertionPoint);
1273
1274 if (containsFullScreenElement() && parentElement() && !parentElement()->containsFullScreenElement())
1275 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
1276
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00001277 ASSERT(!hasRareData() || !elementRareData()->hasPseudoElements());
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001278
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001279 if (!insertionPoint->isInTreeScope())
1280 return InsertionDone;
1281
1282 if (hasRareData())
1283 elementRareData()->clearClassListValueForQuirksMode();
1284
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001285 if (isUpgradedCustomElement() && inDocument())
1286 CustomElement::didEnterDocument(this, document());
1287
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001288 TreeScope& scope = insertionPoint->treeScope();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001289 if (scope != treeScope())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001290 return InsertionDone;
1291
1292 const AtomicString& idValue = getIdAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001293 if (!idValue.isNull())
1294 updateId(scope, nullAtom, idValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001295
1296 const AtomicString& nameValue = getNameAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001297 if (!nameValue.isNull())
1298 updateName(nullAtom, nameValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001299
1300 if (hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001301 if (scope.shouldCacheLabelsByForAttribute())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001302 updateLabel(scope, nullAtom, fastGetAttribute(forAttr));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001303 }
1304
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001305 if (parentElement() && parentElement()->isInCanvasSubtree())
1306 setIsInCanvasSubtree(true);
1307
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001308 return InsertionDone;
1309}
1310
1311void Element::removedFrom(ContainerNode* insertionPoint)
1312{
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001313 bool wasInDocument = insertionPoint->inDocument();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001314
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00001315 ASSERT(!hasRareData() || !elementRareData()->hasPseudoElements());
Ben Murdoche69819b2013-07-17 14:56:49 +01001316
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001317 if (containsFullScreenElement())
1318 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
1319
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001320 if (document().page())
1321 document().page()->pointerLockController().elementRemoved(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001322
1323 setSavedLayerScrollOffset(IntSize());
1324
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001325 if (insertionPoint->isInTreeScope() && treeScope() == document()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001326 const AtomicString& idValue = getIdAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001327 if (!idValue.isNull())
1328 updateId(insertionPoint->treeScope(), idValue, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001329
1330 const AtomicString& nameValue = getNameAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001331 if (!nameValue.isNull())
1332 updateName(nameValue, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001333
1334 if (hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001335 TreeScope& treeScope = insertionPoint->treeScope();
1336 if (treeScope.shouldCacheLabelsByForAttribute())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001337 updateLabel(treeScope, fastGetAttribute(forAttr), nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001338 }
1339 }
1340
1341 ContainerNode::removedFrom(insertionPoint);
Ben Murdoche69819b2013-07-17 14:56:49 +01001342 if (wasInDocument) {
1343 if (hasPendingResources())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001344 document().accessSVGExtensions()->removeElementFromPendingResources(this);
Ben Murdoche69819b2013-07-17 14:56:49 +01001345
Ben Murdoch83750172013-07-24 10:36:59 +01001346 if (isUpgradedCustomElement())
Ben Murdochfff88842013-07-30 15:20:09 +01001347 CustomElement::didLeaveDocument(this, insertionPoint->document());
Ben Murdoche69819b2013-07-17 14:56:49 +01001348 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001349
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00001350 document().removeFromTopLayer(this);
1351
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001352 if (hasRareData())
1353 elementRareData()->setIsInCanvasSubtree(false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001354}
1355
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001356void Element::attach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001357{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001358 ASSERT(document().inStyleRecalc());
1359
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001360 StyleResolverParentPusher parentPusher(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001361
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001362 // We've already been through detach when doing a lazyAttach, but we might
1363 // need to clear any state that's been added since then.
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001364 if (hasRareData() && styleChangeType() == NeedsReattachStyleChange) {
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001365 ElementRareData* data = elementRareData();
1366 data->clearComputedStyle();
1367 data->resetDynamicRestyleObservations();
1368 if (!context.resolvedStyle)
1369 data->resetStyleState();
1370 }
1371
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001372 NodeRenderingContext(this, context.resolvedStyle).createRendererForElementIfNeeded();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001373
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001374 if (RenderStyle* style = renderStyle())
1375 updateCallbackSelectors(0, style);
1376
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001377 createPseudoElementIfNeeded(BEFORE);
1378
1379 // When a shadow root exists, it does the work of attaching the children.
1380 if (ElementShadow* shadow = this->shadow()) {
1381 parentPusher.push();
Ben Murdoch591b9582013-07-10 11:41:44 +01001382 shadow->attach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001383 } else if (firstChild())
1384 parentPusher.push();
1385
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001386 ContainerNode::attach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001387
1388 createPseudoElementIfNeeded(AFTER);
Ben Murdoche69819b2013-07-17 14:56:49 +01001389 createPseudoElementIfNeeded(BACKDROP);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001390
Ben Murdoch591b9582013-07-10 11:41:44 +01001391 if (hasRareData()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001392 ElementRareData* data = elementRareData();
1393 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001394 if (isFocusable() && document().focusedElement() == this)
1395 document().updateFocusAppearanceSoon(false /* don't restore selection */);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001396 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1397 }
1398 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001399
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001400 InspectorInstrumentation::didRecalculateStyleForElement(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001401}
1402
1403void Element::unregisterNamedFlowContentNode()
1404{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001405 if (RuntimeEnabledFeatures::cssRegionsEnabled() && inNamedFlow() && document().renderView())
1406 document().renderView()->flowThreadController()->unregisterNamedFlowContentNode(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001407}
1408
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001409void Element::detach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001410{
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001411 RenderWidget::UpdateSuspendScope suspendWidgetHierarchyUpdates;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001412 unregisterNamedFlowContentNode();
1413 cancelFocusAppearanceUpdate();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001414 if (RenderStyle* style = renderStyle()) {
1415 if (!style->callbackSelectors().isEmpty())
1416 updateCallbackSelectors(style, 0);
1417 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001418 if (hasRareData()) {
1419 ElementRareData* data = elementRareData();
1420 data->setPseudoElement(BEFORE, 0);
1421 data->setPseudoElement(AFTER, 0);
Ben Murdoche69819b2013-07-17 14:56:49 +01001422 data->setPseudoElement(BACKDROP, 0);
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001423 data->clearComputedStyle();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001424 data->resetDynamicRestyleObservations();
Ben Murdoch591b9582013-07-10 11:41:44 +01001425 data->setIsInsideRegion(false);
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001426
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001427 // Only clear the style state if we're not going to reuse the style from recalcStyle.
1428 if (!context.resolvedStyle)
1429 data->resetStyleState();
1430
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001431 if (RuntimeEnabledFeatures::webAnimationsCSSEnabled() && !context.performingReattach) {
1432 if (ActiveAnimations* activeAnimations = data->activeAnimations())
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001433 activeAnimations->cssAnimations().cancel();
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001434 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001435 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001436 if (ElementShadow* shadow = this->shadow())
1437 shadow->detach(context);
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001438 ContainerNode::detach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001439}
1440
1441bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle)
1442{
1443 ASSERT(currentStyle == renderStyle());
1444 ASSERT(renderer());
1445
1446 if (!currentStyle)
1447 return false;
1448
1449 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles();
1450 if (!pseudoStyleCache)
1451 return false;
1452
1453 size_t cacheSize = pseudoStyleCache->size();
1454 for (size_t i = 0; i < cacheSize; ++i) {
1455 RefPtr<RenderStyle> newPseudoStyle;
1456 PseudoId pseudoId = pseudoStyleCache->at(i)->styleType();
1457 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
1458 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle);
1459 else
1460 newPseudoStyle = renderer()->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
1461 if (!newPseudoStyle)
1462 return true;
1463 if (*newPseudoStyle != *pseudoStyleCache->at(i)) {
1464 if (pseudoId < FIRST_INTERNAL_PSEUDOID)
1465 newStyle->setHasPseudoStyle(pseudoId);
1466 newStyle->addCachedPseudoStyle(newPseudoStyle);
1467 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
1468 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
1469 // is needed, but for now just assume a layout will be required. The diff code
1470 // in RenderObject::setStyle would need to be factored out so that it could be reused.
1471 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
1472 }
1473 return true;
1474 }
1475 }
1476 return false;
1477}
1478
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001479PassRefPtr<RenderStyle> Element::styleForRenderer()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001480{
1481 if (hasCustomStyleCallbacks()) {
1482 if (RefPtr<RenderStyle> style = customStyleForRenderer())
1483 return style.release();
1484 }
1485
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001486 return originalStyleForRenderer();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001487}
1488
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001489PassRefPtr<RenderStyle> Element::originalStyleForRenderer()
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001490{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001491 return document().styleResolver()->styleForElement(this);
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001492}
1493
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001494bool Element::recalcStyle(StyleRecalcChange change)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001495{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001496 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001497
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001498 if (hasCustomStyleCallbacks())
1499 willRecalcStyle(change);
1500
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001501 if (hasRareData() && (change > NoChange || needsStyleRecalc())) {
1502 ElementRareData* data = elementRareData();
1503 data->resetStyleState();
1504 data->clearComputedStyle();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001505 }
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001506
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001507 // Active InsertionPoints have no renderers so they never need to go through a recalc.
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00001508 if ((change >= Inherit || needsStyleRecalc()) && parentRenderStyle() && !isActiveInsertionPoint(*this))
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001509 change = recalcOwnStyle(change);
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001510
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001511 // If we reattached we don't need to recalc the style of our descendants anymore.
1512 if (change < Reattach)
1513 recalcChildStyle(change);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001514
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001515 clearNeedsStyleRecalc();
1516 clearChildNeedsStyleRecalc();
Ben Murdoch591b9582013-07-10 11:41:44 +01001517
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001518 if (hasCustomStyleCallbacks())
1519 didRecalcStyle(change);
1520
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001521 return change == Reattach;
1522}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001523
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001524static bool callbackSelectorsDiffer(RenderStyle* style1, RenderStyle* style2)
1525{
1526 const Vector<String> emptyVector;
1527 const Vector<String>& callbackSelectors1 = style1 ? style1->callbackSelectors() : emptyVector;
1528 const Vector<String>& callbackSelectors2 = style2 ? style2->callbackSelectors() : emptyVector;
1529 if (callbackSelectors1.isEmpty() && callbackSelectors2.isEmpty()) {
1530 // Help the inliner with this common case.
1531 return false;
1532 }
1533 return callbackSelectors1 != callbackSelectors2;
1534}
1535
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001536StyleRecalcChange Element::recalcOwnStyle(StyleRecalcChange change)
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001537{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001538 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001539
1540 CSSAnimationUpdateScope cssAnimationUpdateScope(this);
1541 RefPtr<RenderStyle> oldStyle = renderStyle();
1542 RefPtr<RenderStyle> newStyle = styleForRenderer();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001543 StyleRecalcChange localChange = RenderStyle::compare(oldStyle.get(), newStyle.get());
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001544
1545 if (localChange == Reattach) {
1546 AttachContext reattachContext;
1547 reattachContext.resolvedStyle = newStyle.get();
1548 reattach(reattachContext);
1549 return Reattach;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001550 }
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001551
1552 InspectorInstrumentation::didRecalculateStyleForElement(this);
1553
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001554 if (localChange != NoChange && callbackSelectorsDiffer(oldStyle.get(), newStyle.get()))
1555 updateCallbackSelectors(oldStyle.get(), newStyle.get());
1556
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001557 if (RenderObject* renderer = this->renderer()) {
1558 if (localChange != NoChange || pseudoStyleCacheIsInvalid(oldStyle.get(), newStyle.get()) || (change == Force && renderer->requiresForcedStyleRecalcPropagation()) || shouldNotifyRendererWithIdenticalStyles()) {
1559 renderer->setAnimatableStyle(newStyle.get());
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001560 } else {
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001561 // Although no change occurred, we use the new style so that the cousin style sharing code won't get
1562 // fooled into believing this style is the same.
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001563 // FIXME: We may be able to remove this hack, see discussion in
1564 // https://codereview.chromium.org/30453002/
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001565 renderer->setStyleInternal(newStyle.get());
1566 }
1567 }
1568
1569 // 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
1570 // 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 +01001571 if (document().styleEngine()->usesRemUnits() && document().documentElement() == this && oldStyle && newStyle && oldStyle->fontSize() != newStyle->fontSize()) {
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001572 // Cached RenderStyles may depend on the re units.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001573 document().styleResolver()->invalidateMatchedPropertiesCache();
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001574 return Force;
1575 }
1576
1577 if (styleChangeType() >= SubtreeStyleChange)
1578 return Force;
1579
1580 return max(localChange, change);
1581}
1582
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001583void Element::recalcChildStyle(StyleRecalcChange change)
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001584{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001585 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001586
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001587 StyleResolverParentPusher parentPusher(this);
1588
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001589 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
1590 if (shouldRecalcStyle(change, root)) {
1591 parentPusher.push();
1592 root->recalcStyle(change);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001593 }
1594 }
1595
1596 if (shouldRecalcStyle(change, this))
1597 updatePseudoElement(BEFORE, change);
1598
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001599 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
1600 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001601 unsigned forceCheckOfNextElementCount = 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001602 bool forceCheckOfAnyElementSibling = false;
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001603 if (hasDirectAdjacentRules || hasIndirectAdjacentRules) {
1604 for (Node* child = firstChild(); child; child = child->nextSibling()) {
1605 if (!child->isElementNode())
1606 continue;
Ben Murdoche69819b2013-07-17 14:56:49 +01001607 Element* element = toElement(child);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001608 bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() >= SubtreeStyleChange;
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001609
1610 if (forceCheckOfNextElementCount || forceCheckOfAnyElementSibling)
Ben Murdoche69819b2013-07-17 14:56:49 +01001611 element->setNeedsStyleRecalc();
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001612
1613 if (forceCheckOfNextElementCount)
1614 forceCheckOfNextElementCount--;
1615
1616 if (childRulesChanged && hasDirectAdjacentRules)
1617 forceCheckOfNextElementCount = document().styleEngine()->maxDirectAdjacentSelectors();
1618
Ben Murdoche69819b2013-07-17 14:56:49 +01001619 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001620 }
1621 }
1622 // This loop is deliberately backwards because we use insertBefore in the rendering tree, and want to avoid
1623 // a potentially n^2 loop to find the insertion point while resolving style. Having us start from the last
1624 // child and work our way back means in the common case, we'll find the insertion point in O(1) time.
1625 // Reversing this loop can lead to non-deterministic results in our code to optimize out empty whitespace
1626 // RenderTexts. We try to put off recalcing their style until the end to avoid this issue.
1627 // See crbug.com/288225
1628 WhitespaceChildList whitespaceChildList(change);
1629 for (Node* child = lastChild(); child; child = child->previousSibling()) {
1630 if (child->isTextNode()) {
1631 Text* textChild = toText(child);
1632 // FIXME: This check is expensive and may negate the performance gained by the optimization of
1633 // avoiding whitespace renderers.
1634 if (textChild->containsOnlyWhitespace())
1635 whitespaceChildList.append(textChild);
1636 else
1637 textChild->recalcTextStyle(change);
1638 } else if (child->isElementNode()) {
1639 Element* element = toElement(child);
Ben Murdoche69819b2013-07-17 14:56:49 +01001640 if (shouldRecalcStyle(change, element)) {
1641 parentPusher.push();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001642 element->recalcStyle(change);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001643 } else if (element->supportsStyleSharing()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001644 document().styleResolver()->addToStyleSharingList(element);
Ben Murdoche69819b2013-07-17 14:56:49 +01001645 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001646 }
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001647 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001648
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001649 whitespaceChildList.recalcStyle();
1650
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001651 if (shouldRecalcStyle(change, this)) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001652 updatePseudoElement(AFTER, change);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001653 updatePseudoElement(BACKDROP, change);
1654 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001655}
1656
1657ElementShadow* Element::shadow() const
1658{
1659 return hasRareData() ? elementRareData()->shadow() : 0;
1660}
1661
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001662ElementShadow& Element::ensureShadow()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001663{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001664 return ensureElementRareData().ensureShadow();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001665}
1666
1667void Element::didAffectSelector(AffectedSelectorMask mask)
1668{
1669 setNeedsStyleRecalc();
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00001670 if (ElementShadow* elementShadow = shadowWhereNodeCanBeDistributed(*this))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001671 elementShadow->didAffectSelector(mask);
1672}
1673
Ben Murdochdf957042013-08-06 11:01:27 +01001674PassRefPtr<ShadowRoot> Element::createShadowRoot(ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001675{
1676 if (alwaysCreateUserAgentShadowRoot())
1677 ensureUserAgentShadowRoot();
1678
1679 if (RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled())
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001680 return ensureShadow().addShadowRoot(*this, ShadowRoot::AuthorShadowRoot);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001681
1682 // Since some elements recreates shadow root dynamically, multiple shadow
1683 // subtrees won't work well in that element. Until they are fixed, we disable
1684 // adding author shadow root for them.
1685 if (!areAuthorShadowsAllowed()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001686 es.throwUninformativeAndGenericDOMException(HierarchyRequestError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001687 return 0;
1688 }
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001689 return ensureShadow().addShadowRoot(*this, ShadowRoot::AuthorShadowRoot);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001690}
1691
1692ShadowRoot* Element::shadowRoot() const
1693{
1694 ElementShadow* elementShadow = shadow();
1695 if (!elementShadow)
1696 return 0;
1697 ShadowRoot* shadowRoot = elementShadow->youngestShadowRoot();
1698 if (shadowRoot->type() == ShadowRoot::AuthorShadowRoot)
1699 return shadowRoot;
1700 return 0;
1701}
1702
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001703void Element::didAddShadowRoot(ShadowRoot&)
1704{
1705}
1706
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001707ShadowRoot* Element::userAgentShadowRoot() const
1708{
1709 if (ElementShadow* elementShadow = shadow()) {
1710 if (ShadowRoot* shadowRoot = elementShadow->oldestShadowRoot()) {
1711 ASSERT(shadowRoot->type() == ShadowRoot::UserAgentShadowRoot);
1712 return shadowRoot;
1713 }
1714 }
1715
1716 return 0;
1717}
1718
1719ShadowRoot* Element::ensureUserAgentShadowRoot()
1720{
1721 if (ShadowRoot* shadowRoot = userAgentShadowRoot())
1722 return shadowRoot;
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001723 ShadowRoot* shadowRoot = ensureShadow().addShadowRoot(*this, ShadowRoot::UserAgentShadowRoot);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001724 didAddUserAgentShadowRoot(shadowRoot);
1725 return shadowRoot;
1726}
1727
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001728bool Element::childTypeAllowed(NodeType type) const
1729{
1730 switch (type) {
1731 case ELEMENT_NODE:
1732 case TEXT_NODE:
1733 case COMMENT_NODE:
1734 case PROCESSING_INSTRUCTION_NODE:
1735 case CDATA_SECTION_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001736 return true;
1737 default:
1738 break;
1739 }
1740 return false;
1741}
1742
Ben Murdoch83750172013-07-24 10:36:59 +01001743static void inline checkForEmptyStyleChange(Element* element, RenderStyle* style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001744{
1745 if (!style && !element->styleAffectedByEmpty())
1746 return;
1747
1748 if (!style || (element->styleAffectedByEmpty() && (!style->emptyState() || element->hasChildNodes())))
1749 element->setNeedsStyleRecalc();
1750}
1751
1752static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
1753 Node* beforeChange, Node* afterChange, int childCountDelta)
1754{
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001755 if (!e->inActiveDocument() || e->document().hasPendingForcedStyleRecalc() || e->styleChangeType() >= SubtreeStyleChange)
Ben Murdoch83750172013-07-24 10:36:59 +01001756 return;
1757
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001758 // :empty selector.
1759 checkForEmptyStyleChange(e, style);
Ben Murdoch591b9582013-07-10 11:41:44 +01001760
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001761 if (!style || (e->needsStyleRecalc() && e->childrenAffectedByPositionalRules()))
1762 return;
1763
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001764 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
1765 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1766 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
1767 // backward case.
1768 // |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.
1769 // 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 +01001770 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
1771 if ((e->childrenAffectedByForwardPositionalRules() && afterChange) || (e->childrenAffectedByBackwardPositionalRules() && beforeChange)) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001772 e->setNeedsStyleRecalc();
Ben Murdoch83750172013-07-24 10:36:59 +01001773 return;
1774 }
1775
1776 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1777 // In the DOM case, we only need to do something if |afterChange| is not 0.
1778 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
1779 if (e->childrenAffectedByFirstChildRules() && afterChange) {
1780 // Find our new first child.
1781 Node* newFirstChild = e->firstElementChild();
1782 RenderStyle* newFirstChildStyle = newFirstChild ? newFirstChild->renderStyle() : 0;
1783
1784 // Find the first element node following |afterChange|
1785 Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling();
1786 RenderStyle* firstElementAfterInsertionStyle = firstElementAfterInsertion ? firstElementAfterInsertion->renderStyle() : 0;
1787
1788 // This is the insert/append case.
1789 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertionStyle && firstElementAfterInsertionStyle->firstChildState())
1790 firstElementAfterInsertion->setNeedsStyleRecalc();
1791
1792 // We also have to handle node removal.
1793 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChildStyle || !newFirstChildStyle->firstChildState()))
1794 newFirstChild->setNeedsStyleRecalc();
1795 }
1796
1797 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1798 // In the DOM case, we only need to do something if |afterChange| is not 0.
1799 if (e->childrenAffectedByLastChildRules() && beforeChange) {
1800 // Find our new last child.
1801 Node* newLastChild = e->lastElementChild();
1802 RenderStyle* newLastChildStyle = newLastChild ? newLastChild->renderStyle() : 0;
1803
1804 // Find the last element node going backwards from |beforeChange|
1805 Node* lastElementBeforeInsertion = beforeChange->isElementNode() ? beforeChange : beforeChange->previousElementSibling();
1806 RenderStyle* lastElementBeforeInsertionStyle = lastElementBeforeInsertion ? lastElementBeforeInsertion->renderStyle() : 0;
1807
1808 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertionStyle && lastElementBeforeInsertionStyle->lastChildState())
1809 lastElementBeforeInsertion->setNeedsStyleRecalc();
1810
1811 // 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
1812 // to match now.
1813 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChildStyle || !newLastChildStyle->lastChildState()))
1814 newLastChild->setNeedsStyleRecalc();
1815 }
1816
1817 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
1818 // that could be affected by this DOM change.
1819 if (e->childrenAffectedByDirectAdjacentRules() && afterChange) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001820 if (Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling())
Ben Murdoch83750172013-07-24 10:36:59 +01001821 firstElementAfterInsertion->setNeedsStyleRecalc();
1822 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001823}
1824
1825void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
1826{
1827 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
1828 if (changedByParser)
1829 checkForEmptyStyleChange(this, renderStyle());
1830 else
1831 checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
1832
Ben Murdoch83750172013-07-24 10:36:59 +01001833 if (ElementShadow* shadow = this->shadow())
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001834 shadow->setNeedsDistributionRecalc();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001835}
1836
1837void Element::removeAllEventListeners()
1838{
1839 ContainerNode::removeAllEventListeners();
1840 if (ElementShadow* shadow = this->shadow())
1841 shadow->removeAllEventListeners();
1842}
1843
1844void Element::beginParsingChildren()
1845{
1846 clearIsParsingChildrenFinished();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001847}
1848
1849void Element::finishParsingChildren()
1850{
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001851 setIsParsingChildrenFinished();
1852 checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001853 if (isCustomElement())
1854 CustomElement::didFinishParsingChildren(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001855}
1856
1857#ifndef NDEBUG
1858void Element::formatForDebugger(char* buffer, unsigned length) const
1859{
1860 StringBuilder result;
1861 String s;
1862
1863 result.append(nodeName());
1864
1865 s = getIdAttribute();
1866 if (s.length() > 0) {
1867 if (result.length() > 0)
1868 result.appendLiteral("; ");
1869 result.appendLiteral("id=");
1870 result.append(s);
1871 }
1872
1873 s = getAttribute(classAttr);
1874 if (s.length() > 0) {
1875 if (result.length() > 0)
1876 result.appendLiteral("; ");
1877 result.appendLiteral("class=");
1878 result.append(s);
1879 }
1880
1881 strncpy(buffer, result.toString().utf8().data(), length - 1);
1882}
1883#endif
1884
1885const Vector<RefPtr<Attr> >& Element::attrNodeList()
1886{
1887 ASSERT(hasSyntheticAttrChildNodes());
1888 return *attrNodeListForElement(this);
1889}
1890
Ben Murdochdf957042013-08-06 11:01:27 +01001891PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001892{
1893 if (!attrNode) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001894 es.throwUninformativeAndGenericDOMException(TypeMismatchError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001895 return 0;
1896 }
1897
1898 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName());
1899 if (oldAttrNode.get() == attrNode)
1900 return attrNode; // This Attr is already attached to the element.
1901
Ben Murdoche69819b2013-07-17 14:56:49 +01001902 // 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 +01001903 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
1904 if (attrNode->ownerElement()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001905 es.throwUninformativeAndGenericDOMException(InUseAttributeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001906 return 0;
1907 }
1908
1909 synchronizeAllAttributes();
1910 UniqueElementData* elementData = ensureUniqueElementData();
1911
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001912 size_t index = elementData->getAttributeItemIndex(attrNode->qualifiedName(), shouldIgnoreAttributeCase());
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001913 if (index != kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001914 if (oldAttrNode)
1915 detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData->attributeItem(index)->value());
1916 else
1917 oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), elementData->attributeItem(index)->value());
1918 }
1919
1920 setAttributeInternal(index, attrNode->qualifiedName(), attrNode->value(), NotInSynchronizationOfLazyAttribute);
1921
1922 attrNode->attachToElement(this);
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001923 treeScope().adoptIfNeeded(*attrNode);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001924 ensureAttrNodeListForElement(this).append(attrNode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001925
1926 return oldAttrNode.release();
1927}
1928
Ben Murdochdf957042013-08-06 11:01:27 +01001929PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001930{
Ben Murdochdf957042013-08-06 11:01:27 +01001931 return setAttributeNode(attr, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001932}
1933
Ben Murdochdf957042013-08-06 11:01:27 +01001934PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001935{
1936 if (!attr) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001937 es.throwUninformativeAndGenericDOMException(TypeMismatchError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001938 return 0;
1939 }
1940 if (attr->ownerElement() != this) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001941 es.throwUninformativeAndGenericDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001942 return 0;
1943 }
1944
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001945 ASSERT(document() == attr->document());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001946
1947 synchronizeAttribute(attr->qualifiedName());
1948
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001949 size_t index = elementData()->getAttrIndex(attr);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001950 if (index == kNotFound) {
1951 es.throwUninformativeAndGenericDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001952 return 0;
1953 }
1954
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001955 RefPtr<Attr> guard(attr);
1956 detachAttrNodeAtIndex(attr, index);
1957 return guard.release();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001958}
1959
Ben Murdochdf957042013-08-06 11:01:27 +01001960bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001961{
1962 String prefix, localName;
Ben Murdochdf957042013-08-06 11:01:27 +01001963 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, es))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001964 return false;
Ben Murdochdf957042013-08-06 11:01:27 +01001965 ASSERT(!es.hadException());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001966
1967 QualifiedName qName(prefix, localName, namespaceURI);
1968
1969 if (!Document::hasValidNamespaceForAttributes(qName)) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001970 es.throwUninformativeAndGenericDOMException(NamespaceError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001971 return false;
1972 }
1973
1974 out = qName;
1975 return true;
1976}
1977
Ben Murdochdf957042013-08-06 11:01:27 +01001978void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001979{
1980 QualifiedName parsedName = anyName;
Ben Murdochdf957042013-08-06 11:01:27 +01001981 if (!parseAttributeName(parsedName, namespaceURI, qualifiedName, es))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001982 return;
1983 setAttribute(parsedName, value);
1984}
1985
1986void Element::removeAttributeInternal(size_t index, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1987{
1988 ASSERT_WITH_SECURITY_IMPLICATION(index < attributeCount());
1989
1990 UniqueElementData* elementData = ensureUniqueElementData();
1991
1992 QualifiedName name = elementData->attributeItem(index)->name();
1993 AtomicString valueBeingRemoved = elementData->attributeItem(index)->value();
1994
1995 if (!inSynchronizationOfLazyAttribute) {
1996 if (!valueBeingRemoved.isNull())
1997 willModifyAttribute(name, valueBeingRemoved, nullAtom);
1998 }
1999
2000 if (RefPtr<Attr> attrNode = attrIfExists(name))
2001 detachAttrNodeFromElementWithValue(attrNode.get(), elementData->attributeItem(index)->value());
2002
2003 elementData->removeAttribute(index);
2004
2005 if (!inSynchronizationOfLazyAttribute)
2006 didRemoveAttribute(name);
2007}
2008
2009void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
2010{
2011 if (!inSynchronizationOfLazyAttribute)
2012 willModifyAttribute(name, nullAtom, value);
2013 ensureUniqueElementData()->addAttribute(name, value);
2014 if (!inSynchronizationOfLazyAttribute)
2015 didAddAttribute(name, value);
2016}
2017
2018void Element::removeAttribute(const AtomicString& name)
2019{
2020 if (!elementData())
2021 return;
2022
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002023 AtomicString localName = shouldIgnoreAttributeCase() ? name.lower() : name;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002024 size_t index = elementData()->getAttributeItemIndex(localName, false);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01002025 if (index == kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002026 if (UNLIKELY(localName == styleAttr) && elementData()->m_styleAttributeIsDirty && isStyledElement())
Ben Murdoch591b9582013-07-10 11:41:44 +01002027 removeAllInlineStyleProperties();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002028 return;
2029 }
2030
2031 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
2032}
2033
2034void Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName)
2035{
2036 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI));
2037}
2038
2039PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& localName)
2040{
2041 if (!elementData())
2042 return 0;
2043 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002044 const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002045 if (!attribute)
2046 return 0;
2047 return ensureAttr(attribute->name());
2048}
2049
2050PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
2051{
2052 if (!elementData())
2053 return 0;
2054 QualifiedName qName(nullAtom, localName, namespaceURI);
2055 synchronizeAttribute(qName);
2056 const Attribute* attribute = elementData()->getAttributeItem(qName);
2057 if (!attribute)
2058 return 0;
2059 return ensureAttr(attribute->name());
2060}
2061
2062bool Element::hasAttribute(const AtomicString& localName) const
2063{
2064 if (!elementData())
2065 return false;
2066 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002067 return elementData()->getAttributeItem(shouldIgnoreAttributeCase() ? localName.lower() : localName, false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002068}
2069
2070bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
2071{
2072 if (!elementData())
2073 return false;
2074 QualifiedName qName(nullAtom, localName, namespaceURI);
2075 synchronizeAttribute(qName);
2076 return elementData()->getAttributeItem(qName);
2077}
2078
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002079void Element::focus(bool restorePreviousSelection, FocusDirection direction)
2080{
2081 if (!inDocument())
2082 return;
2083
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002084 Document& doc = document();
2085 if (doc.focusedElement() == this)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002086 return;
2087
2088 // If the stylesheets have already been loaded we can reliably check isFocusable.
2089 // If not, we continue and set the focused node on the focus controller below so
Ben Murdoch591b9582013-07-10 11:41:44 +01002090 // that it can be updated soon after attach.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002091 if (doc.haveStylesheetsLoaded()) {
2092 doc.updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002093 if (!isFocusable())
2094 return;
2095 }
2096
2097 if (!supportsFocus())
2098 return;
2099
2100 RefPtr<Node> protect;
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002101 if (Page* page = doc.page()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002102 // Focus and change event handlers can cause us to lose our last ref.
2103 // If a focus event handler changes the focus to a different node it
2104 // does not make sense to continue and update appearence.
2105 protect = this;
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002106 if (!page->focusController().setFocusedElement(this, doc.frame(), direction))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002107 return;
2108 }
2109
2110 // Setting the focused node above might have invalidated the layout due to scripts.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002111 doc.updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002112
2113 if (!isFocusable()) {
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002114 ensureElementRareData().setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002115 return;
2116 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002117
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002118 cancelFocusAppearanceUpdate();
2119 updateFocusAppearance(restorePreviousSelection);
2120}
2121
2122void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
2123{
2124 if (isRootEditableElement()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002125 Frame* frame = document().frame();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002126 if (!frame)
2127 return;
Ben Murdoch591b9582013-07-10 11:41:44 +01002128
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002129 // 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 +01002130 if (this == frame->selection().rootEditableElement())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002131 return;
2132
2133 // FIXME: We should restore the previous selection if there is one.
2134 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002135 frame->selection().setSelection(newSelection);
2136 frame->selection().revealSelection();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002137 } else if (renderer() && !renderer()->isWidget())
2138 renderer()->scrollRectToVisible(boundingBox());
2139}
2140
2141void Element::blur()
2142{
2143 cancelFocusAppearanceUpdate();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002144 if (treeScope().adjustedFocusedElement() == this) {
2145 Document& doc = document();
2146 if (doc.page())
2147 doc.page()->focusController().setFocusedElement(0, doc.frame());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002148 else
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002149 doc.setFocusedElement(0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002150 }
2151}
2152
Ben Murdochdf957042013-08-06 11:01:27 +01002153bool Element::isFocusable() const
2154{
2155 return inDocument() && supportsFocus() && !isInert() && rendererIsFocusable();
2156}
2157
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002158bool Element::isKeyboardFocusable() const
2159{
2160 return isFocusable() && tabIndex() >= 0;
2161}
2162
2163bool Element::isMouseFocusable() const
2164{
2165 return isFocusable();
2166}
2167
Ben Murdoch02772c62013-07-26 10:21:05 +01002168void Element::dispatchFocusEvent(Element* oldFocusedElement, FocusDirection)
2169{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002170 RefPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::focus, false, false, document().domWindow(), 0, oldFocusedElement);
Ben Murdoch02772c62013-07-26 10:21:05 +01002171 EventDispatcher::dispatchEvent(this, FocusEventDispatchMediator::create(event.release()));
2172}
2173
2174void Element::dispatchBlurEvent(Element* newFocusedElement)
2175{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002176 RefPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::blur, false, false, document().domWindow(), 0, newFocusedElement);
Ben Murdoch02772c62013-07-26 10:21:05 +01002177 EventDispatcher::dispatchEvent(this, BlurEventDispatchMediator::create(event.release()));
2178}
2179
2180void Element::dispatchFocusInEvent(const AtomicString& eventType, Element* oldFocusedElement)
2181{
2182 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002183 ASSERT(eventType == EventTypeNames::focusin || eventType == EventTypeNames::DOMFocusIn);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002184 dispatchScopedEventDispatchMediator(FocusInEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document().domWindow(), 0, oldFocusedElement)));
Ben Murdoch02772c62013-07-26 10:21:05 +01002185}
2186
2187void Element::dispatchFocusOutEvent(const AtomicString& eventType, Element* newFocusedElement)
2188{
2189 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002190 ASSERT(eventType == EventTypeNames::focusout || eventType == EventTypeNames::DOMFocusOut);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002191 dispatchScopedEventDispatchMediator(FocusOutEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document().domWindow(), 0, newFocusedElement)));
Ben Murdoch02772c62013-07-26 10:21:05 +01002192}
2193
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002194String Element::innerHTML() const
2195{
2196 return createMarkup(this, ChildrenOnly);
2197}
2198
2199String Element::outerHTML() const
2200{
2201 return createMarkup(this);
2202}
2203
2204void Element::setInnerHTML(const String& html, ExceptionState& es)
2205{
2206 if (RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(html, this, AllowScriptingContent, "innerHTML", es)) {
2207 ContainerNode* container = this;
2208 if (hasTagName(templateTag))
2209 container = toHTMLTemplateElement(this)->content();
2210 replaceChildrenWithFragment(container, fragment.release(), es);
2211 }
2212}
2213
2214void Element::setOuterHTML(const String& html, ExceptionState& es)
2215{
2216 Node* p = parentNode();
2217 if (!p || !p->isElementNode()) {
2218 es.throwUninformativeAndGenericDOMException(NoModificationAllowedError);
2219 return;
2220 }
2221 RefPtr<Element> parent = toElement(p);
2222 RefPtr<Node> prev = previousSibling();
2223 RefPtr<Node> next = nextSibling();
2224
2225 RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(html, parent.get(), AllowScriptingContent, "outerHTML", es);
2226 if (es.hadException())
2227 return;
2228
2229 parent->replaceChild(fragment.release(), this, es);
2230 RefPtr<Node> node = next ? next->previousSibling() : 0;
2231 if (!es.hadException() && node && node->isTextNode())
2232 mergeWithNextTextNode(node.release(), es);
2233
2234 if (!es.hadException() && prev && prev->isTextNode())
2235 mergeWithNextTextNode(prev.release(), es);
2236}
2237
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002238String Element::innerText()
2239{
2240 // We need to update layout, since plainText uses line boxes in the render tree.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002241 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002242
2243 if (!renderer())
2244 return textContent(true);
2245
2246 return plainText(rangeOfContents(const_cast<Element*>(this)).get());
2247}
2248
2249String Element::outerText()
2250{
2251 // Getting outerText is the same as getting innerText, only
2252 // setting is different. You would think this should get the plain
2253 // text for the outer range, but this is wrong, <br> for instance
2254 // would return different values for inner and outer text by such
2255 // a rule, but it doesn't in WinIE, and we want to match that.
2256 return innerText();
2257}
2258
Ben Murdoch591b9582013-07-10 11:41:44 +01002259String Element::textFromChildren()
2260{
2261 Text* firstTextNode = 0;
2262 bool foundMultipleTextNodes = false;
2263 unsigned totalLength = 0;
2264
2265 for (Node* child = firstChild(); child; child = child->nextSibling()) {
2266 if (!child->isTextNode())
2267 continue;
2268 Text* text = toText(child);
2269 if (!firstTextNode)
2270 firstTextNode = text;
2271 else
2272 foundMultipleTextNodes = true;
2273 unsigned length = text->data().length();
2274 if (length > std::numeric_limits<unsigned>::max() - totalLength)
2275 return emptyString();
2276 totalLength += length;
2277 }
2278
2279 if (!firstTextNode)
2280 return emptyString();
2281
2282 if (firstTextNode && !foundMultipleTextNodes) {
2283 firstTextNode->atomize();
2284 return firstTextNode->data();
2285 }
2286
2287 StringBuilder content;
2288 content.reserveCapacity(totalLength);
2289 for (Node* child = firstTextNode; child; child = child->nextSibling()) {
2290 if (!child->isTextNode())
2291 continue;
2292 content.append(toText(child)->data());
2293 }
2294
2295 ASSERT(content.length() == totalLength);
2296 return content.toString();
2297}
2298
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01002299// pseudo is used via shadowPseudoId.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002300const AtomicString& Element::pseudo() const
2301{
2302 return getAttribute(pseudoAttr);
2303}
2304
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002305const AtomicString& Element::part() const
2306{
2307 return getAttribute(partAttr);
2308}
2309
2310void Element::setPart(const AtomicString& value)
2311{
2312 setAttribute(partAttr, value);
2313}
2314
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002315LayoutSize Element::minimumSizeForResizing() const
2316{
2317 return hasRareData() ? elementRareData()->minimumSizeForResizing() : defaultMinimumSizeForResizing();
2318}
2319
2320void Element::setMinimumSizeForResizing(const LayoutSize& size)
2321{
2322 if (!hasRareData() && size == defaultMinimumSizeForResizing())
2323 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002324 ensureElementRareData().setMinimumSizeForResizing(size);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002325}
2326
2327RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
2328{
2329 if (PseudoElement* element = pseudoElement(pseudoElementSpecifier))
2330 return element->computedStyle();
2331
2332 // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
2333 // properties, which are only known by the renderer because it did the layout, will be correct and so that the
2334 // values returned for the ":selection" pseudo-element will be correct.
2335 if (RenderStyle* usedStyle = renderStyle()) {
2336 if (pseudoElementSpecifier) {
2337 RenderStyle* cachedPseudoStyle = usedStyle->getCachedPseudoStyle(pseudoElementSpecifier);
2338 return cachedPseudoStyle ? cachedPseudoStyle : usedStyle;
2339 } else
2340 return usedStyle;
2341 }
2342
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00002343 if (!inActiveDocument())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002344 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
2345 // document tree and figure out when to destroy the computed style for such elements.
2346 return 0;
2347
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002348 ElementRareData& rareData = ensureElementRareData();
2349 if (!rareData.computedStyle())
2350 rareData.setComputedStyle(document().styleForElementIgnoringPendingStylesheets(this));
2351 return pseudoElementSpecifier ? rareData.computedStyle()->getCachedPseudoStyle(pseudoElementSpecifier) : rareData.computedStyle();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002352}
2353
2354void Element::setStyleAffectedByEmpty()
2355{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002356 ensureElementRareData().setStyleAffectedByEmpty(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002357}
2358
2359void Element::setChildrenAffectedByHover(bool value)
2360{
2361 if (value || hasRareData())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002362 ensureElementRareData().setChildrenAffectedByHover(value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002363}
2364
2365void Element::setChildrenAffectedByActive(bool value)
2366{
2367 if (value || hasRareData())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002368 ensureElementRareData().setChildrenAffectedByActive(value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002369}
2370
2371void Element::setChildrenAffectedByDrag(bool value)
2372{
2373 if (value || hasRareData())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002374 ensureElementRareData().setChildrenAffectedByDrag(value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002375}
2376
2377void Element::setChildrenAffectedByFirstChildRules()
2378{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002379 ensureElementRareData().setChildrenAffectedByFirstChildRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002380}
2381
2382void Element::setChildrenAffectedByLastChildRules()
2383{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002384 ensureElementRareData().setChildrenAffectedByLastChildRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002385}
2386
2387void Element::setChildrenAffectedByDirectAdjacentRules()
2388{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002389 ensureElementRareData().setChildrenAffectedByDirectAdjacentRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002390}
2391
2392void Element::setChildrenAffectedByForwardPositionalRules()
2393{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002394 ensureElementRareData().setChildrenAffectedByForwardPositionalRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002395}
2396
2397void Element::setChildrenAffectedByBackwardPositionalRules()
2398{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002399 ensureElementRareData().setChildrenAffectedByBackwardPositionalRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002400}
2401
2402void Element::setChildIndex(unsigned index)
2403{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002404 ElementRareData& rareData = ensureElementRareData();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002405 if (RenderStyle* style = renderStyle())
2406 style->setUnique();
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002407 rareData.setChildIndex(index);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002408}
2409
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002410bool Element::childrenSupportStyleSharing() const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002411{
2412 if (!hasRareData())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002413 return true;
2414 return !rareDataChildrenAffectedByHover()
2415 && !rareDataChildrenAffectedByActive()
2416 && !rareDataChildrenAffectedByDrag()
2417 && !rareDataChildrenAffectedByFirstChildRules()
2418 && !rareDataChildrenAffectedByLastChildRules()
2419 && !rareDataChildrenAffectedByDirectAdjacentRules()
2420 && !rareDataChildrenAffectedByForwardPositionalRules()
2421 && !rareDataChildrenAffectedByBackwardPositionalRules();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002422}
2423
2424bool Element::rareDataStyleAffectedByEmpty() const
2425{
2426 ASSERT(hasRareData());
2427 return elementRareData()->styleAffectedByEmpty();
2428}
2429
2430bool Element::rareDataChildrenAffectedByHover() const
2431{
2432 ASSERT(hasRareData());
2433 return elementRareData()->childrenAffectedByHover();
2434}
2435
2436bool Element::rareDataChildrenAffectedByActive() const
2437{
2438 ASSERT(hasRareData());
2439 return elementRareData()->childrenAffectedByActive();
2440}
2441
2442bool Element::rareDataChildrenAffectedByDrag() const
2443{
2444 ASSERT(hasRareData());
2445 return elementRareData()->childrenAffectedByDrag();
2446}
2447
2448bool Element::rareDataChildrenAffectedByFirstChildRules() const
2449{
2450 ASSERT(hasRareData());
2451 return elementRareData()->childrenAffectedByFirstChildRules();
2452}
2453
2454bool Element::rareDataChildrenAffectedByLastChildRules() const
2455{
2456 ASSERT(hasRareData());
2457 return elementRareData()->childrenAffectedByLastChildRules();
2458}
2459
2460bool Element::rareDataChildrenAffectedByDirectAdjacentRules() const
2461{
2462 ASSERT(hasRareData());
2463 return elementRareData()->childrenAffectedByDirectAdjacentRules();
2464}
2465
2466bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
2467{
2468 ASSERT(hasRareData());
2469 return elementRareData()->childrenAffectedByForwardPositionalRules();
2470}
2471
2472bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
2473{
2474 ASSERT(hasRareData());
2475 return elementRareData()->childrenAffectedByBackwardPositionalRules();
2476}
2477
2478unsigned Element::rareDataChildIndex() const
2479{
2480 ASSERT(hasRareData());
2481 return elementRareData()->childIndex();
2482}
2483
2484void Element::setIsInCanvasSubtree(bool isInCanvasSubtree)
2485{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002486 ensureElementRareData().setIsInCanvasSubtree(isInCanvasSubtree);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002487}
2488
2489bool Element::isInCanvasSubtree() const
2490{
2491 return hasRareData() && elementRareData()->isInCanvasSubtree();
2492}
2493
Ben Murdoch591b9582013-07-10 11:41:44 +01002494void Element::setIsInsideRegion(bool value)
2495{
2496 if (value == isInsideRegion())
2497 return;
2498
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002499 ensureElementRareData().setIsInsideRegion(value);
Ben Murdoch591b9582013-07-10 11:41:44 +01002500}
2501
2502bool Element::isInsideRegion() const
2503{
2504 return hasRareData() ? elementRareData()->isInsideRegion() : false;
2505}
2506
2507void Element::setRegionOversetState(RegionOversetState state)
2508{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002509 ensureElementRareData().setRegionOversetState(state);
Ben Murdoch591b9582013-07-10 11:41:44 +01002510}
2511
2512RegionOversetState Element::regionOversetState() const
2513{
2514 return hasRareData() ? elementRareData()->regionOversetState() : RegionUndefined;
2515}
2516
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002517AtomicString Element::computeInheritedLanguage() const
2518{
2519 const Node* n = this;
2520 AtomicString value;
2521 // The language property is inherited, so we iterate over the parents to find the first language.
2522 do {
2523 if (n->isElementNode()) {
2524 if (const ElementData* elementData = toElement(n)->elementData()) {
2525 // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7
2526 if (const Attribute* attribute = elementData->getAttributeItem(XMLNames::langAttr))
2527 value = attribute->value();
2528 else if (const Attribute* attribute = elementData->getAttributeItem(HTMLNames::langAttr))
2529 value = attribute->value();
2530 }
2531 } else if (n->isDocumentNode()) {
2532 // checking the MIME content-language
2533 value = toDocument(n)->contentLanguage();
2534 }
2535
2536 n = n->parentNode();
2537 } while (n && value.isNull());
2538
2539 return value;
2540}
2541
2542Locale& Element::locale() const
2543{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002544 return document().getCachedLocale(computeInheritedLanguage());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002545}
2546
2547void Element::cancelFocusAppearanceUpdate()
2548{
2549 if (hasRareData())
2550 elementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002551 if (document().focusedElement() == this)
2552 document().cancelFocusAppearanceUpdate();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002553}
2554
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002555void Element::updateCallbackSelectors(RenderStyle* oldStyle, RenderStyle* newStyle)
2556{
2557 const Vector<String> emptyVector;
2558 const Vector<String>& oldCallbackSelectors = oldStyle ? oldStyle->callbackSelectors() : emptyVector;
2559 const Vector<String>& newCallbackSelectors = newStyle ? newStyle->callbackSelectors() : emptyVector;
2560
2561 CSSSelectorWatch::from(document()).updateSelectorMatches(oldCallbackSelectors, newCallbackSelectors);
2562}
2563
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002564void Element::normalizeAttributes()
2565{
2566 if (!hasAttributes())
2567 return;
2568 for (unsigned i = 0; i < attributeCount(); ++i) {
2569 if (RefPtr<Attr> attr = attrIfExists(attributeItem(i)->name()))
2570 attr->normalize();
2571 }
2572}
2573
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002574void Element::updatePseudoElement(PseudoId pseudoId, StyleRecalcChange change)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002575{
2576 PseudoElement* element = pseudoElement(pseudoId);
2577 if (element && (needsStyleRecalc() || shouldRecalcStyle(change, element))) {
2578 // PseudoElement styles hang off their parent element's style so if we needed
2579 // a style recalc we should Force one on the pseudo.
2580 element->recalcStyle(needsStyleRecalc() ? Force : change);
2581
2582 // Wait until our parent is not displayed or pseudoElementRendererIsNeeded
2583 // is false, otherwise we could continously create and destroy PseudoElements
2584 // when RenderObject::isChildAllowed on our parent returns false for the
2585 // PseudoElement's renderer for each style recalc.
2586 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01002587 elementRareData()->setPseudoElement(pseudoId, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002588 } else if (change >= Inherit || needsStyleRecalc())
2589 createPseudoElementIfNeeded(pseudoId);
2590}
2591
2592void Element::createPseudoElementIfNeeded(PseudoId pseudoId)
2593{
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002594 if (needsPseudoElement(pseudoId))
2595 createPseudoElement(pseudoId);
2596}
2597
2598bool Element::needsPseudoElement(PseudoId pseudoId) const
2599{
Ben Murdoche69819b2013-07-17 14:56:49 +01002600 if (pseudoId == BACKDROP && !isInTopLayer())
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002601 return false;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002602 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002603 return false;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002604 if (!renderer()->canHaveGeneratedChildren())
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002605 return false;
2606 return true;
2607}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002608
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002609void Element::createPseudoElement(PseudoId pseudoId)
2610{
2611 ASSERT(needsPseudoElement(pseudoId));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002612 ASSERT(!isPseudoElement());
2613 RefPtr<PseudoElement> element = PseudoElement::create(this, pseudoId);
Ben Murdoche69819b2013-07-17 14:56:49 +01002614 if (pseudoId == BACKDROP)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002615 document().addToTopLayer(element.get(), this);
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002616 element->insertedInto(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002617 element->attach();
Ben Murdoche69819b2013-07-17 14:56:49 +01002618
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002619 InspectorInstrumentation::pseudoElementCreated(element.get());
2620
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002621 ensureElementRareData().setPseudoElement(pseudoId, element.release());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002622}
2623
2624PseudoElement* Element::pseudoElement(PseudoId pseudoId) const
2625{
2626 return hasRareData() ? elementRareData()->pseudoElement(pseudoId) : 0;
2627}
2628
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002629RenderObject* Element::pseudoElementRenderer(PseudoId pseudoId) const
2630{
2631 if (PseudoElement* element = pseudoElement(pseudoId))
2632 return element->renderer();
2633 return 0;
2634}
2635
Ben Murdochdf957042013-08-06 11:01:27 +01002636bool Element::webkitMatchesSelector(const String& selector, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002637{
2638 if (selector.isEmpty()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01002639 es.throwUninformativeAndGenericDOMException(SyntaxError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002640 return false;
2641 }
2642
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00002643 SelectorQuery* selectorQuery = document().selectorQueryCache().add(selector, document(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002644 if (!selectorQuery)
2645 return false;
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002646 return selectorQuery->matches(*this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002647}
2648
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002649DOMTokenList* Element::classList()
2650{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002651 ElementRareData& rareData = ensureElementRareData();
2652 if (!rareData.classList())
2653 rareData.setClassList(ClassList::create(this));
2654 return rareData.classList();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002655}
2656
2657DOMStringMap* Element::dataset()
2658{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002659 ElementRareData& rareData = ensureElementRareData();
2660 if (!rareData.dataset())
2661 rareData.setDataset(DatasetDOMStringMap::create(this));
2662 return rareData.dataset();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002663}
2664
2665KURL Element::getURLAttribute(const QualifiedName& name) const
2666{
2667#if !ASSERT_DISABLED
2668 if (elementData()) {
2669 if (const Attribute* attribute = getAttributeItem(name))
2670 ASSERT(isURLAttribute(*attribute));
2671 }
2672#endif
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002673 return document().completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002674}
2675
2676KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
2677{
2678#if !ASSERT_DISABLED
2679 if (elementData()) {
2680 if (const Attribute* attribute = getAttributeItem(name))
2681 ASSERT(isURLAttribute(*attribute));
2682 }
2683#endif
2684 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
2685 if (value.isEmpty())
2686 return KURL();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002687 return document().completeURL(value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002688}
2689
2690int Element::getIntegralAttribute(const QualifiedName& attributeName) const
2691{
2692 return getAttribute(attributeName).string().toInt();
2693}
2694
2695void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
2696{
2697 // FIXME: Need an AtomicString version of String::number.
2698 setAttribute(attributeName, String::number(value));
2699}
2700
2701unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
2702{
2703 return getAttribute(attributeName).string().toUInt();
2704}
2705
2706void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
2707{
2708 // FIXME: Need an AtomicString version of String::number.
2709 setAttribute(attributeName, String::number(value));
2710}
2711
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002712bool Element::childShouldCreateRenderer(const Node& child) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002713{
2714 // 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 +01002715 if (child.isSVGElement())
2716 return child.hasTagName(SVGNames::svgTag) || isSVGElement();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002717
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002718 return ContainerNode::childShouldCreateRenderer(child);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002719}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002720
2721void Element::webkitRequestFullscreen()
2722{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002723 FullscreenElementStack::from(&document())->requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002724}
2725
2726void Element::webkitRequestFullScreen(unsigned short flags)
2727{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002728 FullscreenElementStack::from(&document())->requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002729}
2730
2731bool Element::containsFullScreenElement() const
2732{
2733 return hasRareData() && elementRareData()->containsFullScreenElement();
2734}
2735
2736void Element::setContainsFullScreenElement(bool flag)
2737{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002738 ensureElementRareData().setContainsFullScreenElement(flag);
Ben Murdoche69819b2013-07-17 14:56:49 +01002739 setNeedsStyleRecalc(SubtreeStyleChange);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002740}
2741
2742static Element* parentCrossingFrameBoundaries(Element* element)
2743{
2744 ASSERT(element);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002745 return element->parentElement() ? element->parentElement() : element->document().ownerElement();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002746}
2747
2748void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool flag)
2749{
2750 Element* element = this;
2751 while ((element = parentCrossingFrameBoundaries(element)))
2752 element->setContainsFullScreenElement(flag);
2753}
2754
2755bool Element::isInTopLayer() const
2756{
2757 return hasRareData() && elementRareData()->isInTopLayer();
2758}
2759
2760void Element::setIsInTopLayer(bool inTopLayer)
2761{
2762 if (isInTopLayer() == inTopLayer)
2763 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002764 ensureElementRareData().setIsInTopLayer(inTopLayer);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002765
2766 // We must ensure a reattach occurs so the renderer is inserted in the correct sibling order under RenderView according to its
2767 // top layer position, or in its usual place if not in the top layer.
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002768 lazyReattachIfAttached();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002769}
2770
2771void Element::webkitRequestPointerLock()
2772{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002773 if (document().page())
2774 document().page()->pointerLockController().requestPointerLock(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002775}
2776
2777SpellcheckAttributeState Element::spellcheckAttributeState() const
2778{
2779 const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
2780 if (value == nullAtom)
2781 return SpellcheckAttributeDefault;
2782 if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
2783 return SpellcheckAttributeTrue;
2784 if (equalIgnoringCase(value, "false"))
2785 return SpellcheckAttributeFalse;
2786
2787 return SpellcheckAttributeDefault;
2788}
2789
2790bool Element::isSpellCheckingEnabled() const
2791{
2792 for (const Element* element = this; element; element = element->parentOrShadowHostElement()) {
2793 switch (element->spellcheckAttributeState()) {
2794 case SpellcheckAttributeTrue:
2795 return true;
2796 case SpellcheckAttributeFalse:
2797 return false;
2798 case SpellcheckAttributeDefault:
2799 break;
2800 }
2801 }
2802
2803 return true;
2804}
2805
2806RenderRegion* Element::renderRegion() const
2807{
2808 if (renderer() && renderer()->isRenderRegion())
2809 return toRenderRegion(renderer());
2810
2811 return 0;
2812}
2813
Ben Murdoch591b9582013-07-10 11:41:44 +01002814bool Element::shouldMoveToFlowThread(RenderStyle* styleToUse) const
2815{
2816 ASSERT(styleToUse);
2817
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002818 if (FullscreenElementStack::isActiveFullScreenElement(this))
Ben Murdoch591b9582013-07-10 11:41:44 +01002819 return false;
2820
2821 if (isInShadowTree())
2822 return false;
2823
2824 if (styleToUse->flowThread().isEmpty())
2825 return false;
2826
2827 return !isRegisteredWithNamedFlow();
2828}
2829
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002830const AtomicString& Element::webkitRegionOverset() const
2831{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002832 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002833
2834 DEFINE_STATIC_LOCAL(AtomicString, undefinedState, ("undefined", AtomicString::ConstructFromLiteral));
2835 if (!RuntimeEnabledFeatures::cssRegionsEnabled() || !renderRegion())
2836 return undefinedState;
2837
Ben Murdoch591b9582013-07-10 11:41:44 +01002838 switch (renderRegion()->regionOversetState()) {
2839 case RegionFit: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002840 DEFINE_STATIC_LOCAL(AtomicString, fitState, ("fit", AtomicString::ConstructFromLiteral));
2841 return fitState;
2842 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002843 case RegionEmpty: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002844 DEFINE_STATIC_LOCAL(AtomicString, emptyState, ("empty", AtomicString::ConstructFromLiteral));
2845 return emptyState;
2846 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002847 case RegionOverset: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002848 DEFINE_STATIC_LOCAL(AtomicString, overflowState, ("overset", AtomicString::ConstructFromLiteral));
2849 return overflowState;
2850 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002851 case RegionUndefined:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002852 return undefinedState;
2853 }
2854
2855 ASSERT_NOT_REACHED();
2856 return undefinedState;
2857}
2858
2859Vector<RefPtr<Range> > Element::webkitGetRegionFlowRanges() const
2860{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002861 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002862
2863 Vector<RefPtr<Range> > rangeObjects;
2864 if (RuntimeEnabledFeatures::cssRegionsEnabled() && renderer() && renderer()->isRenderRegion()) {
2865 RenderRegion* region = toRenderRegion(renderer());
2866 if (region->isValid())
2867 region->getRanges(rangeObjects);
2868 }
2869
2870 return rangeObjects;
2871}
2872
2873#ifndef NDEBUG
2874bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
2875{
2876 if (name == HTMLNames::styleAttr)
2877 return false;
2878
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002879 if (isSVGElement())
2880 return !static_cast<const SVGElement*>(this)->isAnimatableAttribute(name);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002881
2882 return true;
2883}
2884#endif
2885
2886#ifdef DUMP_NODE_STATISTICS
2887bool Element::hasNamedNodeMap() const
2888{
2889 return hasRareData() && elementRareData()->attributeMap();
2890}
2891#endif
2892
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002893inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002894{
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002895 if (!inDocument() || isInShadowTree())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002896 return;
2897
2898 if (oldName == newName)
2899 return;
2900
Ben Murdochdf957042013-08-06 11:01:27 +01002901 if (shouldRegisterAsNamedItem())
2902 updateNamedItemRegistration(oldName, newName);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002903}
2904
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002905inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002906{
2907 if (!isInTreeScope())
2908 return;
2909
2910 if (oldId == newId)
2911 return;
2912
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002913 updateId(treeScope(), oldId, newId);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002914}
2915
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002916inline void Element::updateId(TreeScope& scope, const AtomicString& oldId, const AtomicString& newId)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002917{
2918 ASSERT(isInTreeScope());
2919 ASSERT(oldId != newId);
2920
2921 if (!oldId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002922 scope.removeElementById(oldId, this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002923 if (!newId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002924 scope.addElementById(newId, this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002925
Ben Murdochdf957042013-08-06 11:01:27 +01002926 if (shouldRegisterAsExtraNamedItem())
2927 updateExtraNamedItemRegistration(oldId, newId);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002928}
2929
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002930void Element::updateLabel(TreeScope& scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002931{
2932 ASSERT(hasTagName(labelTag));
2933
2934 if (!inDocument())
2935 return;
2936
2937 if (oldForAttributeValue == newForAttributeValue)
2938 return;
2939
2940 if (!oldForAttributeValue.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002941 scope.removeLabel(oldForAttributeValue, toHTMLLabelElement(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002942 if (!newForAttributeValue.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002943 scope.addLabel(newForAttributeValue, toHTMLLabelElement(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002944}
2945
Ben Murdoch7757ec22013-07-23 11:17:36 +01002946static bool hasSelectorForAttribute(Document* document, const AtomicString& localName)
2947{
2948 return document->styleResolver() && document->styleResolver()->ruleFeatureSet().hasSelectorForAttribute(localName);
2949}
2950
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002951void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
2952{
2953 if (isIdAttributeName(name))
2954 updateId(oldValue, newValue);
2955 else if (name == HTMLNames::nameAttr)
2956 updateName(oldValue, newValue);
2957 else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002958 TreeScope& scope = treeScope();
2959 if (scope.shouldCacheLabelsByForAttribute())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002960 updateLabel(scope, oldValue, newValue);
2961 }
2962
2963 if (oldValue != newValue) {
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00002964 if (inActiveDocument() && hasSelectorForAttribute(&document(), name.localName()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002965 setNeedsStyleRecalc();
Ben Murdoche69819b2013-07-17 14:56:49 +01002966
2967 if (isUpgradedCustomElement())
Ben Murdoch83750172013-07-24 10:36:59 +01002968 CustomElement::attributeDidChange(this, name.localName(), oldValue, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002969 }
2970
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00002971 if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(*this, name))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002972 recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue));
2973
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002974 InspectorInstrumentation::willModifyDOMAttr(this, oldValue, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002975}
2976
2977void Element::didAddAttribute(const QualifiedName& name, const AtomicString& value)
2978{
2979 attributeChanged(name, value);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002980 InspectorInstrumentation::didModifyDOMAttr(this, name.localName(), value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002981 dispatchSubtreeModifiedEvent();
2982}
2983
2984void Element::didModifyAttribute(const QualifiedName& name, const AtomicString& value)
2985{
2986 attributeChanged(name, value);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002987 InspectorInstrumentation::didModifyDOMAttr(this, name.localName(), value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002988 // Do not dispatch a DOMSubtreeModified event here; see bug 81141.
2989}
2990
2991void Element::didRemoveAttribute(const QualifiedName& name)
2992{
2993 attributeChanged(name, nullAtom);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002994 InspectorInstrumentation::didRemoveDOMAttr(this, name.localName());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002995 dispatchSubtreeModifiedEvent();
2996}
2997
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002998void Element::didMoveToNewDocument(Document& oldDocument)
Ben Murdoche69819b2013-07-17 14:56:49 +01002999{
3000 Node::didMoveToNewDocument(oldDocument);
3001
3002 // If the documents differ by quirks mode then they differ by case sensitivity
3003 // for class and id names so we need to go through the attribute change logic
3004 // to pick up the new casing in the ElementData.
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01003005 if (oldDocument.inQuirksMode() != document().inQuirksMode()) {
Ben Murdoche69819b2013-07-17 14:56:49 +01003006 if (hasID())
3007 setIdAttribute(getIdAttribute());
3008 if (hasClass())
3009 setAttribute(HTMLNames::classAttr, getClassAttribute());
3010 }
3011}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003012
Ben Murdochdf957042013-08-06 11:01:27 +01003013void Element::updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName)
3014{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003015 if (!document().isHTMLDocument())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01003016 return;
Ben Murdochdf957042013-08-06 11:01:27 +01003017
3018 if (!oldName.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003019 toHTMLDocument(document()).removeNamedItem(oldName);
Ben Murdochdf957042013-08-06 11:01:27 +01003020
3021 if (!newName.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003022 toHTMLDocument(document()).addNamedItem(newName);
Ben Murdochdf957042013-08-06 11:01:27 +01003023}
3024
3025void Element::updateExtraNamedItemRegistration(const AtomicString& oldId, const AtomicString& newId)
3026{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003027 if (!document().isHTMLDocument())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01003028 return;
Ben Murdochdf957042013-08-06 11:01:27 +01003029
3030 if (!oldId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003031 toHTMLDocument(document()).removeExtraNamedItem(oldId);
Ben Murdochdf957042013-08-06 11:01:27 +01003032
3033 if (!newId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003034 toHTMLDocument(document()).addExtraNamedItem(newId);
Ben Murdochdf957042013-08-06 11:01:27 +01003035}
3036
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003037PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
3038{
3039 if (HTMLCollection* collection = cachedHTMLCollection(type))
3040 return collection;
3041
3042 RefPtr<HTMLCollection> collection;
3043 if (type == TableRows) {
3044 ASSERT(hasTagName(tableTag));
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003045 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003046 } else if (type == SelectOptions) {
3047 ASSERT(hasTagName(selectTag));
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003048 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003049 } else if (type == FormControls) {
3050 ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003051 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003052 }
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003053 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003054}
3055
Ben Murdoch591b9582013-07-10 11:41:44 +01003056static void scheduleLayerUpdateCallback(Node* node)
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003057{
Ben Murdoche69819b2013-07-17 14:56:49 +01003058 // Notify the renderer even is the styles are identical since it may need to
3059 // create or destroy a RenderLayer.
3060 node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003061}
3062
Ben Murdoch591b9582013-07-10 11:41:44 +01003063void Element::scheduleLayerUpdate()
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003064{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003065 if (document().inStyleRecalc())
3066 PostAttachCallbacks::queueCallback(scheduleLayerUpdateCallback, this);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003067 else
Ben Murdoche69819b2013-07-17 14:56:49 +01003068 scheduleLayerUpdateCallback(this);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003069}
3070
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003071HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
3072{
3073 return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0;
3074}
3075
3076IntSize Element::savedLayerScrollOffset() const
3077{
3078 return hasRareData() ? elementRareData()->savedLayerScrollOffset() : IntSize();
3079}
3080
3081void Element::setSavedLayerScrollOffset(const IntSize& size)
3082{
3083 if (size.isZero() && !hasRareData())
3084 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003085 ensureElementRareData().setSavedLayerScrollOffset(size);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003086}
3087
3088PassRefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
3089{
3090 if (AttrNodeList* attrNodeList = attrNodeListForElement(this))
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003091 return findAttrNodeInList(*attrNodeList, name);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003092 return 0;
3093}
3094
3095PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name)
3096{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003097 AttrNodeList& attrNodeList = ensureAttrNodeListForElement(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003098 RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
3099 if (!attrNode) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003100 attrNode = Attr::create(*this, name);
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003101 treeScope().adoptIfNeeded(*attrNode);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003102 attrNodeList.append(attrNode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003103 }
3104 return attrNode.release();
3105}
3106
3107void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value)
3108{
3109 ASSERT(hasSyntheticAttrChildNodes());
3110 attrNode->detachFromElementWithValue(value);
3111
3112 AttrNodeList* attrNodeList = attrNodeListForElement(this);
3113 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
3114 if (attrNodeList->at(i)->qualifiedName() == attrNode->qualifiedName()) {
3115 attrNodeList->remove(i);
3116 if (attrNodeList->isEmpty())
3117 removeAttrNodeListForElement(this);
3118 return;
3119 }
3120 }
3121 ASSERT_NOT_REACHED();
3122}
3123
3124void Element::detachAllAttrNodesFromElement()
3125{
3126 AttrNodeList* attrNodeList = attrNodeListForElement(this);
3127 ASSERT(attrNodeList);
3128
3129 for (unsigned i = 0; i < attributeCount(); ++i) {
3130 const Attribute* attribute = attributeItem(i);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003131 if (RefPtr<Attr> attrNode = findAttrNodeInList(*attrNodeList, attribute->name()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003132 attrNode->detachFromElementWithValue(attribute->value());
3133 }
3134
3135 removeAttrNodeListForElement(this);
3136}
3137
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003138void Element::willRecalcStyle(StyleRecalcChange)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003139{
3140 ASSERT(hasCustomStyleCallbacks());
3141}
3142
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003143void Element::didRecalcStyle(StyleRecalcChange)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003144{
3145 ASSERT(hasCustomStyleCallbacks());
3146}
3147
3148
3149PassRefPtr<RenderStyle> Element::customStyleForRenderer()
3150{
3151 ASSERT(hasCustomStyleCallbacks());
3152 return 0;
3153}
3154
3155void Element::cloneAttributesFromElement(const Element& other)
3156{
3157 if (hasSyntheticAttrChildNodes())
3158 detachAllAttrNodesFromElement();
3159
3160 other.synchronizeAllAttributes();
3161 if (!other.m_elementData) {
3162 m_elementData.clear();
3163 return;
3164 }
3165
3166 const AtomicString& oldID = getIdAttribute();
3167 const AtomicString& newID = other.getIdAttribute();
3168
3169 if (!oldID.isNull() || !newID.isNull())
3170 updateId(oldID, newID);
3171
3172 const AtomicString& oldName = getNameAttribute();
3173 const AtomicString& newName = other.getNameAttribute();
3174
3175 if (!oldName.isNull() || !newName.isNull())
3176 updateName(oldName, newName);
3177
Ben Murdoche69819b2013-07-17 14:56:49 +01003178 // Quirks mode makes class and id not case sensitive. We can't share the ElementData
3179 // if the idForStyleResolution and the className need different casing.
3180 bool ownerDocumentsHaveDifferentCaseSensitivity = false;
3181 if (other.hasClass() || other.hasID())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003182 ownerDocumentsHaveDifferentCaseSensitivity = other.document().inQuirksMode() != document().inQuirksMode();
Ben Murdoche69819b2013-07-17 14:56:49 +01003183
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003184 // 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 +01003185 // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes,
3186 // and sharing the data won't result in different case sensitivity of class or id.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003187 if (other.m_elementData->isUnique()
Ben Murdoche69819b2013-07-17 14:56:49 +01003188 && !ownerDocumentsHaveDifferentCaseSensitivity
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003189 && !other.m_elementData->presentationAttributeStyle()
3190 && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper()))
3191 const_cast<Element&>(other).m_elementData = static_cast<const UniqueElementData*>(other.m_elementData.get())->makeShareableCopy();
3192
Ben Murdoche69819b2013-07-17 14:56:49 +01003193 if (!other.m_elementData->isUnique() && !ownerDocumentsHaveDifferentCaseSensitivity)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003194 m_elementData = other.m_elementData;
3195 else
3196 m_elementData = other.m_elementData->makeUniqueCopy();
3197
3198 for (unsigned i = 0; i < m_elementData->length(); ++i) {
3199 const Attribute* attribute = const_cast<const ElementData*>(m_elementData.get())->attributeItem(i);
3200 attributeChangedFromParserOrByCloning(attribute->name(), attribute->value(), ModifiedByCloning);
3201 }
3202}
3203
3204void Element::cloneDataFromElement(const Element& other)
3205{
3206 cloneAttributesFromElement(other);
3207 copyNonAttributePropertiesFromElement(other);
3208}
3209
3210void Element::createUniqueElementData()
3211{
3212 if (!m_elementData)
3213 m_elementData = UniqueElementData::create();
3214 else {
3215 ASSERT(!m_elementData->isUnique());
3216 m_elementData = static_cast<ShareableElementData*>(m_elementData.get())->makeUniqueCopy();
3217 }
3218}
3219
Ben Murdoch1fad5ca2013-08-07 11:05:11 +01003220InputMethodContext* Element::inputMethodContext()
Torne (Richard Coles)81a51572013-05-13 16:52:28 +01003221{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003222 return ensureElementRareData().ensureInputMethodContext(toHTMLElement(this));
Torne (Richard Coles)81a51572013-05-13 16:52:28 +01003223}
3224
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00003225bool Element::hasInputMethodContext() const
3226{
3227 return hasRareData() && elementRareData()->hasInputMethodContext();
3228}
3229
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003230bool Element::hasPendingResources() const
3231{
3232 return hasRareData() && elementRareData()->hasPendingResources();
3233}
3234
3235void Element::setHasPendingResources()
3236{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003237 ensureElementRareData().setHasPendingResources(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003238}
3239
3240void Element::clearHasPendingResources()
3241{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003242 ensureElementRareData().setHasPendingResources(false);
Ben Murdoch591b9582013-07-10 11:41:44 +01003243}
3244
3245void Element::synchronizeStyleAttributeInternal() const
3246{
3247 ASSERT(isStyledElement());
3248 ASSERT(elementData());
3249 ASSERT(elementData()->m_styleAttributeIsDirty);
3250 elementData()->m_styleAttributeIsDirty = false;
3251 if (const StylePropertySet* inlineStyle = this->inlineStyle())
3252 const_cast<Element*>(this)->setSynchronizedLazyAttribute(styleAttr, inlineStyle->asText());
3253}
3254
3255CSSStyleDeclaration* Element::style()
3256{
3257 if (!isStyledElement())
3258 return 0;
3259 return ensureMutableInlineStyle()->ensureInlineCSSStyleDeclaration(this);
3260}
3261
3262MutableStylePropertySet* Element::ensureMutableInlineStyle()
3263{
3264 ASSERT(isStyledElement());
3265 RefPtr<StylePropertySet>& inlineStyle = ensureUniqueElementData()->m_inlineStyle;
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003266 if (!inlineStyle) {
3267 CSSParserMode mode = (!isHTMLElement() || document().inQuirksMode()) ? HTMLQuirksMode : HTMLStandardMode;
3268 inlineStyle = MutableStylePropertySet::create(mode);
3269 }
Ben Murdoch591b9582013-07-10 11:41:44 +01003270 else if (!inlineStyle->isMutable())
3271 inlineStyle = inlineStyle->mutableCopy();
3272 ASSERT(inlineStyle->isMutable());
3273 return static_cast<MutableStylePropertySet*>(inlineStyle.get());
3274}
3275
3276PropertySetCSSStyleDeclaration* Element::inlineStyleCSSOMWrapper()
3277{
3278 if (!inlineStyle() || !inlineStyle()->hasCSSOMWrapper())
3279 return 0;
3280 PropertySetCSSStyleDeclaration* cssomWrapper = ensureMutableInlineStyle()->cssStyleDeclaration();
3281 ASSERT(cssomWrapper && cssomWrapper->parentElement() == this);
3282 return cssomWrapper;
3283}
3284
3285inline void Element::setInlineStyleFromString(const AtomicString& newStyleString)
3286{
3287 ASSERT(isStyledElement());
3288 RefPtr<StylePropertySet>& inlineStyle = elementData()->m_inlineStyle;
3289
3290 // Avoid redundant work if we're using shared attribute data with already parsed inline style.
3291 if (inlineStyle && !elementData()->isUnique())
3292 return;
3293
3294 // We reconstruct the property set instead of mutating if there is no CSSOM wrapper.
3295 // This makes wrapperless property sets immutable and so cacheable.
3296 if (inlineStyle && !inlineStyle->isMutable())
3297 inlineStyle.clear();
3298
3299 if (!inlineStyle) {
3300 inlineStyle = CSSParser::parseInlineStyleDeclaration(newStyleString, this);
3301 } else {
3302 ASSERT(inlineStyle->isMutable());
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003303 static_pointer_cast<MutableStylePropertySet>(inlineStyle)->parseDeclaration(newStyleString, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003304 }
3305}
3306
3307void Element::styleAttributeChanged(const AtomicString& newStyleString, AttributeModificationReason modificationReason)
3308{
3309 ASSERT(isStyledElement());
3310 WTF::OrdinalNumber startLineNumber = WTF::OrdinalNumber::beforeFirst();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003311 if (document().scriptableDocumentParser() && !document().isInDocumentWrite())
3312 startLineNumber = document().scriptableDocumentParser()->lineNumber();
Ben Murdoch591b9582013-07-10 11:41:44 +01003313
3314 if (newStyleString.isNull()) {
3315 if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
3316 cssomWrapper->clearParentElement();
3317 ensureUniqueElementData()->m_inlineStyle.clear();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003318 } else if (modificationReason == ModifiedByCloning || document().contentSecurityPolicy()->allowInlineStyle(document().url(), startLineNumber)) {
Ben Murdoch591b9582013-07-10 11:41:44 +01003319 setInlineStyleFromString(newStyleString);
3320 }
3321
3322 elementData()->m_styleAttributeIsDirty = false;
3323
Ben Murdoche69819b2013-07-17 14:56:49 +01003324 setNeedsStyleRecalc(LocalStyleChange);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003325 InspectorInstrumentation::didInvalidateStyleAttr(this);
Ben Murdoch591b9582013-07-10 11:41:44 +01003326}
3327
3328void Element::inlineStyleChanged()
3329{
3330 ASSERT(isStyledElement());
Ben Murdoche69819b2013-07-17 14:56:49 +01003331 setNeedsStyleRecalc(LocalStyleChange);
Ben Murdoch591b9582013-07-10 11:41:44 +01003332 ASSERT(elementData());
3333 elementData()->m_styleAttributeIsDirty = true;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003334 InspectorInstrumentation::didInvalidateStyleAttr(this);
Ben Murdoch591b9582013-07-10 11:41:44 +01003335}
3336
3337bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
3338{
3339 ASSERT(isStyledElement());
3340 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
3341 inlineStyleChanged();
3342 return true;
3343}
3344
3345bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
3346{
3347 ASSERT(isStyledElement());
3348 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
3349 inlineStyleChanged();
3350 return true;
3351}
3352
3353bool Element::setInlineStyleProperty(CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit, bool important)
3354{
3355 ASSERT(isStyledElement());
3356 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createValue(value, unit), important);
3357 inlineStyleChanged();
3358 return true;
3359}
3360
3361bool Element::setInlineStyleProperty(CSSPropertyID propertyID, const String& value, bool important)
3362{
3363 ASSERT(isStyledElement());
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003364 bool changes = ensureMutableInlineStyle()->setProperty(propertyID, value, important, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003365 if (changes)
3366 inlineStyleChanged();
3367 return changes;
3368}
3369
3370bool Element::removeInlineStyleProperty(CSSPropertyID propertyID)
3371{
3372 ASSERT(isStyledElement());
3373 if (!inlineStyle())
3374 return false;
3375 bool changes = ensureMutableInlineStyle()->removeProperty(propertyID);
3376 if (changes)
3377 inlineStyleChanged();
3378 return changes;
3379}
3380
3381void Element::removeAllInlineStyleProperties()
3382{
3383 ASSERT(isStyledElement());
3384 if (!inlineStyle() || inlineStyle()->isEmpty())
3385 return;
3386 ensureMutableInlineStyle()->clear();
3387 inlineStyleChanged();
3388}
3389
3390void Element::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
3391{
3392 ASSERT(isStyledElement());
3393 if (const StylePropertySet* inlineStyle = elementData() ? elementData()->inlineStyle() : 0)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003394 inlineStyle->addSubresourceStyleURLs(urls, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003395}
3396
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003397void Element::updatePresentationAttributeStyle()
Ben Murdoch591b9582013-07-10 11:41:44 +01003398{
Ben Murdoch591b9582013-07-10 11:41:44 +01003399 // ShareableElementData doesn't store presentation attribute style, so make sure we have a UniqueElementData.
3400 UniqueElementData* elementData = ensureUniqueElementData();
Ben Murdoch591b9582013-07-10 11:41:44 +01003401 elementData->m_presentationAttributeStyleIsDirty = false;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003402 elementData->m_presentationAttributeStyle = computePresentationAttributeStyle(*this);
Ben Murdoch591b9582013-07-10 11:41:44 +01003403}
3404
3405void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, CSSValueID identifier)
3406{
3407 ASSERT(isStyledElement());
3408 style->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier));
3409}
3410
3411void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit)
3412{
3413 ASSERT(isStyledElement());
3414 style->setProperty(propertyID, cssValuePool().createValue(value, unit));
3415}
3416
3417void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, const String& value)
3418{
3419 ASSERT(isStyledElement());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01003420 style->setProperty(propertyID, value, false);
Ben Murdoch591b9582013-07-10 11:41:44 +01003421}
3422
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003423bool Element::supportsStyleSharing() const
3424{
3425 if (!isStyledElement() || !parentElement())
3426 return false;
3427 // If the element has inline style it is probably unique.
3428 if (inlineStyle())
3429 return false;
3430 if (isSVGElement() && toSVGElement(this)->animatedSMILStyleProperties())
3431 return false;
3432 // Ids stop style sharing if they show up in the stylesheets.
3433 if (hasID() && document().styleResolver()->hasRulesForId(idForStyleResolution()))
3434 return false;
3435 // Active and hovered elements always make a chain towards the document node
3436 // and no siblings or cousins will have the same state.
3437 if (hovered())
3438 return false;
3439 if (active())
3440 return false;
3441 if (focused())
3442 return false;
3443 if (!parentElement()->childrenSupportStyleSharing())
3444 return false;
3445 if (hasScopedHTMLStyleChild())
3446 return false;
3447 if (this == document().cssTarget())
3448 return false;
3449 if (isHTMLElement() && toHTMLElement(this)->hasDirectionAuto())
3450 return false;
3451 if (hasActiveAnimations())
3452 return false;
3453 if (shadow() && shadow()->containsActiveStyles())
3454 return false;
3455 // Turn off style sharing for elements that can gain layers for reasons outside of the style system.
3456 // See comments in RenderObject::setStyle().
3457 // FIXME: Why does gaining a layer from outside the style system require disabling sharing?
3458 if (hasTagName(iframeTag)
3459 || hasTagName(frameTag)
3460 || hasTagName(embedTag)
3461 || hasTagName(objectTag)
3462 || hasTagName(appletTag)
3463 || hasTagName(canvasTag))
3464 return false;
3465 // FIXME: We should share style for option and optgroup whenever possible.
3466 // Before doing so, we need to resolve issues in HTMLSelectElement::recalcListItems
3467 // and RenderMenuList::setText. See also https://bugs.webkit.org/show_bug.cgi?id=88405
3468 if (hasTagName(optionTag) || hasTagName(optgroupTag))
3469 return false;
3470 if (FullscreenElementStack::isActiveFullScreenElement(this))
3471 return false;
3472 return true;
3473}
3474
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003475} // namespace WebCore