blob: 369bf395fcdf353872a0689f0b962b9a078bb64d [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 "CSSValueKeywords.h"
Ben Murdoch7757ec22013-07-23 11:17:36 +010030#include "RuntimeEnabledFeatures.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010031#include "SVGNames.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010032#include "XMLNames.h"
Ben Murdochdf957042013-08-06 11:01:27 +010033#include "bindings/v8/ExceptionState.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010034#include "core/accessibility/AXObjectCache.h"
Ben Murdoch83750172013-07-24 10:36:59 +010035#include "core/animation/DocumentTimeline.h"
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +010036#include "core/animation/css/CSSAnimations.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010037#include "core/css/CSSParser.h"
38#include "core/css/CSSStyleSheet.h"
39#include "core/css/CSSValuePool.h"
40#include "core/css/PropertySetCSSStyleDeclaration.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010041#include "core/css/StylePropertySet.h"
Torne (Richard Coles)81a51572013-05-13 16:52:28 +010042#include "core/css/resolver/StyleResolver.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010043#include "core/dom/Attr.h"
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010044#include "core/dom/CSSSelectorWatch.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010045#include "core/dom/ClientRect.h"
46#include "core/dom/ClientRectList.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010047#include "core/dom/DatasetDOMStringMap.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010048#include "core/dom/DocumentSharedObjectPool.h"
49#include "core/dom/ElementRareData.h"
50#include "core/dom/ExceptionCode.h"
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +010051#include "core/dom/FullscreenElementStack.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010052#include "core/dom/MutationObserverInterestGroup.h"
53#include "core/dom/MutationRecord.h"
54#include "core/dom/NamedNodeMap.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010055#include "core/dom/NodeRenderStyle.h"
56#include "core/dom/NodeRenderingContext.h"
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +010057#include "core/dom/PostAttachCallbacks.h"
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +010058#include "core/dom/PresentationAttributeStyle.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010059#include "core/dom/PseudoElement.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010060#include "core/dom/ScriptableDocumentParser.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010061#include "core/dom/SelectorQuery.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010062#include "core/dom/Text.h"
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010063#include "core/dom/custom/CustomElement.h"
64#include "core/dom/custom/CustomElementRegistrationContext.h"
Torne (Richard Coles)e5249552013-05-15 11:35:13 +010065#include "core/dom/shadow/InsertionPoint.h"
66#include "core/dom/shadow/ShadowRoot.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010067#include "core/editing/FrameSelection.h"
68#include "core/editing/TextIterator.h"
69#include "core/editing/htmlediting.h"
Torne (Richard Coles)19cde672013-11-06 12:28:04 +000070#include "core/editing/markup.h"
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010071#include "core/events/EventDispatcher.h"
72#include "core/events/FocusEvent.h"
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +010073#include "core/frame/ContentSecurityPolicy.h"
74#include "core/frame/Frame.h"
75#include "core/frame/FrameView.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010076#include "core/html/ClassList.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010077#include "core/html/HTMLCollection.h"
78#include "core/html/HTMLDocument.h"
79#include "core/html/HTMLElement.h"
80#include "core/html/HTMLFormControlsCollection.h"
81#include "core/html/HTMLFrameOwnerElement.h"
82#include "core/html/HTMLLabelElement.h"
83#include "core/html/HTMLOptionsCollection.h"
84#include "core/html/HTMLTableRowsCollection.h"
Torne (Richard Coles)19cde672013-11-06 12:28:04 +000085#include "core/html/HTMLTemplateElement.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010086#include "core/html/parser/HTMLParserIdioms.h"
Torne (Richard Coles)51b29062013-11-28 11:56:03 +000087#include "core/inspector/InspectorInstrumentation.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010088#include "core/page/FocusController.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010089#include "core/page/Page.h"
90#include "core/page/PointerLockController.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010091#include "core/rendering/FlowThreadController.h"
Torne (Richard Coles)51b29062013-11-28 11:56:03 +000092#include "core/rendering/RenderNamedFlowFragment.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010093#include "core/rendering/RenderView.h"
94#include "core/rendering/RenderWidget.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010095#include "core/svg/SVGDocumentExtensions.h"
96#include "core/svg/SVGElement.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010097#include "wtf/BitVector.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010098#include "wtf/HashFunctions.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010099#include "wtf/text/CString.h"
Ben Murdoch591b9582013-07-10 11:41:44 +0100100#include "wtf/text/TextPosition.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100101
102namespace WebCore {
103
104using namespace HTMLNames;
105using namespace XMLNames;
106
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100107class StyleResolverParentPusher {
108public:
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000109 explicit StyleResolverParentPusher(Element& parent)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100110 : m_parent(parent)
111 , m_pushedStyleResolver(0)
112 {
113 }
114 void push()
115 {
116 if (m_pushedStyleResolver)
117 return;
Torne (Richard Coles)a854de02013-12-18 16:25:25 +0000118 m_pushedStyleResolver = &m_parent.document().ensureStyleResolver();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100119 m_pushedStyleResolver->pushParentElement(m_parent);
120 }
121 ~StyleResolverParentPusher()
122 {
123
124 if (!m_pushedStyleResolver)
125 return;
126
127 // This tells us that our pushed style selector is in a bad state,
128 // so we should just bail out in that scenario.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000129 ASSERT(m_pushedStyleResolver == m_parent.document().styleResolver());
130 if (m_pushedStyleResolver != m_parent.document().styleResolver())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100131 return;
132
133 m_pushedStyleResolver->popParentElement(m_parent);
134 }
135
136private:
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000137 Element& m_parent;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100138 StyleResolver* m_pushedStyleResolver;
139};
140
141typedef Vector<RefPtr<Attr> > AttrNodeList;
142typedef HashMap<Element*, OwnPtr<AttrNodeList> > AttrNodeListMap;
143
144static AttrNodeListMap& attrNodeListMap()
145{
146 DEFINE_STATIC_LOCAL(AttrNodeListMap, map, ());
147 return map;
148}
149
150static AttrNodeList* attrNodeListForElement(Element* element)
151{
152 if (!element->hasSyntheticAttrChildNodes())
153 return 0;
154 ASSERT(attrNodeListMap().contains(element));
155 return attrNodeListMap().get(element);
156}
157
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100158static AttrNodeList& ensureAttrNodeListForElement(Element* element)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100159{
160 if (element->hasSyntheticAttrChildNodes()) {
161 ASSERT(attrNodeListMap().contains(element));
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100162 return *attrNodeListMap().get(element);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100163 }
164 ASSERT(!attrNodeListMap().contains(element));
165 element->setHasSyntheticAttrChildNodes(true);
166 AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList));
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100167 return *result.iterator->value;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100168}
169
170static void removeAttrNodeListForElement(Element* element)
171{
172 ASSERT(element->hasSyntheticAttrChildNodes());
173 ASSERT(attrNodeListMap().contains(element));
174 attrNodeListMap().remove(element);
175 element->setHasSyntheticAttrChildNodes(false);
176}
177
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000178static Attr* findAttrNodeInList(const AttrNodeList& attrNodeList, const QualifiedName& name)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100179{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000180 AttrNodeList::const_iterator end = attrNodeList.end();
181 for (AttrNodeList::const_iterator it = attrNodeList.begin(); it != end; ++it) {
182 if ((*it)->qualifiedName() == name)
183 return it->get();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100184 }
185 return 0;
186}
187
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100188PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document)
189{
190 return adoptRef(new Element(tagName, document, CreateElement));
191}
192
193Element::~Element()
194{
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000195 // When the document is not destroyed, an element that was part of a named flow
196 // content nodes should have been removed from the content nodes collection
197 // and the inNamedFlow flag reset.
198 ASSERT(!document().renderView() || !inNamedFlow());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100199
Ben Murdoch591b9582013-07-10 11:41:44 +0100200 if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
201 cssomWrapper->clearParentElement();
202
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100203 if (hasRareData()) {
204 ElementRareData* data = elementRareData();
205 data->setPseudoElement(BEFORE, 0);
206 data->setPseudoElement(AFTER, 0);
Ben Murdoche69819b2013-07-17 14:56:49 +0100207 data->setPseudoElement(BACKDROP, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100208 data->clearShadow();
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100209
210 if (RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
211 if (ActiveAnimations* activeAnimations = data->activeAnimations())
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000212 activeAnimations->cssAnimations().cancel();
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100213 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100214 }
215
Ben Murdoch83750172013-07-24 10:36:59 +0100216 if (isCustomElement())
217 CustomElement::wasDestroyed(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100218
219 if (hasSyntheticAttrChildNodes())
220 detachAllAttrNodesFromElement();
221
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100222 if (hasPendingResources()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100223 document().accessSVGExtensions()->removeElementFromPendingResources(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100224 ASSERT(!hasPendingResources());
225 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100226}
227
228inline ElementRareData* Element::elementRareData() const
229{
230 ASSERT(hasRareData());
231 return static_cast<ElementRareData*>(rareData());
232}
233
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100234inline ElementRareData& Element::ensureElementRareData()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100235{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100236 return static_cast<ElementRareData&>(ensureRareData());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100237}
238
239void Element::clearTabIndexExplicitlyIfNeeded()
240{
241 if (hasRareData())
242 elementRareData()->clearTabIndexExplicitly();
243}
244
245void Element::setTabIndexExplicitly(short tabIndex)
246{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100247 ensureElementRareData().setTabIndexExplicitly(tabIndex);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100248}
249
250bool Element::supportsFocus() const
251{
252 return hasRareData() && elementRareData()->tabIndexSetExplicitly();
253}
254
255short Element::tabIndex() const
256{
257 return hasRareData() ? elementRareData()->tabIndex() : 0;
258}
259
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100260bool Element::rendererIsFocusable() const
261{
262 // Elements in canvas fallback content are not rendered, but they are allowed to be
263 // focusable as long as their canvas is displayed and visible.
264 if (isInCanvasSubtree()) {
265 const Element* e = this;
266 while (e && !e->hasLocalName(canvasTag))
267 e = e->parentElement();
268 ASSERT(e);
269 return e->renderer() && e->renderer()->style()->visibility() == VISIBLE;
270 }
271
272 // FIXME: These asserts should be in Node::isFocusable, but there are some
Ben Murdoche69819b2013-07-17 14:56:49 +0100273 // callsites like Document::setFocusedElement that would currently fail on
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100274 // them. See crbug.com/251163
275 if (renderer()) {
276 ASSERT(!renderer()->needsLayout());
277 } else {
278 // We can't just use needsStyleRecalc() because if the node is in a
279 // display:none tree it might say it needs style recalc but the whole
280 // document is actually up to date.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100281 ASSERT(!document().childNeedsStyleRecalc());
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100282 }
283
284 // FIXME: Even if we are not visible, we might have a child that is visible.
285 // Hyatt wants to fix that some day with a "has visible content" flag or the like.
286 if (!renderer() || renderer()->style()->visibility() != VISIBLE)
287 return false;
288
289 return true;
290}
291
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100292PassRefPtr<Node> Element::cloneNode(bool deep)
293{
294 return deep ? cloneElementWithChildren() : cloneElementWithoutChildren();
295}
296
297PassRefPtr<Element> Element::cloneElementWithChildren()
298{
299 RefPtr<Element> clone = cloneElementWithoutChildren();
300 cloneChildNodes(clone.get());
301 return clone.release();
302}
303
304PassRefPtr<Element> Element::cloneElementWithoutChildren()
305{
306 RefPtr<Element> clone = cloneElementWithoutAttributesAndChildren();
307 // This will catch HTML elements in the wrong namespace that are not correctly copied.
308 // This is a sanity check as HTML overloads some of the DOM methods.
309 ASSERT(isHTMLElement() == clone->isHTMLElement());
310
311 clone->cloneDataFromElement(*this);
312 return clone.release();
313}
314
315PassRefPtr<Element> Element::cloneElementWithoutAttributesAndChildren()
316{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100317 return document().createElement(tagQName(), false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100318}
319
320PassRefPtr<Attr> Element::detachAttribute(size_t index)
321{
322 ASSERT(elementData());
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100323 const Attribute* attribute = elementData()->attributeItem(index);
324 RefPtr<Attr> attrNode = attrIfExists(attribute->name());
325 if (attrNode)
326 detachAttrNodeAtIndex(attrNode.get(), index);
327 else {
328 attrNode = Attr::create(document(), attribute->name(), attribute->value());
329 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
330 }
331 return attrNode.release();
332}
333
334void Element::detachAttrNodeAtIndex(Attr* attr, size_t index)
335{
336 ASSERT(attr);
337 ASSERT(elementData());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100338
339 const Attribute* attribute = elementData()->attributeItem(index);
340 ASSERT(attribute);
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100341 ASSERT(attribute->name() == attr->qualifiedName());
342 detachAttrNodeFromElementWithValue(attr, attribute->value());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100343 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100344}
345
346void Element::removeAttribute(const QualifiedName& name)
347{
348 if (!elementData())
349 return;
350
351 size_t index = elementData()->getAttributeItemIndex(name);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100352 if (index == kNotFound)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100353 return;
354
355 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
356}
357
358void Element::setBooleanAttribute(const QualifiedName& name, bool value)
359{
360 if (value)
361 setAttribute(name, emptyAtom);
362 else
363 removeAttribute(name);
364}
365
366NamedNodeMap* Element::attributes() const
367{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100368 ElementRareData& rareData = const_cast<Element*>(this)->ensureElementRareData();
369 if (NamedNodeMap* attributeMap = rareData.attributeMap())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100370 return attributeMap;
371
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100372 rareData.setAttributeMap(NamedNodeMap::create(const_cast<Element*>(this)));
373 return rareData.attributeMap();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100374}
375
Ben Murdoch83750172013-07-24 10:36:59 +0100376ActiveAnimations* Element::activeAnimations() const
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100377{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000378 if (hasRareData())
Ben Murdoch83750172013-07-24 10:36:59 +0100379 return elementRareData()->activeAnimations();
380 return 0;
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100381}
382
Ben Murdoch83750172013-07-24 10:36:59 +0100383ActiveAnimations* Element::ensureActiveAnimations()
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100384{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100385 ElementRareData& rareData = ensureElementRareData();
386 if (!rareData.activeAnimations())
387 rareData.setActiveAnimations(adoptPtr(new ActiveAnimations()));
388 return rareData.activeAnimations();
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100389}
390
391bool Element::hasActiveAnimations() const
392{
Torne (Richard Coles)a854de02013-12-18 16:25:25 +0000393 if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled())
Ben Murdoch83750172013-07-24 10:36:59 +0100394 return false;
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100395
Ben Murdoch83750172013-07-24 10:36:59 +0100396 if (!hasRareData())
397 return false;
398
399 ActiveAnimations* activeAnimations = elementRareData()->activeAnimations();
400 return activeAnimations && !activeAnimations->isEmpty();
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100401}
402
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100403Node::NodeType Element::nodeType() const
404{
405 return ELEMENT_NODE;
406}
407
408bool Element::hasAttribute(const QualifiedName& name) const
409{
410 return hasAttributeNS(name.namespaceURI(), name.localName());
411}
412
413void Element::synchronizeAllAttributes() const
414{
415 if (!elementData())
416 return;
417 if (elementData()->m_styleAttributeIsDirty) {
418 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100419 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100420 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100421 if (elementData()->m_animatedSVGAttributesAreDirty) {
422 ASSERT(isSVGElement());
423 toSVGElement(this)->synchronizeAnimatedSVGAttribute(anyQName());
424 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100425}
426
427inline void Element::synchronizeAttribute(const QualifiedName& name) const
428{
429 if (!elementData())
430 return;
431 if (UNLIKELY(name == styleAttr && elementData()->m_styleAttributeIsDirty)) {
432 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100433 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100434 return;
435 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100436 if (UNLIKELY(elementData()->m_animatedSVGAttributesAreDirty)) {
437 ASSERT(isSVGElement());
438 toSVGElement(this)->synchronizeAnimatedSVGAttribute(name);
439 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100440}
441
Torne (Richard Coles)a854de02013-12-18 16:25:25 +0000442void Element::synchronizeAttribute(const AtomicString& localName) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100443{
444 // This version of synchronizeAttribute() is streamlined for the case where you don't have a full QualifiedName,
445 // e.g when called from DOM API.
446 if (!elementData())
447 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100448 if (elementData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(localName, styleAttr.localName(), shouldIgnoreAttributeCase())) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100449 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100450 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100451 return;
452 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100453 if (elementData()->m_animatedSVGAttributesAreDirty) {
454 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
455 ASSERT(isSVGElement());
456 static_cast<const SVGElement*>(this)->synchronizeAnimatedSVGAttribute(QualifiedName(nullAtom, localName, nullAtom));
457 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100458}
459
460const AtomicString& Element::getAttribute(const QualifiedName& name) const
461{
462 if (!elementData())
463 return nullAtom;
464 synchronizeAttribute(name);
465 if (const Attribute* attribute = getAttributeItem(name))
466 return attribute->value();
467 return nullAtom;
468}
469
Ben Murdoch591b9582013-07-10 11:41:44 +0100470void Element::scrollIntoView(bool alignToTop)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100471{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100472 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100473
474 if (!renderer())
475 return;
476
477 LayoutRect bounds = boundingBox();
478 // Align to the top / bottom and to the closest edge.
479 if (alignToTop)
480 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
481 else
482 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
483}
484
485void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
486{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100487 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100488
489 if (!renderer())
490 return;
491
492 LayoutRect bounds = boundingBox();
493 if (centerIfNeeded)
494 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
495 else
496 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
497}
498
499void Element::scrollByUnits(int units, ScrollGranularity granularity)
500{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100501 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100502
503 if (!renderer())
504 return;
505
506 if (!renderer()->hasOverflowClip())
507 return;
508
509 ScrollDirection direction = ScrollDown;
510 if (units < 0) {
511 direction = ScrollUp;
512 units = -units;
513 }
Torne (Richard Coles)a854de02013-12-18 16:25:25 +0000514 toRenderBox(renderer())->scroll(direction, granularity, units);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100515}
516
517void Element::scrollByLines(int lines)
518{
519 scrollByUnits(lines, ScrollByLine);
520}
521
522void Element::scrollByPages(int pages)
523{
524 scrollByUnits(pages, ScrollByPage);
525}
526
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000527static float localZoomForRenderer(RenderObject& renderer)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100528{
529 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
530 // other out, but the alternative is that we'd have to crawl up the whole render tree every
531 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
532 float zoomFactor = 1;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000533 if (renderer.style()->effectiveZoom() != 1) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100534 // Need to find the nearest enclosing RenderObject that set up
535 // a differing zoom, and then we divide our result by it to eliminate the zoom.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000536 RenderObject* prev = &renderer;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100537 for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) {
538 if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) {
539 zoomFactor = prev->style()->zoom();
540 break;
541 }
542 prev = curr;
543 }
544 if (prev->isRenderView())
545 zoomFactor = prev->style()->zoom();
546 }
547 return zoomFactor;
548}
549
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000550static int adjustForLocalZoom(LayoutUnit value, RenderObject& renderer)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100551{
552 float zoomFactor = localZoomForRenderer(renderer);
553 if (zoomFactor == 1)
554 return value;
555 return lroundf(value / zoomFactor);
556}
557
558int Element::offsetLeft()
559{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100560 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100561 if (RenderBoxModelObject* renderer = renderBoxModelObject())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000562 return adjustForLocalZoom(renderer->pixelSnappedOffsetLeft(), *renderer);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100563 return 0;
564}
565
566int Element::offsetTop()
567{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100568 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100569 if (RenderBoxModelObject* renderer = renderBoxModelObject())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000570 return adjustForLocalZoom(renderer->pixelSnappedOffsetTop(), *renderer);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100571 return 0;
572}
573
574int Element::offsetWidth()
575{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100576 document().updateStyleForNodeIfNeeded(this);
Ben Murdoch591b9582013-07-10 11:41:44 +0100577
578 if (RenderBox* renderer = renderBox()) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100579 if (renderer->canDetermineWidthWithoutLayout())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000580 return adjustLayoutUnitForAbsoluteZoom(renderer->fixedOffsetWidth(), *renderer).round();
Ben Murdoch591b9582013-07-10 11:41:44 +0100581 }
582
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100583 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100584 if (RenderBoxModelObject* renderer = renderBoxModelObject())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000585 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetWidth(), *renderer).round();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100586 return 0;
587}
588
589int Element::offsetHeight()
590{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100591 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100592 if (RenderBoxModelObject* renderer = renderBoxModelObject())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000593 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetHeight(), *renderer).round();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100594 return 0;
595}
596
597Element* Element::bindingsOffsetParent()
598{
599 Element* element = offsetParent();
600 if (!element || !element->isInShadowTree())
601 return element;
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100602 return element->containingShadowRoot()->shouldExposeToBindings() ? element : 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100603}
604
605Element* Element::offsetParent()
606{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100607 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100608 if (RenderObject* renderer = this->renderer())
609 return renderer->offsetParent();
610 return 0;
611}
612
613int Element::clientLeft()
614{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100615 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100616
617 if (RenderBox* renderer = renderBox())
618 return adjustForAbsoluteZoom(roundToInt(renderer->clientLeft()), renderer);
619 return 0;
620}
621
622int Element::clientTop()
623{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100624 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100625
626 if (RenderBox* renderer = renderBox())
627 return adjustForAbsoluteZoom(roundToInt(renderer->clientTop()), renderer);
628 return 0;
629}
630
631int Element::clientWidth()
632{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100633 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100634
635 // When in strict mode, clientWidth for the document element should return the width of the containing frame.
636 // 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 +0100637 bool inQuirksMode = document().inQuirksMode();
638 if ((!inQuirksMode && document().documentElement() == this)
639 || (inQuirksMode && isHTMLElement() && document().body() == this)) {
640 if (FrameView* view = document().view()) {
641 if (RenderView* renderView = document().renderView())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100642 return adjustForAbsoluteZoom(view->layoutSize().width(), renderView);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100643 }
644 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100645
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100646 if (RenderBox* renderer = renderBox())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000647 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientWidth(), *renderer).round();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100648 return 0;
649}
650
651int Element::clientHeight()
652{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100653 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100654
655 // When in strict mode, clientHeight for the document element should return the height of the containing frame.
656 // 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 +0100657 bool inQuirksMode = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100658
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100659 if ((!inQuirksMode && document().documentElement() == this)
660 || (inQuirksMode && isHTMLElement() && document().body() == this)) {
661 if (FrameView* view = document().view()) {
662 if (RenderView* renderView = document().renderView())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100663 return adjustForAbsoluteZoom(view->layoutSize().height(), renderView);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100664 }
665 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100666
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100667 if (RenderBox* renderer = renderBox())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000668 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientHeight(), *renderer).round();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100669 return 0;
670}
671
672int Element::scrollLeft()
673{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100674 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100675
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000676 if (document().documentElement() != this) {
677 if (RenderBox* rend = renderBox())
678 return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
679 return 0;
680 }
681
682 if (RuntimeEnabledFeatures::scrollTopLeftInteropEnabled()) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100683 if (document().inQuirksMode())
684 return 0;
685
686 if (FrameView* view = document().view()) {
687 if (RenderView* renderView = document().renderView())
688 return adjustForAbsoluteZoom(view->scrollX(), renderView);
689 }
690 }
691
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100692 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
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000699 if (document().documentElement() != this) {
700 if (RenderBox* rend = renderBox())
701 return adjustForAbsoluteZoom(rend->scrollTop(), rend);
702 return 0;
703 }
704
705 if (RuntimeEnabledFeatures::scrollTopLeftInteropEnabled()) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100706 if (document().inQuirksMode())
707 return 0;
708
709 if (FrameView* view = document().view()) {
710 if (RenderView* renderView = document().renderView())
711 return adjustForAbsoluteZoom(view->scrollY(), renderView);
712 }
713 }
714
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100715 return 0;
716}
717
718void Element::setScrollLeft(int newLeft)
719{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100720 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100721
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000722 if (document().documentElement() != this) {
723 if (RenderBox* rend = renderBox())
724 rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
725 return;
726 }
727
728 if (RuntimeEnabledFeatures::scrollTopLeftInteropEnabled()) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100729 if (document().inQuirksMode())
730 return;
731
732 Frame* frame = document().frame();
733 if (!frame)
734 return;
735 FrameView* view = frame->view();
736 if (!view)
737 return;
738
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100739 view->setScrollPosition(IntPoint(static_cast<int>(newLeft * frame->pageZoomFactor()), view->scrollY()));
740 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100741}
742
743void Element::setScrollTop(int newTop)
744{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100745 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100746
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000747 if (document().documentElement() != this) {
748 if (RenderBox* rend = renderBox())
749 rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
750 return;
751 }
752
753 if (RuntimeEnabledFeatures::scrollTopLeftInteropEnabled()) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100754 if (document().inQuirksMode())
755 return;
756
757 Frame* frame = document().frame();
758 if (!frame)
759 return;
760 FrameView* view = frame->view();
761 if (!view)
762 return;
763
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100764 view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(newTop * frame->pageZoomFactor())));
765 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100766}
767
768int Element::scrollWidth()
769{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100770 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100771 if (RenderBox* rend = renderBox())
772 return adjustForAbsoluteZoom(rend->scrollWidth(), rend);
773 return 0;
774}
775
776int Element::scrollHeight()
777{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100778 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100779 if (RenderBox* rend = renderBox())
780 return adjustForAbsoluteZoom(rend->scrollHeight(), rend);
781 return 0;
782}
783
784IntRect Element::boundsInRootViewSpace()
785{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100786 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100787
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100788 FrameView* view = document().view();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100789 if (!view)
790 return IntRect();
791
792 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100793 if (isSVGElement() && renderer()) {
794 // Get the bounding rectangle from the SVG model.
795 SVGElement* svgElement = toSVGElement(this);
796 FloatRect localRect;
797 if (svgElement->getBoundingBox(localRect))
798 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100799 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100800 // Get the bounding rectangle from the box model.
801 if (renderBoxModelObject())
802 renderBoxModelObject()->absoluteQuads(quads);
803 }
804
805 if (quads.isEmpty())
806 return IntRect();
807
808 IntRect result = quads[0].enclosingBoundingBox();
809 for (size_t i = 1; i < quads.size(); ++i)
810 result.unite(quads[i].enclosingBoundingBox());
811
812 result = view->contentsToRootView(result);
813 return result;
814}
815
816PassRefPtr<ClientRectList> Element::getClientRects()
817{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100818 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100819
820 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject();
821 if (!renderBoxModelObject)
822 return ClientRectList::create();
823
824 // FIXME: Handle SVG elements.
825 // FIXME: Handle table/inline-table with a caption.
826
827 Vector<FloatQuad> quads;
828 renderBoxModelObject->absoluteQuads(quads);
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000829 document().adjustFloatQuadsForScrollAndAbsoluteZoom(quads, *renderBoxModelObject);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100830 return ClientRectList::create(quads);
831}
832
833PassRefPtr<ClientRect> Element::getBoundingClientRect()
834{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100835 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100836
837 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100838 if (isSVGElement() && renderer() && !renderer()->isSVGRoot()) {
839 // Get the bounding rectangle from the SVG model.
840 SVGElement* svgElement = toSVGElement(this);
841 FloatRect localRect;
842 if (svgElement->getBoundingBox(localRect))
843 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100844 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100845 // Get the bounding rectangle from the box model.
846 if (renderBoxModelObject())
847 renderBoxModelObject()->absoluteQuads(quads);
848 }
849
850 if (quads.isEmpty())
851 return ClientRect::create();
852
853 FloatRect result = quads[0].boundingBox();
854 for (size_t i = 1; i < quads.size(); ++i)
855 result.unite(quads[i].boundingBox());
856
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000857 ASSERT(renderer());
858 document().adjustFloatRectForScrollAndAbsoluteZoom(result, *renderer());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100859 return ClientRect::create(result);
860}
Ben Murdoch591b9582013-07-10 11:41:44 +0100861
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100862IntRect Element::screenRect() const
863{
864 if (!renderer())
865 return IntRect();
866 // FIXME: this should probably respect transforms
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100867 return document().view()->contentsToScreen(renderer()->absoluteBoundingBoxRectIgnoringTransforms());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100868}
869
870const AtomicString& Element::getAttribute(const AtomicString& localName) const
871{
872 if (!elementData())
873 return nullAtom;
874 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100875 if (const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100876 return attribute->value();
877 return nullAtom;
878}
879
880const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
881{
882 return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
883}
884
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000885void Element::setAttribute(const AtomicString& localName, const AtomicString& value, ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100886{
887 if (!Document::isValidName(localName)) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000888 exceptionState.throwUninformativeAndGenericDOMException(InvalidCharacterError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100889 return;
890 }
891
892 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100893 const AtomicString& caseAdjustedLocalName = shouldIgnoreAttributeCase() ? localName.lower() : localName;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100894
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100895 size_t index = elementData() ? elementData()->getAttributeItemIndex(caseAdjustedLocalName, false) : kNotFound;
896 const QualifiedName& qName = index != kNotFound ? attributeItem(index)->name() : QualifiedName(nullAtom, caseAdjustedLocalName, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100897 setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute);
898}
899
900void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
901{
902 synchronizeAttribute(name);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100903 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : kNotFound;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100904 setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute);
905}
906
907void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value)
908{
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100909 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : kNotFound;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100910 setAttributeInternal(index, name, value, InSynchronizationOfLazyAttribute);
911}
912
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000913ALWAYS_INLINE void Element::setAttributeInternal(size_t index, const QualifiedName& name, const AtomicString& newValue, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100914{
915 if (newValue.isNull()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100916 if (index != kNotFound)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100917 removeAttributeInternal(index, inSynchronizationOfLazyAttribute);
918 return;
919 }
920
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100921 if (index == kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100922 addAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute);
923 return;
924 }
925
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000926 const Attribute* existingAttribute = attributeItem(index);
927 QualifiedName existingAttributeName = existingAttribute->name();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100928
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100929 if (!inSynchronizationOfLazyAttribute)
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000930 willModifyAttribute(existingAttributeName, existingAttribute->value(), newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100931
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000932 if (newValue != existingAttribute->value()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100933 // 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)a854de02013-12-18 16:25:25 +0000974 StyleResolver* styleResolver = document().styleResolver();
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);
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000990 shouldInvalidateStyle = testShouldInvalidateStyle && checkNeedsStyleInvalidationForIdChange(oldId, newId, styleResolver->ensureRuleFeatureSet());
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)51b29062013-11-28 11:56:03 +00001015 CustomElementRegistrationContext::setTypeExtension(this, newValue);
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{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001060 if (!oldClasses.size())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001061 return checkSelectorForClassChange(newClasses, checker);
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001062
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001063 // Class vectors tend to be very short. This is faster than using a hash table.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001064 BitVector remainingClassBits;
1065 remainingClassBits.ensureSize(oldClasses.size());
1066
1067 for (unsigned i = 0; i < newClasses.size(); ++i) {
1068 bool found = false;
1069 for (unsigned j = 0; j < oldClasses.size(); ++j) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001070 if (newClasses[i] == oldClasses[j]) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001071 // Mark each class that is still in the newClasses so we can skip doing
1072 // an n^2 search below when looking for removals. We can't break from
1073 // this loop early since a class can appear more than once.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001074 remainingClassBits.quickSet(j);
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001075 found = true;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001076 }
1077 }
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001078 // Class was added.
1079 if (!found && checker.hasSelectorForClass(newClasses[i]))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001080 return true;
1081 }
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001082
1083 for (unsigned i = 0; i < oldClasses.size(); ++i) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001084 if (remainingClassBits.quickGet(i))
1085 continue;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001086 // Class was removed.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001087 if (checker.hasSelectorForClass(oldClasses[i]))
1088 return true;
1089 }
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001090
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001091 return false;
1092}
1093
1094void Element::classAttributeChanged(const AtomicString& newClassString)
1095{
Torne (Richard Coles)a854de02013-12-18 16:25:25 +00001096 StyleResolver* styleResolver = document().styleResolver();
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001097 bool testShouldInvalidateStyle = inActiveDocument() && styleResolver && styleChangeType() < SubtreeStyleChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001098 bool shouldInvalidateStyle = false;
1099
1100 if (classStringHasClassName(newClassString)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001101 const bool shouldFoldCase = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001102 const SpaceSplitString oldClasses = elementData()->classNames();
1103 elementData()->setClass(newClassString, shouldFoldCase);
1104 const SpaceSplitString& newClasses = elementData()->classNames();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001105 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, newClasses, styleResolver->ensureRuleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001106 } else {
1107 const SpaceSplitString& oldClasses = elementData()->classNames();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001108 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, styleResolver->ensureRuleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001109 elementData()->clearClass();
1110 }
1111
1112 if (hasRareData())
1113 elementRareData()->clearClassListValueForQuirksMode();
1114
1115 if (shouldInvalidateStyle)
1116 setNeedsStyleRecalc();
1117}
1118
1119bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
1120{
1121 ASSERT(elementShadow);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001122 const SelectRuleFeatureSet& featureSet = elementShadow->ensureSelectFeatureSet();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001123
1124 if (isIdAttributeName(name)) {
1125 AtomicString oldId = elementData()->idForStyleResolution();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001126 AtomicString newId = makeIdForStyleResolution(newValue, document().inQuirksMode());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001127 if (newId != oldId) {
1128 if (!oldId.isEmpty() && featureSet.hasSelectorForId(oldId))
1129 return true;
1130 if (!newId.isEmpty() && featureSet.hasSelectorForId(newId))
1131 return true;
1132 }
1133 }
1134
1135 if (name == HTMLNames::classAttr) {
1136 const AtomicString& newClassString = newValue;
1137 if (classStringHasClassName(newClassString)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001138 const bool shouldFoldCase = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001139 const SpaceSplitString& oldClasses = elementData()->classNames();
1140 const SpaceSplitString newClasses(newClassString, shouldFoldCase);
1141 if (checkSelectorForClassChange(oldClasses, newClasses, featureSet))
1142 return true;
1143 } else {
1144 const SpaceSplitString& oldClasses = elementData()->classNames();
1145 if (checkSelectorForClassChange(oldClasses, featureSet))
1146 return true;
1147 }
1148 }
1149
1150 return featureSet.hasSelectorForAttribute(name.localName());
1151}
1152
1153// Returns true is the given attribute is an event handler.
1154// We consider an event handler any attribute that begins with "on".
1155// It is a simple solution that has the advantage of not requiring any
1156// code or configuration change if a new event handler is defined.
1157
1158static inline bool isEventHandlerAttribute(const Attribute& attribute)
1159{
1160 return attribute.name().namespaceURI().isNull() && attribute.name().localName().startsWith("on");
1161}
1162
1163bool Element::isJavaScriptURLAttribute(const Attribute& attribute) const
1164{
1165 return isURLAttribute(attribute) && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(attribute.value()));
1166}
1167
1168void Element::stripScriptingAttributes(Vector<Attribute>& attributeVector) const
1169{
1170 size_t destination = 0;
1171 for (size_t source = 0; source < attributeVector.size(); ++source) {
1172 if (isEventHandlerAttribute(attributeVector[source])
1173 || isJavaScriptURLAttribute(attributeVector[source])
1174 || isHTMLContentAttribute(attributeVector[source]))
1175 continue;
1176
1177 if (source != destination)
1178 attributeVector[destination] = attributeVector[source];
1179
1180 ++destination;
1181 }
1182 attributeVector.shrink(destination);
1183}
1184
1185void Element::parserSetAttributes(const Vector<Attribute>& attributeVector)
1186{
1187 ASSERT(!inDocument());
1188 ASSERT(!parentNode());
1189 ASSERT(!m_elementData);
1190
1191 if (attributeVector.isEmpty())
1192 return;
1193
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001194 if (document().sharedObjectPool())
1195 m_elementData = document().sharedObjectPool()->cachedShareableElementDataWithAttributes(attributeVector);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001196 else
1197 m_elementData = ShareableElementData::createWithAttributes(attributeVector);
1198
1199 // Use attributeVector instead of m_elementData because attributeChanged might modify m_elementData.
1200 for (unsigned i = 0; i < attributeVector.size(); ++i)
1201 attributeChangedFromParserOrByCloning(attributeVector[i].name(), attributeVector[i].value(), ModifiedDirectly);
1202}
1203
1204bool Element::hasAttributes() const
1205{
1206 synchronizeAllAttributes();
1207 return elementData() && elementData()->length();
1208}
1209
1210bool Element::hasEquivalentAttributes(const Element* other) const
1211{
1212 synchronizeAllAttributes();
1213 other->synchronizeAllAttributes();
1214 if (elementData() == other->elementData())
1215 return true;
1216 if (elementData())
1217 return elementData()->isEquivalent(other->elementData());
1218 if (other->elementData())
1219 return other->elementData()->isEquivalent(elementData());
1220 return true;
1221}
1222
1223String Element::nodeName() const
1224{
1225 return m_tagName.toString();
1226}
1227
1228String Element::nodeNamePreservingCase() const
1229{
1230 return m_tagName.toString();
1231}
1232
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001233void Element::setPrefix(const AtomicString& prefix, ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001234{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001235 checkSetPrefix(prefix, exceptionState);
1236 if (exceptionState.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001237 return;
1238
1239 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
1240}
1241
1242KURL Element::baseURI() const
1243{
1244 const AtomicString& baseAttribute = getAttribute(baseAttr);
1245 KURL base(KURL(), baseAttribute);
1246 if (!base.protocol().isEmpty())
1247 return base;
1248
1249 ContainerNode* parent = parentNode();
1250 if (!parent)
1251 return base;
1252
1253 const KURL& parentBase = parent->baseURI();
1254 if (parentBase.isNull())
1255 return base;
1256
1257 return KURL(parentBase, baseAttribute);
1258}
1259
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001260const AtomicString Element::imageSourceURL() const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001261{
1262 return getAttribute(srcAttr);
1263}
1264
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001265bool Element::rendererIsNeeded(const RenderStyle& style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001266{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001267 return style.display() != NONE;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001268}
1269
Ben Murdoch591b9582013-07-10 11:41:44 +01001270RenderObject* Element::createRenderer(RenderStyle* style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001271{
1272 return RenderObject::createObject(this, style);
1273}
1274
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001275Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertionPoint)
1276{
1277 // need to do superclass processing first so inDocument() is true
1278 // by the time we reach updateId
1279 ContainerNode::insertedInto(insertionPoint);
1280
1281 if (containsFullScreenElement() && parentElement() && !parentElement()->containsFullScreenElement())
1282 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
1283
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00001284 ASSERT(!hasRareData() || !elementRareData()->hasPseudoElements());
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001285
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001286 if (!insertionPoint->isInTreeScope())
1287 return InsertionDone;
1288
1289 if (hasRareData())
1290 elementRareData()->clearClassListValueForQuirksMode();
1291
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001292 if (isUpgradedCustomElement() && inDocument())
1293 CustomElement::didEnterDocument(this, document());
1294
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001295 TreeScope& scope = insertionPoint->treeScope();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001296 if (scope != treeScope())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001297 return InsertionDone;
1298
1299 const AtomicString& idValue = getIdAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001300 if (!idValue.isNull())
1301 updateId(scope, nullAtom, idValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001302
1303 const AtomicString& nameValue = getNameAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001304 if (!nameValue.isNull())
1305 updateName(nullAtom, nameValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001306
1307 if (hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001308 if (scope.shouldCacheLabelsByForAttribute())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001309 updateLabel(scope, nullAtom, fastGetAttribute(forAttr));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001310 }
1311
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001312 if (parentElement() && parentElement()->isInCanvasSubtree())
1313 setIsInCanvasSubtree(true);
1314
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001315 return InsertionDone;
1316}
1317
1318void Element::removedFrom(ContainerNode* insertionPoint)
1319{
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001320 bool wasInDocument = insertionPoint->inDocument();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001321
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00001322 ASSERT(!hasRareData() || !elementRareData()->hasPseudoElements());
Ben Murdoche69819b2013-07-17 14:56:49 +01001323
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001324 if (containsFullScreenElement())
1325 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
1326
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001327 if (document().page())
1328 document().page()->pointerLockController().elementRemoved(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001329
1330 setSavedLayerScrollOffset(IntSize());
1331
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001332 if (insertionPoint->isInTreeScope() && treeScope() == document()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001333 const AtomicString& idValue = getIdAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001334 if (!idValue.isNull())
1335 updateId(insertionPoint->treeScope(), idValue, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001336
1337 const AtomicString& nameValue = getNameAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001338 if (!nameValue.isNull())
1339 updateName(nameValue, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001340
1341 if (hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001342 TreeScope& treeScope = insertionPoint->treeScope();
1343 if (treeScope.shouldCacheLabelsByForAttribute())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001344 updateLabel(treeScope, fastGetAttribute(forAttr), nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001345 }
1346 }
1347
1348 ContainerNode::removedFrom(insertionPoint);
Ben Murdoche69819b2013-07-17 14:56:49 +01001349 if (wasInDocument) {
1350 if (hasPendingResources())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001351 document().accessSVGExtensions()->removeElementFromPendingResources(this);
Ben Murdoche69819b2013-07-17 14:56:49 +01001352
Ben Murdoch83750172013-07-24 10:36:59 +01001353 if (isUpgradedCustomElement())
Ben Murdochfff88842013-07-30 15:20:09 +01001354 CustomElement::didLeaveDocument(this, insertionPoint->document());
Ben Murdoche69819b2013-07-17 14:56:49 +01001355 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001356
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00001357 document().removeFromTopLayer(this);
1358
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001359 if (hasRareData())
1360 elementRareData()->setIsInCanvasSubtree(false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001361}
1362
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001363void Element::attach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001364{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001365 ASSERT(document().inStyleRecalc());
1366
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001367 StyleResolverParentPusher parentPusher(*this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001368
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001369 // We've already been through detach when doing an attach, but we might
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001370 // need to clear any state that's been added since then.
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001371 if (hasRareData() && styleChangeType() == NeedsReattachStyleChange) {
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001372 ElementRareData* data = elementRareData();
1373 data->clearComputedStyle();
1374 data->resetDynamicRestyleObservations();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001375 // Only clear the style state if we're not going to reuse the style from recalcStyle.
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001376 if (!context.resolvedStyle)
1377 data->resetStyleState();
1378 }
1379
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001380 NodeRenderingContext(this, context.resolvedStyle).createRendererForElementIfNeeded();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001381
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001382 addCallbackSelectors();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001383
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001384 createPseudoElementIfNeeded(BEFORE);
1385
1386 // When a shadow root exists, it does the work of attaching the children.
1387 if (ElementShadow* shadow = this->shadow()) {
1388 parentPusher.push();
Ben Murdoch591b9582013-07-10 11:41:44 +01001389 shadow->attach(context);
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001390 } else if (firstChild()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001391 parentPusher.push();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001392 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001393
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001394 ContainerNode::attach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001395
1396 createPseudoElementIfNeeded(AFTER);
Ben Murdoche69819b2013-07-17 14:56:49 +01001397 createPseudoElementIfNeeded(BACKDROP);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001398
Ben Murdoch591b9582013-07-10 11:41:44 +01001399 if (hasRareData()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001400 ElementRareData* data = elementRareData();
1401 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001402 if (isFocusable() && document().focusedElement() == this)
1403 document().updateFocusAppearanceSoon(false /* don't restore selection */);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001404 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1405 }
1406 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001407
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001408 InspectorInstrumentation::didRecalculateStyleForElement(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001409}
1410
1411void Element::unregisterNamedFlowContentNode()
1412{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001413 if (RuntimeEnabledFeatures::cssRegionsEnabled() && inNamedFlow() && document().renderView())
1414 document().renderView()->flowThreadController()->unregisterNamedFlowContentNode(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001415}
1416
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001417void Element::detach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001418{
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001419 RenderWidget::UpdateSuspendScope suspendWidgetHierarchyUpdates;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001420 unregisterNamedFlowContentNode();
1421 cancelFocusAppearanceUpdate();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001422 removeCallbackSelectors();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001423 if (hasRareData()) {
1424 ElementRareData* data = elementRareData();
1425 data->setPseudoElement(BEFORE, 0);
1426 data->setPseudoElement(AFTER, 0);
Ben Murdoche69819b2013-07-17 14:56:49 +01001427 data->setPseudoElement(BACKDROP, 0);
Ben Murdoch591b9582013-07-10 11:41:44 +01001428 data->setIsInsideRegion(false);
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001429
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001430 // attach() will perform the below steps for us when inside recalcStyle.
1431 if (!document().inStyleRecalc()) {
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001432 data->resetStyleState();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001433 data->clearComputedStyle();
1434 data->resetDynamicRestyleObservations();
1435 }
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001436
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001437 if (RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
1438 if (ActiveAnimations* activeAnimations = data->activeAnimations()) {
1439 if (context.performingReattach) {
1440 // FIXME: restart compositor animations rather than pull back to the main thread
1441 activeAnimations->cancelAnimationOnCompositor();
1442 } else {
1443 activeAnimations->cssAnimations().cancel();
1444 }
1445 }
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001446 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001447 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001448 if (ElementShadow* shadow = this->shadow())
1449 shadow->detach(context);
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001450 ContainerNode::detach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001451}
1452
1453bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle)
1454{
1455 ASSERT(currentStyle == renderStyle());
1456 ASSERT(renderer());
1457
1458 if (!currentStyle)
1459 return false;
1460
1461 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles();
1462 if (!pseudoStyleCache)
1463 return false;
1464
1465 size_t cacheSize = pseudoStyleCache->size();
1466 for (size_t i = 0; i < cacheSize; ++i) {
1467 RefPtr<RenderStyle> newPseudoStyle;
1468 PseudoId pseudoId = pseudoStyleCache->at(i)->styleType();
1469 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
1470 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle);
1471 else
1472 newPseudoStyle = renderer()->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
1473 if (!newPseudoStyle)
1474 return true;
1475 if (*newPseudoStyle != *pseudoStyleCache->at(i)) {
1476 if (pseudoId < FIRST_INTERNAL_PSEUDOID)
1477 newStyle->setHasPseudoStyle(pseudoId);
1478 newStyle->addCachedPseudoStyle(newPseudoStyle);
1479 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
1480 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001481 // is needed, but for now just assume a layout will be required. The diff code
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001482 // in RenderObject::setStyle would need to be factored out so that it could be reused.
1483 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
1484 }
1485 return true;
1486 }
1487 }
1488 return false;
1489}
1490
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001491PassRefPtr<RenderStyle> Element::styleForRenderer()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001492{
Torne (Richard Coles)a854de02013-12-18 16:25:25 +00001493 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001494
Torne (Richard Coles)a854de02013-12-18 16:25:25 +00001495 RefPtr<RenderStyle> style;
1496
1497 // FIXME: Instead of clearing updates that may have been added from calls to styleForElement
1498 // outside recalcStyle, we should just never set them if we're not inside recalcStyle.
1499 if (ActiveAnimations* activeAnimations = this->activeAnimations())
1500 activeAnimations->cssAnimations().setPendingUpdate(nullptr);
1501
1502 if (hasCustomStyleCallbacks())
1503 style = customStyleForRenderer();
1504 if (!style)
1505 style = originalStyleForRenderer();
1506
1507 // styleForElement() might add active animations so we need to get it again.
1508 if (ActiveAnimations* activeAnimations = this->activeAnimations())
1509 activeAnimations->cssAnimations().maybeApplyPendingUpdate(this);
1510
1511 ASSERT(style);
1512 return style.release();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001513}
1514
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001515PassRefPtr<RenderStyle> Element::originalStyleForRenderer()
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001516{
Torne (Richard Coles)a854de02013-12-18 16:25:25 +00001517 ASSERT(document().inStyleRecalc());
1518 return document().ensureStyleResolver().styleForElement(this);
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001519}
1520
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001521void Element::recalcStyle(StyleRecalcChange change, Text* nextTextSibling)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001522{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001523 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001524 ASSERT(!parentOrShadowHostNode()->needsStyleRecalc());
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001525
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001526 if (hasCustomStyleCallbacks())
1527 willRecalcStyle(change);
1528
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001529 if (change >= Inherit || needsStyleRecalc()) {
1530 if (hasRareData()) {
1531 ElementRareData* data = elementRareData();
1532 data->resetStyleState();
1533 data->clearComputedStyle();
Torne (Richard Coles)a854de02013-12-18 16:25:25 +00001534
1535 if (change >= Inherit) {
1536 if (ActiveAnimations* activeAnimations = data->activeAnimations())
1537 activeAnimations->setAnimationStyleChange(false);
1538 }
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001539 }
1540 if (parentRenderStyle())
1541 change = recalcOwnStyle(change);
1542 clearNeedsStyleRecalc();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001543 }
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001544
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001545 // If we reattached we don't need to recalc the style of our descendants anymore.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001546 if ((change >= Inherit && change < Reattach) || childNeedsStyleRecalc())
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001547 recalcChildStyle(change);
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001548 clearChildNeedsStyleRecalc();
Ben Murdoch591b9582013-07-10 11:41:44 +01001549
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001550 if (hasCustomStyleCallbacks())
1551 didRecalcStyle(change);
1552
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001553 if (change == Reattach)
1554 reattachWhitespaceSiblings(nextTextSibling);
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001555}
1556
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001557StyleRecalcChange Element::recalcOwnStyle(StyleRecalcChange change)
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001558{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001559 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001560 ASSERT(!parentOrShadowHostNode()->needsStyleRecalc());
1561 ASSERT(change >= Inherit || needsStyleRecalc());
1562 ASSERT(parentRenderStyle());
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001563
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001564 RefPtr<RenderStyle> oldStyle = renderStyle();
Torne (Richard Coles)a854de02013-12-18 16:25:25 +00001565 RefPtr<RenderStyle> newStyle = styleForRenderer();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001566 StyleRecalcChange localChange = RenderStyle::compare(oldStyle.get(), newStyle.get());
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001567
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001568 ASSERT(newStyle);
1569
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001570 if (localChange == Reattach) {
1571 AttachContext reattachContext;
1572 reattachContext.resolvedStyle = newStyle.get();
1573 reattach(reattachContext);
1574 return Reattach;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001575 }
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001576
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001577 ASSERT(oldStyle);
1578
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001579 InspectorInstrumentation::didRecalculateStyleForElement(this);
1580
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001581 if (localChange != NoChange)
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001582 updateCallbackSelectors(oldStyle.get(), newStyle.get());
1583
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001584 if (RenderObject* renderer = this->renderer()) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001585 if (localChange != NoChange || pseudoStyleCacheIsInvalid(oldStyle.get(), newStyle.get()) || shouldNotifyRendererWithIdenticalStyles()) {
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001586 renderer->setAnimatableStyle(newStyle.get());
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001587 } else {
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001588 // Although no change occurred, we use the new style so that the cousin style sharing code won't get
1589 // fooled into believing this style is the same.
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001590 // FIXME: We may be able to remove this hack, see discussion in
1591 // https://codereview.chromium.org/30453002/
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001592 renderer->setStyleInternal(newStyle.get());
1593 }
1594 }
1595
1596 // 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
1597 // 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)51b29062013-11-28 11:56:03 +00001598 if (document().styleEngine()->usesRemUnits() && document().documentElement() == this && oldStyle->fontSize() != newStyle->fontSize()) {
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001599 // Cached RenderStyles may depend on the re units.
Torne (Richard Coles)a854de02013-12-18 16:25:25 +00001600 document().ensureStyleResolver().invalidateMatchedPropertiesCache();
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001601 return Force;
1602 }
1603
1604 if (styleChangeType() >= SubtreeStyleChange)
1605 return Force;
1606
1607 return max(localChange, change);
1608}
1609
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001610void Element::recalcChildStyle(StyleRecalcChange change)
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001611{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001612 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001613 ASSERT(change >= Inherit || childNeedsStyleRecalc());
1614 ASSERT(!needsStyleRecalc());
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001615
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001616 StyleResolverParentPusher parentPusher(*this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001617
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001618 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
1619 if (shouldRecalcStyle(change, root)) {
1620 parentPusher.push();
1621 root->recalcStyle(change);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001622 }
1623 }
1624
1625 if (shouldRecalcStyle(change, this))
1626 updatePseudoElement(BEFORE, change);
1627
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001628 if (change < Force && hasRareData() && childNeedsStyleRecalc())
1629 checkForChildrenAdjacentRuleChanges();
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001630
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001631 // This loop is deliberately backwards because we use insertBefore in the rendering tree, and want to avoid
1632 // a potentially n^2 loop to find the insertion point while resolving style. Having us start from the last
1633 // child and work our way back means in the common case, we'll find the insertion point in O(1) time.
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001634 // See crbug.com/288225
Torne (Richard Coles)a854de02013-12-18 16:25:25 +00001635 StyleResolver& styleResolver = document().ensureStyleResolver();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001636 Text* lastTextNode = 0;
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001637 for (Node* child = lastChild(); child; child = child->previousSibling()) {
1638 if (child->isTextNode()) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001639 toText(child)->recalcTextStyle(change, lastTextNode);
1640 lastTextNode = toText(child);
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001641 } else if (child->isElementNode()) {
1642 Element* element = toElement(child);
Ben Murdoche69819b2013-07-17 14:56:49 +01001643 if (shouldRecalcStyle(change, element)) {
1644 parentPusher.push();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001645 element->recalcStyle(change, lastTextNode);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001646 } else if (element->supportsStyleSharing()) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001647 styleResolver.addToStyleSharingList(*element);
Ben Murdoche69819b2013-07-17 14:56:49 +01001648 }
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001649 if (element->renderer())
1650 lastTextNode = 0;
Ben Murdoch591b9582013-07-10 11:41:44 +01001651 }
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001652 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001653
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001654 if (shouldRecalcStyle(change, this)) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001655 updatePseudoElement(AFTER, change);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001656 updatePseudoElement(BACKDROP, change);
1657 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001658}
1659
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001660void Element::checkForChildrenAdjacentRuleChanges()
1661{
1662 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
1663 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
1664
1665 if (!hasDirectAdjacentRules && !hasIndirectAdjacentRules)
1666 return;
1667
1668 unsigned forceCheckOfNextElementCount = 0;
1669 bool forceCheckOfAnyElementSibling = false;
1670
1671 for (Node* child = firstChild(); child; child = child->nextSibling()) {
1672 if (!child->isElementNode())
1673 continue;
1674 Element* element = toElement(child);
1675 bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() >= SubtreeStyleChange;
1676
1677 if (forceCheckOfNextElementCount || forceCheckOfAnyElementSibling)
1678 element->setNeedsStyleRecalc();
1679
1680 if (forceCheckOfNextElementCount)
1681 forceCheckOfNextElementCount--;
1682
1683 if (childRulesChanged && hasDirectAdjacentRules)
1684 forceCheckOfNextElementCount = document().styleEngine()->maxDirectAdjacentSelectors();
1685
1686 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
1687 }
1688}
1689
1690void Element::updateCallbackSelectors(RenderStyle* oldStyle, RenderStyle* newStyle)
1691{
1692 Vector<String> emptyVector;
1693 const Vector<String>& oldCallbackSelectors = oldStyle ? oldStyle->callbackSelectors() : emptyVector;
1694 const Vector<String>& newCallbackSelectors = newStyle ? newStyle->callbackSelectors() : emptyVector;
1695 if (oldCallbackSelectors.isEmpty() && newCallbackSelectors.isEmpty())
1696 return;
1697 if (oldCallbackSelectors != newCallbackSelectors)
1698 CSSSelectorWatch::from(document()).updateSelectorMatches(oldCallbackSelectors, newCallbackSelectors);
1699}
1700
1701void Element::addCallbackSelectors()
1702{
1703 updateCallbackSelectors(0, renderStyle());
1704}
1705
1706void Element::removeCallbackSelectors()
1707{
1708 updateCallbackSelectors(renderStyle(), 0);
1709}
1710
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001711ElementShadow* Element::shadow() const
1712{
1713 return hasRareData() ? elementRareData()->shadow() : 0;
1714}
1715
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001716ElementShadow& Element::ensureShadow()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001717{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001718 return ensureElementRareData().ensureShadow();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001719}
1720
1721void Element::didAffectSelector(AffectedSelectorMask mask)
1722{
1723 setNeedsStyleRecalc();
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00001724 if (ElementShadow* elementShadow = shadowWhereNodeCanBeDistributed(*this))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001725 elementShadow->didAffectSelector(mask);
1726}
1727
Torne (Richard Coles)a854de02013-12-18 16:25:25 +00001728void Element::setAnimationStyleChange(bool animationStyleChange)
1729{
1730 if (ActiveAnimations* activeAnimations = elementRareData()->activeAnimations())
1731 activeAnimations->setAnimationStyleChange(animationStyleChange);
1732}
1733
1734void Element::setNeedsAnimationStyleRecalc()
1735{
1736 if (styleChangeType() != NoStyleChange)
1737 return;
1738
1739 setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer);
1740 setAnimationStyleChange(true);
1741}
1742
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001743PassRefPtr<ShadowRoot> Element::createShadowRoot(ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001744{
1745 if (alwaysCreateUserAgentShadowRoot())
1746 ensureUserAgentShadowRoot();
1747
1748 if (RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001749 return PassRefPtr<ShadowRoot>(ensureShadow().addShadowRoot(*this, ShadowRoot::AuthorShadowRoot));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001750
1751 // Since some elements recreates shadow root dynamically, multiple shadow
1752 // subtrees won't work well in that element. Until they are fixed, we disable
1753 // adding author shadow root for them.
1754 if (!areAuthorShadowsAllowed()) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001755 exceptionState.throwUninformativeAndGenericDOMException(HierarchyRequestError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001756 return 0;
1757 }
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001758 return PassRefPtr<ShadowRoot>(ensureShadow().addShadowRoot(*this, ShadowRoot::AuthorShadowRoot));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001759}
1760
1761ShadowRoot* Element::shadowRoot() const
1762{
1763 ElementShadow* elementShadow = shadow();
1764 if (!elementShadow)
1765 return 0;
1766 ShadowRoot* shadowRoot = elementShadow->youngestShadowRoot();
1767 if (shadowRoot->type() == ShadowRoot::AuthorShadowRoot)
1768 return shadowRoot;
1769 return 0;
1770}
1771
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001772void Element::didAddShadowRoot(ShadowRoot&)
1773{
1774}
1775
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001776ShadowRoot* Element::userAgentShadowRoot() const
1777{
1778 if (ElementShadow* elementShadow = shadow()) {
1779 if (ShadowRoot* shadowRoot = elementShadow->oldestShadowRoot()) {
1780 ASSERT(shadowRoot->type() == ShadowRoot::UserAgentShadowRoot);
1781 return shadowRoot;
1782 }
1783 }
1784
1785 return 0;
1786}
1787
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001788ShadowRoot& Element::ensureUserAgentShadowRoot()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001789{
1790 if (ShadowRoot* shadowRoot = userAgentShadowRoot())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001791 return *shadowRoot;
1792 ShadowRoot& shadowRoot = ensureShadow().addShadowRoot(*this, ShadowRoot::UserAgentShadowRoot);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001793 didAddUserAgentShadowRoot(shadowRoot);
1794 return shadowRoot;
1795}
1796
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001797bool Element::childTypeAllowed(NodeType type) const
1798{
1799 switch (type) {
1800 case ELEMENT_NODE:
1801 case TEXT_NODE:
1802 case COMMENT_NODE:
1803 case PROCESSING_INSTRUCTION_NODE:
1804 case CDATA_SECTION_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001805 return true;
1806 default:
1807 break;
1808 }
1809 return false;
1810}
1811
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001812void Element::checkForEmptyStyleChange(RenderStyle* style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001813{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001814 if (!style && !styleAffectedByEmpty())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001815 return;
1816
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001817 if (!style || (styleAffectedByEmpty() && (!style->emptyState() || hasChildNodes())))
1818 setNeedsStyleRecalc();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001819}
1820
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001821void Element::checkForSiblingStyleChanges(bool finishedParsingCallback, Node* beforeChange, Node* afterChange, int childCountDelta)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001822{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001823 if (!inActiveDocument() || document().hasPendingForcedStyleRecalc() || styleChangeType() >= SubtreeStyleChange)
Ben Murdoch83750172013-07-24 10:36:59 +01001824 return;
1825
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001826 RenderStyle* style = renderStyle();
Ben Murdoch591b9582013-07-10 11:41:44 +01001827
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001828 // :empty selector.
1829 checkForEmptyStyleChange(style);
1830
1831 if (!style || (needsStyleRecalc() && childrenAffectedByPositionalRules()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001832 return;
1833
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001834 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
1835 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1836 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
1837 // backward case.
1838 // |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.
1839 // 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 +01001840 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001841 if ((childrenAffectedByForwardPositionalRules() && afterChange) || (childrenAffectedByBackwardPositionalRules() && beforeChange)) {
1842 setNeedsStyleRecalc();
Ben Murdoch83750172013-07-24 10:36:59 +01001843 return;
1844 }
1845
1846 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1847 // In the DOM case, we only need to do something if |afterChange| is not 0.
1848 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001849 if (childrenAffectedByFirstChildRules() && afterChange) {
Ben Murdoch83750172013-07-24 10:36:59 +01001850 // Find our new first child.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001851 Node* newFirstChild = firstElementChild();
Ben Murdoch83750172013-07-24 10:36:59 +01001852 RenderStyle* newFirstChildStyle = newFirstChild ? newFirstChild->renderStyle() : 0;
1853
1854 // Find the first element node following |afterChange|
1855 Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling();
1856 RenderStyle* firstElementAfterInsertionStyle = firstElementAfterInsertion ? firstElementAfterInsertion->renderStyle() : 0;
1857
1858 // This is the insert/append case.
1859 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertionStyle && firstElementAfterInsertionStyle->firstChildState())
1860 firstElementAfterInsertion->setNeedsStyleRecalc();
1861
1862 // We also have to handle node removal.
1863 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChildStyle || !newFirstChildStyle->firstChildState()))
1864 newFirstChild->setNeedsStyleRecalc();
1865 }
1866
1867 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1868 // In the DOM case, we only need to do something if |afterChange| is not 0.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001869 if (childrenAffectedByLastChildRules() && beforeChange) {
Ben Murdoch83750172013-07-24 10:36:59 +01001870 // Find our new last child.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001871 Node* newLastChild = lastElementChild();
Ben Murdoch83750172013-07-24 10:36:59 +01001872 RenderStyle* newLastChildStyle = newLastChild ? newLastChild->renderStyle() : 0;
1873
1874 // Find the last element node going backwards from |beforeChange|
1875 Node* lastElementBeforeInsertion = beforeChange->isElementNode() ? beforeChange : beforeChange->previousElementSibling();
1876 RenderStyle* lastElementBeforeInsertionStyle = lastElementBeforeInsertion ? lastElementBeforeInsertion->renderStyle() : 0;
1877
1878 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertionStyle && lastElementBeforeInsertionStyle->lastChildState())
1879 lastElementBeforeInsertion->setNeedsStyleRecalc();
1880
1881 // 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
1882 // to match now.
1883 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChildStyle || !newLastChildStyle->lastChildState()))
1884 newLastChild->setNeedsStyleRecalc();
1885 }
1886
1887 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
1888 // that could be affected by this DOM change.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001889 if (childrenAffectedByDirectAdjacentRules() && afterChange) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001890 if (Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling())
Ben Murdoch83750172013-07-24 10:36:59 +01001891 firstElementAfterInsertion->setNeedsStyleRecalc();
1892 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001893}
1894
1895void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
1896{
1897 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
1898 if (changedByParser)
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001899 checkForEmptyStyleChange(renderStyle());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001900 else
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001901 checkForSiblingStyleChanges(false, beforeChange, afterChange, childCountDelta);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001902
Ben Murdoch83750172013-07-24 10:36:59 +01001903 if (ElementShadow* shadow = this->shadow())
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001904 shadow->setNeedsDistributionRecalc();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001905}
1906
1907void Element::removeAllEventListeners()
1908{
1909 ContainerNode::removeAllEventListeners();
1910 if (ElementShadow* shadow = this->shadow())
1911 shadow->removeAllEventListeners();
1912}
1913
1914void Element::beginParsingChildren()
1915{
1916 clearIsParsingChildrenFinished();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001917}
1918
1919void Element::finishParsingChildren()
1920{
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001921 setIsParsingChildrenFinished();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001922 checkForSiblingStyleChanges(this, lastChild(), 0, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001923}
1924
1925#ifndef NDEBUG
1926void Element::formatForDebugger(char* buffer, unsigned length) const
1927{
1928 StringBuilder result;
1929 String s;
1930
1931 result.append(nodeName());
1932
1933 s = getIdAttribute();
1934 if (s.length() > 0) {
1935 if (result.length() > 0)
1936 result.appendLiteral("; ");
1937 result.appendLiteral("id=");
1938 result.append(s);
1939 }
1940
1941 s = getAttribute(classAttr);
1942 if (s.length() > 0) {
1943 if (result.length() > 0)
1944 result.appendLiteral("; ");
1945 result.appendLiteral("class=");
1946 result.append(s);
1947 }
1948
1949 strncpy(buffer, result.toString().utf8().data(), length - 1);
1950}
1951#endif
1952
1953const Vector<RefPtr<Attr> >& Element::attrNodeList()
1954{
1955 ASSERT(hasSyntheticAttrChildNodes());
1956 return *attrNodeListForElement(this);
1957}
1958
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001959PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001960{
1961 if (!attrNode) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001962 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001963 return 0;
1964 }
1965
1966 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName());
1967 if (oldAttrNode.get() == attrNode)
1968 return attrNode; // This Attr is already attached to the element.
1969
Ben Murdoche69819b2013-07-17 14:56:49 +01001970 // 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 +01001971 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
1972 if (attrNode->ownerElement()) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001973 exceptionState.throwUninformativeAndGenericDOMException(InUseAttributeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001974 return 0;
1975 }
1976
1977 synchronizeAllAttributes();
1978 UniqueElementData* elementData = ensureUniqueElementData();
1979
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001980 size_t index = elementData->getAttributeItemIndex(attrNode->qualifiedName(), shouldIgnoreAttributeCase());
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001981 if (index != kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001982 if (oldAttrNode)
1983 detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData->attributeItem(index)->value());
1984 else
1985 oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), elementData->attributeItem(index)->value());
1986 }
1987
1988 setAttributeInternal(index, attrNode->qualifiedName(), attrNode->value(), NotInSynchronizationOfLazyAttribute);
1989
1990 attrNode->attachToElement(this);
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001991 treeScope().adoptIfNeeded(*attrNode);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001992 ensureAttrNodeListForElement(this).append(attrNode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001993
1994 return oldAttrNode.release();
1995}
1996
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001997PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001998{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001999 return setAttributeNode(attr, exceptionState);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002000}
2001
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002002PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002003{
2004 if (!attr) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002005 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002006 return 0;
2007 }
2008 if (attr->ownerElement() != this) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002009 exceptionState.throwUninformativeAndGenericDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002010 return 0;
2011 }
2012
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002013 ASSERT(document() == attr->document());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002014
2015 synchronizeAttribute(attr->qualifiedName());
2016
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01002017 size_t index = elementData()->getAttrIndex(attr);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01002018 if (index == kNotFound) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002019 exceptionState.throwUninformativeAndGenericDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002020 return 0;
2021 }
2022
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01002023 RefPtr<Attr> guard(attr);
2024 detachAttrNodeAtIndex(attr, index);
2025 return guard.release();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002026}
2027
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002028bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002029{
Torne (Richard Coles)a854de02013-12-18 16:25:25 +00002030 AtomicString prefix, localName;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002031 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, exceptionState))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002032 return false;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002033 ASSERT(!exceptionState.hadException());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002034
2035 QualifiedName qName(prefix, localName, namespaceURI);
2036
2037 if (!Document::hasValidNamespaceForAttributes(qName)) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002038 exceptionState.throwUninformativeAndGenericDOMException(NamespaceError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002039 return false;
2040 }
2041
2042 out = qName;
2043 return true;
2044}
2045
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002046void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002047{
2048 QualifiedName parsedName = anyName;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002049 if (!parseAttributeName(parsedName, namespaceURI, qualifiedName, exceptionState))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002050 return;
2051 setAttribute(parsedName, value);
2052}
2053
2054void Element::removeAttributeInternal(size_t index, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
2055{
2056 ASSERT_WITH_SECURITY_IMPLICATION(index < attributeCount());
2057
2058 UniqueElementData* elementData = ensureUniqueElementData();
2059
2060 QualifiedName name = elementData->attributeItem(index)->name();
2061 AtomicString valueBeingRemoved = elementData->attributeItem(index)->value();
2062
2063 if (!inSynchronizationOfLazyAttribute) {
2064 if (!valueBeingRemoved.isNull())
2065 willModifyAttribute(name, valueBeingRemoved, nullAtom);
2066 }
2067
2068 if (RefPtr<Attr> attrNode = attrIfExists(name))
2069 detachAttrNodeFromElementWithValue(attrNode.get(), elementData->attributeItem(index)->value());
2070
2071 elementData->removeAttribute(index);
2072
2073 if (!inSynchronizationOfLazyAttribute)
2074 didRemoveAttribute(name);
2075}
2076
2077void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
2078{
2079 if (!inSynchronizationOfLazyAttribute)
2080 willModifyAttribute(name, nullAtom, value);
2081 ensureUniqueElementData()->addAttribute(name, value);
2082 if (!inSynchronizationOfLazyAttribute)
2083 didAddAttribute(name, value);
2084}
2085
2086void Element::removeAttribute(const AtomicString& name)
2087{
2088 if (!elementData())
2089 return;
2090
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002091 AtomicString localName = shouldIgnoreAttributeCase() ? name.lower() : name;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002092 size_t index = elementData()->getAttributeItemIndex(localName, false);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01002093 if (index == kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002094 if (UNLIKELY(localName == styleAttr) && elementData()->m_styleAttributeIsDirty && isStyledElement())
Ben Murdoch591b9582013-07-10 11:41:44 +01002095 removeAllInlineStyleProperties();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002096 return;
2097 }
2098
2099 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
2100}
2101
2102void Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName)
2103{
2104 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI));
2105}
2106
2107PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& localName)
2108{
2109 if (!elementData())
2110 return 0;
2111 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002112 const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002113 if (!attribute)
2114 return 0;
2115 return ensureAttr(attribute->name());
2116}
2117
2118PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
2119{
2120 if (!elementData())
2121 return 0;
2122 QualifiedName qName(nullAtom, localName, namespaceURI);
2123 synchronizeAttribute(qName);
2124 const Attribute* attribute = elementData()->getAttributeItem(qName);
2125 if (!attribute)
2126 return 0;
2127 return ensureAttr(attribute->name());
2128}
2129
2130bool Element::hasAttribute(const AtomicString& localName) const
2131{
2132 if (!elementData())
2133 return false;
2134 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002135 return elementData()->getAttributeItem(shouldIgnoreAttributeCase() ? localName.lower() : localName, false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002136}
2137
2138bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
2139{
2140 if (!elementData())
2141 return false;
2142 QualifiedName qName(nullAtom, localName, namespaceURI);
2143 synchronizeAttribute(qName);
2144 return elementData()->getAttributeItem(qName);
2145}
2146
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002147void Element::focus(bool restorePreviousSelection, FocusDirection direction)
2148{
2149 if (!inDocument())
2150 return;
2151
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002152 Document& doc = document();
2153 if (doc.focusedElement() == this)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002154 return;
2155
2156 // If the stylesheets have already been loaded we can reliably check isFocusable.
2157 // If not, we continue and set the focused node on the focus controller below so
Ben Murdoch591b9582013-07-10 11:41:44 +01002158 // that it can be updated soon after attach.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002159 if (doc.haveStylesheetsLoaded()) {
2160 doc.updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002161 if (!isFocusable())
2162 return;
2163 }
2164
2165 if (!supportsFocus())
2166 return;
2167
2168 RefPtr<Node> protect;
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002169 if (Page* page = doc.page()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002170 // Focus and change event handlers can cause us to lose our last ref.
2171 // If a focus event handler changes the focus to a different node it
2172 // does not make sense to continue and update appearence.
2173 protect = this;
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002174 if (!page->focusController().setFocusedElement(this, doc.frame(), direction))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002175 return;
2176 }
2177
2178 // Setting the focused node above might have invalidated the layout due to scripts.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002179 doc.updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002180
2181 if (!isFocusable()) {
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002182 ensureElementRareData().setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002183 return;
2184 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002185
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002186 cancelFocusAppearanceUpdate();
2187 updateFocusAppearance(restorePreviousSelection);
2188}
2189
2190void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
2191{
2192 if (isRootEditableElement()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002193 Frame* frame = document().frame();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002194 if (!frame)
2195 return;
Ben Murdoch591b9582013-07-10 11:41:44 +01002196
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002197 // 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 +01002198 if (this == frame->selection().rootEditableElement())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002199 return;
2200
2201 // FIXME: We should restore the previous selection if there is one.
2202 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002203 frame->selection().setSelection(newSelection);
2204 frame->selection().revealSelection();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002205 } else if (renderer() && !renderer()->isWidget())
2206 renderer()->scrollRectToVisible(boundingBox());
2207}
2208
2209void Element::blur()
2210{
2211 cancelFocusAppearanceUpdate();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002212 if (treeScope().adjustedFocusedElement() == this) {
2213 Document& doc = document();
2214 if (doc.page())
2215 doc.page()->focusController().setFocusedElement(0, doc.frame());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002216 else
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002217 doc.setFocusedElement(0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002218 }
2219}
2220
Ben Murdochdf957042013-08-06 11:01:27 +01002221bool Element::isFocusable() const
2222{
2223 return inDocument() && supportsFocus() && !isInert() && rendererIsFocusable();
2224}
2225
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002226bool Element::isKeyboardFocusable() const
2227{
2228 return isFocusable() && tabIndex() >= 0;
2229}
2230
2231bool Element::isMouseFocusable() const
2232{
2233 return isFocusable();
2234}
2235
Ben Murdoch02772c62013-07-26 10:21:05 +01002236void Element::dispatchFocusEvent(Element* oldFocusedElement, FocusDirection)
2237{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002238 RefPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::focus, false, false, document().domWindow(), 0, oldFocusedElement);
Ben Murdoch02772c62013-07-26 10:21:05 +01002239 EventDispatcher::dispatchEvent(this, FocusEventDispatchMediator::create(event.release()));
2240}
2241
2242void Element::dispatchBlurEvent(Element* newFocusedElement)
2243{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002244 RefPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::blur, false, false, document().domWindow(), 0, newFocusedElement);
Ben Murdoch02772c62013-07-26 10:21:05 +01002245 EventDispatcher::dispatchEvent(this, BlurEventDispatchMediator::create(event.release()));
2246}
2247
2248void Element::dispatchFocusInEvent(const AtomicString& eventType, Element* oldFocusedElement)
2249{
2250 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002251 ASSERT(eventType == EventTypeNames::focusin || eventType == EventTypeNames::DOMFocusIn);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002252 dispatchScopedEventDispatchMediator(FocusInEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document().domWindow(), 0, oldFocusedElement)));
Ben Murdoch02772c62013-07-26 10:21:05 +01002253}
2254
2255void Element::dispatchFocusOutEvent(const AtomicString& eventType, Element* newFocusedElement)
2256{
2257 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002258 ASSERT(eventType == EventTypeNames::focusout || eventType == EventTypeNames::DOMFocusOut);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002259 dispatchScopedEventDispatchMediator(FocusOutEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document().domWindow(), 0, newFocusedElement)));
Ben Murdoch02772c62013-07-26 10:21:05 +01002260}
2261
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002262String Element::innerHTML() const
2263{
2264 return createMarkup(this, ChildrenOnly);
2265}
2266
2267String Element::outerHTML() const
2268{
2269 return createMarkup(this);
2270}
2271
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002272void Element::setInnerHTML(const String& html, ExceptionState& exceptionState)
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002273{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002274 if (RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(html, this, AllowScriptingContent, "innerHTML", exceptionState)) {
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002275 ContainerNode* container = this;
2276 if (hasTagName(templateTag))
2277 container = toHTMLTemplateElement(this)->content();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002278 replaceChildrenWithFragment(container, fragment.release(), exceptionState);
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002279 }
2280}
2281
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002282void Element::setOuterHTML(const String& html, ExceptionState& exceptionState)
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002283{
2284 Node* p = parentNode();
2285 if (!p || !p->isElementNode()) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002286 exceptionState.throwUninformativeAndGenericDOMException(NoModificationAllowedError);
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002287 return;
2288 }
2289 RefPtr<Element> parent = toElement(p);
2290 RefPtr<Node> prev = previousSibling();
2291 RefPtr<Node> next = nextSibling();
2292
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002293 RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(html, parent.get(), AllowScriptingContent, "outerHTML", exceptionState);
2294 if (exceptionState.hadException())
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002295 return;
2296
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002297 parent->replaceChild(fragment.release(), this, exceptionState);
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002298 RefPtr<Node> node = next ? next->previousSibling() : 0;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002299 if (!exceptionState.hadException() && node && node->isTextNode())
2300 mergeWithNextTextNode(node.release(), exceptionState);
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002301
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002302 if (!exceptionState.hadException() && prev && prev->isTextNode())
2303 mergeWithNextTextNode(prev.release(), exceptionState);
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002304}
2305
Torne (Richard Coles)a854de02013-12-18 16:25:25 +00002306Node* Element::insertAdjacent(const String& where, Node* newChild, ExceptionState& exceptionState)
2307{
2308 if (equalIgnoringCase(where, "beforeBegin")) {
2309 if (ContainerNode* parent = this->parentNode()) {
2310 parent->insertBefore(newChild, this, exceptionState);
2311 if (!exceptionState.hadException())
2312 return newChild;
2313 }
2314 return 0;
2315 }
2316
2317 if (equalIgnoringCase(where, "afterBegin")) {
2318 insertBefore(newChild, firstChild(), exceptionState);
2319 return exceptionState.hadException() ? 0 : newChild;
2320 }
2321
2322 if (equalIgnoringCase(where, "beforeEnd")) {
2323 appendChild(newChild, exceptionState);
2324 return exceptionState.hadException() ? 0 : newChild;
2325 }
2326
2327 if (equalIgnoringCase(where, "afterEnd")) {
2328 if (ContainerNode* parent = this->parentNode()) {
2329 parent->insertBefore(newChild, nextSibling(), exceptionState);
2330 if (!exceptionState.hadException())
2331 return newChild;
2332 }
2333 return 0;
2334 }
2335
2336 exceptionState.throwDOMException(SyntaxError, "The value provided ('" + where + "') is not one of 'beforeBegin', 'afterBegin', 'beforeEnd', or 'afterEnd'.");
2337 return 0;
2338}
2339
2340// Step 1 of http://domparsing.spec.whatwg.org/#insertadjacenthtml()
2341static Element* contextElementForInsertion(const String& where, Element* element, ExceptionState& exceptionState)
2342{
2343 if (equalIgnoringCase(where, "beforeBegin") || equalIgnoringCase(where, "afterEnd")) {
2344 ContainerNode* parent = element->parentNode();
2345 if (!parent || !parent->isElementNode()) {
2346 exceptionState.throwDOMException(NoModificationAllowedError, "The element has no parent.");
2347 return 0;
2348 }
2349 return toElement(parent);
2350 }
2351 if (equalIgnoringCase(where, "afterBegin") || equalIgnoringCase(where, "beforeEnd"))
2352 return element;
2353 exceptionState.throwDOMException(SyntaxError, "The value provided ('" + where + "') is not one of 'beforeBegin', 'afterBegin', 'beforeEnd', or 'afterEnd'.");
2354 return 0;
2355}
2356
2357void Element::insertAdjacentHTML(const String& where, const String& markup, ExceptionState& exceptionState)
2358{
2359 RefPtr<Element> contextElement = contextElementForInsertion(where, this, exceptionState);
2360 if (!contextElement)
2361 return;
2362
2363 RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(markup, contextElement.get(), AllowScriptingContent, "insertAdjacentHTML", exceptionState);
2364 if (!fragment)
2365 return;
2366 insertAdjacent(where, fragment.get(), exceptionState);
2367}
2368
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002369String Element::innerText()
2370{
2371 // We need to update layout, since plainText uses line boxes in the render tree.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002372 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002373
2374 if (!renderer())
2375 return textContent(true);
2376
2377 return plainText(rangeOfContents(const_cast<Element*>(this)).get());
2378}
2379
2380String Element::outerText()
2381{
2382 // Getting outerText is the same as getting innerText, only
2383 // setting is different. You would think this should get the plain
2384 // text for the outer range, but this is wrong, <br> for instance
2385 // would return different values for inner and outer text by such
2386 // a rule, but it doesn't in WinIE, and we want to match that.
2387 return innerText();
2388}
2389
Ben Murdoch591b9582013-07-10 11:41:44 +01002390String Element::textFromChildren()
2391{
2392 Text* firstTextNode = 0;
2393 bool foundMultipleTextNodes = false;
2394 unsigned totalLength = 0;
2395
2396 for (Node* child = firstChild(); child; child = child->nextSibling()) {
2397 if (!child->isTextNode())
2398 continue;
2399 Text* text = toText(child);
2400 if (!firstTextNode)
2401 firstTextNode = text;
2402 else
2403 foundMultipleTextNodes = true;
2404 unsigned length = text->data().length();
2405 if (length > std::numeric_limits<unsigned>::max() - totalLength)
2406 return emptyString();
2407 totalLength += length;
2408 }
2409
2410 if (!firstTextNode)
2411 return emptyString();
2412
2413 if (firstTextNode && !foundMultipleTextNodes) {
2414 firstTextNode->atomize();
2415 return firstTextNode->data();
2416 }
2417
2418 StringBuilder content;
2419 content.reserveCapacity(totalLength);
2420 for (Node* child = firstTextNode; child; child = child->nextSibling()) {
2421 if (!child->isTextNode())
2422 continue;
2423 content.append(toText(child)->data());
2424 }
2425
2426 ASSERT(content.length() == totalLength);
2427 return content.toString();
2428}
2429
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01002430// pseudo is used via shadowPseudoId.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002431const AtomicString& Element::pseudo() const
2432{
2433 return getAttribute(pseudoAttr);
2434}
2435
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002436void Element::setPseudo(const AtomicString& value)
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002437{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002438 setAttribute(pseudoAttr, value);
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002439}
2440
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002441bool Element::isInDescendantTreeOf(const Element* shadowHost) const
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002442{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002443 ASSERT(shadowHost);
2444 ASSERT(isShadowHost(shadowHost));
2445
2446 const ShadowRoot* shadowRoot = containingShadowRoot();
2447 while (shadowRoot) {
2448 const Element* ancestorShadowHost = shadowRoot->shadowHost();
2449 if (ancestorShadowHost == shadowHost)
2450 return true;
2451 shadowRoot = ancestorShadowHost->containingShadowRoot();
2452 }
2453 return false;
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002454}
2455
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002456LayoutSize Element::minimumSizeForResizing() const
2457{
2458 return hasRareData() ? elementRareData()->minimumSizeForResizing() : defaultMinimumSizeForResizing();
2459}
2460
2461void Element::setMinimumSizeForResizing(const LayoutSize& size)
2462{
2463 if (!hasRareData() && size == defaultMinimumSizeForResizing())
2464 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002465 ensureElementRareData().setMinimumSizeForResizing(size);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002466}
2467
2468RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
2469{
2470 if (PseudoElement* element = pseudoElement(pseudoElementSpecifier))
2471 return element->computedStyle();
2472
2473 // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
2474 // properties, which are only known by the renderer because it did the layout, will be correct and so that the
2475 // values returned for the ":selection" pseudo-element will be correct.
2476 if (RenderStyle* usedStyle = renderStyle()) {
2477 if (pseudoElementSpecifier) {
2478 RenderStyle* cachedPseudoStyle = usedStyle->getCachedPseudoStyle(pseudoElementSpecifier);
2479 return cachedPseudoStyle ? cachedPseudoStyle : usedStyle;
2480 } else
2481 return usedStyle;
2482 }
2483
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00002484 if (!inActiveDocument())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002485 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
2486 // document tree and figure out when to destroy the computed style for such elements.
2487 return 0;
2488
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002489 ElementRareData& rareData = ensureElementRareData();
2490 if (!rareData.computedStyle())
2491 rareData.setComputedStyle(document().styleForElementIgnoringPendingStylesheets(this));
2492 return pseudoElementSpecifier ? rareData.computedStyle()->getCachedPseudoStyle(pseudoElementSpecifier) : rareData.computedStyle();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002493}
2494
2495void Element::setStyleAffectedByEmpty()
2496{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002497 ensureElementRareData().setStyleAffectedByEmpty(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002498}
2499
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002500void Element::setChildrenAffectedByFocus()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002501{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002502 ensureElementRareData().setChildrenAffectedByFocus(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002503}
2504
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002505void Element::setChildrenAffectedByHover()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002506{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002507 ensureElementRareData().setChildrenAffectedByHover(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002508}
2509
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002510void Element::setChildrenAffectedByActive()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002511{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002512 ensureElementRareData().setChildrenAffectedByActive(true);
2513}
2514
2515void Element::setChildrenAffectedByDrag()
2516{
2517 ensureElementRareData().setChildrenAffectedByDrag(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002518}
2519
2520void Element::setChildrenAffectedByFirstChildRules()
2521{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002522 ensureElementRareData().setChildrenAffectedByFirstChildRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002523}
2524
2525void Element::setChildrenAffectedByLastChildRules()
2526{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002527 ensureElementRareData().setChildrenAffectedByLastChildRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002528}
2529
2530void Element::setChildrenAffectedByDirectAdjacentRules()
2531{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002532 ensureElementRareData().setChildrenAffectedByDirectAdjacentRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002533}
2534
2535void Element::setChildrenAffectedByForwardPositionalRules()
2536{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002537 ensureElementRareData().setChildrenAffectedByForwardPositionalRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002538}
2539
2540void Element::setChildrenAffectedByBackwardPositionalRules()
2541{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002542 ensureElementRareData().setChildrenAffectedByBackwardPositionalRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002543}
2544
2545void Element::setChildIndex(unsigned index)
2546{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002547 ElementRareData& rareData = ensureElementRareData();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002548 if (RenderStyle* style = renderStyle())
2549 style->setUnique();
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002550 rareData.setChildIndex(index);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002551}
2552
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002553bool Element::childrenSupportStyleSharing() const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002554{
2555 if (!hasRareData())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002556 return true;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002557 return !rareDataChildrenAffectedByFocus()
2558 && !rareDataChildrenAffectedByHover()
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002559 && !rareDataChildrenAffectedByActive()
2560 && !rareDataChildrenAffectedByDrag()
2561 && !rareDataChildrenAffectedByFirstChildRules()
2562 && !rareDataChildrenAffectedByLastChildRules()
2563 && !rareDataChildrenAffectedByDirectAdjacentRules()
2564 && !rareDataChildrenAffectedByForwardPositionalRules()
2565 && !rareDataChildrenAffectedByBackwardPositionalRules();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002566}
2567
2568bool Element::rareDataStyleAffectedByEmpty() const
2569{
2570 ASSERT(hasRareData());
2571 return elementRareData()->styleAffectedByEmpty();
2572}
2573
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002574bool Element::rareDataChildrenAffectedByFocus() const
2575{
2576 ASSERT(hasRareData());
2577 return elementRareData()->childrenAffectedByFocus();
2578}
2579
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002580bool Element::rareDataChildrenAffectedByHover() const
2581{
2582 ASSERT(hasRareData());
2583 return elementRareData()->childrenAffectedByHover();
2584}
2585
2586bool Element::rareDataChildrenAffectedByActive() const
2587{
2588 ASSERT(hasRareData());
2589 return elementRareData()->childrenAffectedByActive();
2590}
2591
2592bool Element::rareDataChildrenAffectedByDrag() const
2593{
2594 ASSERT(hasRareData());
2595 return elementRareData()->childrenAffectedByDrag();
2596}
2597
2598bool Element::rareDataChildrenAffectedByFirstChildRules() const
2599{
2600 ASSERT(hasRareData());
2601 return elementRareData()->childrenAffectedByFirstChildRules();
2602}
2603
2604bool Element::rareDataChildrenAffectedByLastChildRules() const
2605{
2606 ASSERT(hasRareData());
2607 return elementRareData()->childrenAffectedByLastChildRules();
2608}
2609
2610bool Element::rareDataChildrenAffectedByDirectAdjacentRules() const
2611{
2612 ASSERT(hasRareData());
2613 return elementRareData()->childrenAffectedByDirectAdjacentRules();
2614}
2615
2616bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
2617{
2618 ASSERT(hasRareData());
2619 return elementRareData()->childrenAffectedByForwardPositionalRules();
2620}
2621
2622bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
2623{
2624 ASSERT(hasRareData());
2625 return elementRareData()->childrenAffectedByBackwardPositionalRules();
2626}
2627
2628unsigned Element::rareDataChildIndex() const
2629{
2630 ASSERT(hasRareData());
2631 return elementRareData()->childIndex();
2632}
2633
2634void Element::setIsInCanvasSubtree(bool isInCanvasSubtree)
2635{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002636 ensureElementRareData().setIsInCanvasSubtree(isInCanvasSubtree);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002637}
2638
2639bool Element::isInCanvasSubtree() const
2640{
2641 return hasRareData() && elementRareData()->isInCanvasSubtree();
2642}
2643
Ben Murdoch591b9582013-07-10 11:41:44 +01002644void Element::setIsInsideRegion(bool value)
2645{
2646 if (value == isInsideRegion())
2647 return;
2648
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002649 ensureElementRareData().setIsInsideRegion(value);
Ben Murdoch591b9582013-07-10 11:41:44 +01002650}
2651
2652bool Element::isInsideRegion() const
2653{
2654 return hasRareData() ? elementRareData()->isInsideRegion() : false;
2655}
2656
2657void Element::setRegionOversetState(RegionOversetState state)
2658{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002659 ensureElementRareData().setRegionOversetState(state);
Ben Murdoch591b9582013-07-10 11:41:44 +01002660}
2661
2662RegionOversetState Element::regionOversetState() const
2663{
2664 return hasRareData() ? elementRareData()->regionOversetState() : RegionUndefined;
2665}
2666
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002667AtomicString Element::computeInheritedLanguage() const
2668{
2669 const Node* n = this;
2670 AtomicString value;
2671 // The language property is inherited, so we iterate over the parents to find the first language.
2672 do {
2673 if (n->isElementNode()) {
2674 if (const ElementData* elementData = toElement(n)->elementData()) {
2675 // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7
2676 if (const Attribute* attribute = elementData->getAttributeItem(XMLNames::langAttr))
2677 value = attribute->value();
2678 else if (const Attribute* attribute = elementData->getAttributeItem(HTMLNames::langAttr))
2679 value = attribute->value();
2680 }
2681 } else if (n->isDocumentNode()) {
2682 // checking the MIME content-language
2683 value = toDocument(n)->contentLanguage();
2684 }
2685
2686 n = n->parentNode();
2687 } while (n && value.isNull());
2688
2689 return value;
2690}
2691
2692Locale& Element::locale() const
2693{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002694 return document().getCachedLocale(computeInheritedLanguage());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002695}
2696
2697void Element::cancelFocusAppearanceUpdate()
2698{
2699 if (hasRareData())
2700 elementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002701 if (document().focusedElement() == this)
2702 document().cancelFocusAppearanceUpdate();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002703}
2704
2705void Element::normalizeAttributes()
2706{
2707 if (!hasAttributes())
2708 return;
2709 for (unsigned i = 0; i < attributeCount(); ++i) {
2710 if (RefPtr<Attr> attr = attrIfExists(attributeItem(i)->name()))
2711 attr->normalize();
2712 }
2713}
2714
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002715void Element::updatePseudoElement(PseudoId pseudoId, StyleRecalcChange change)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002716{
2717 PseudoElement* element = pseudoElement(pseudoId);
2718 if (element && (needsStyleRecalc() || shouldRecalcStyle(change, element))) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002719 // Need to clear the cached style if the PseudoElement wants a recalc so it
2720 // computes a new style.
2721 if (element->needsStyleRecalc())
2722 renderer()->style()->removeCachedPseudoStyle(pseudoId);
2723
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002724 // PseudoElement styles hang off their parent element's style so if we needed
2725 // a style recalc we should Force one on the pseudo.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002726 // FIXME: We should figure out the right text sibling to pass.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002727 element->recalcStyle(needsStyleRecalc() ? Force : change);
2728
2729 // Wait until our parent is not displayed or pseudoElementRendererIsNeeded
2730 // is false, otherwise we could continously create and destroy PseudoElements
2731 // when RenderObject::isChildAllowed on our parent returns false for the
2732 // PseudoElement's renderer for each style recalc.
2733 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01002734 elementRareData()->setPseudoElement(pseudoId, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002735 } else if (change >= Inherit || needsStyleRecalc())
2736 createPseudoElementIfNeeded(pseudoId);
2737}
2738
2739void Element::createPseudoElementIfNeeded(PseudoId pseudoId)
2740{
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002741 if (needsPseudoElement(pseudoId))
2742 createPseudoElement(pseudoId);
2743}
2744
2745bool Element::needsPseudoElement(PseudoId pseudoId) const
2746{
Ben Murdoche69819b2013-07-17 14:56:49 +01002747 if (pseudoId == BACKDROP && !isInTopLayer())
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002748 return false;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002749 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002750 return false;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002751 if (!renderer()->canHaveGeneratedChildren())
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002752 return false;
2753 return true;
2754}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002755
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002756void Element::createPseudoElement(PseudoId pseudoId)
2757{
2758 ASSERT(needsPseudoElement(pseudoId));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002759 ASSERT(!isPseudoElement());
2760 RefPtr<PseudoElement> element = PseudoElement::create(this, pseudoId);
Ben Murdoche69819b2013-07-17 14:56:49 +01002761 if (pseudoId == BACKDROP)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002762 document().addToTopLayer(element.get(), this);
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002763 element->insertedInto(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002764 element->attach();
Ben Murdoche69819b2013-07-17 14:56:49 +01002765
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002766 InspectorInstrumentation::pseudoElementCreated(element.get());
2767
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002768 ensureElementRareData().setPseudoElement(pseudoId, element.release());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002769}
2770
2771PseudoElement* Element::pseudoElement(PseudoId pseudoId) const
2772{
2773 return hasRareData() ? elementRareData()->pseudoElement(pseudoId) : 0;
2774}
2775
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002776RenderObject* Element::pseudoElementRenderer(PseudoId pseudoId) const
2777{
2778 if (PseudoElement* element = pseudoElement(pseudoId))
2779 return element->renderer();
2780 return 0;
2781}
2782
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002783bool Element::webkitMatchesSelector(const String& selector, ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002784{
2785 if (selector.isEmpty()) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002786 exceptionState.throwUninformativeAndGenericDOMException(SyntaxError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002787 return false;
2788 }
2789
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002790 SelectorQuery* selectorQuery = document().selectorQueryCache().add(selector, document(), exceptionState);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002791 if (!selectorQuery)
2792 return false;
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002793 return selectorQuery->matches(*this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002794}
2795
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002796DOMTokenList* Element::classList()
2797{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002798 ElementRareData& rareData = ensureElementRareData();
2799 if (!rareData.classList())
2800 rareData.setClassList(ClassList::create(this));
2801 return rareData.classList();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002802}
2803
2804DOMStringMap* Element::dataset()
2805{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002806 ElementRareData& rareData = ensureElementRareData();
2807 if (!rareData.dataset())
2808 rareData.setDataset(DatasetDOMStringMap::create(this));
2809 return rareData.dataset();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002810}
2811
2812KURL Element::getURLAttribute(const QualifiedName& name) const
2813{
2814#if !ASSERT_DISABLED
2815 if (elementData()) {
2816 if (const Attribute* attribute = getAttributeItem(name))
2817 ASSERT(isURLAttribute(*attribute));
2818 }
2819#endif
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002820 return document().completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002821}
2822
2823KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
2824{
2825#if !ASSERT_DISABLED
2826 if (elementData()) {
2827 if (const Attribute* attribute = getAttributeItem(name))
2828 ASSERT(isURLAttribute(*attribute));
2829 }
2830#endif
2831 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
2832 if (value.isEmpty())
2833 return KURL();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002834 return document().completeURL(value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002835}
2836
2837int Element::getIntegralAttribute(const QualifiedName& attributeName) const
2838{
2839 return getAttribute(attributeName).string().toInt();
2840}
2841
2842void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
2843{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002844 setAttribute(attributeName, AtomicString::number(value));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002845}
2846
2847unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
2848{
2849 return getAttribute(attributeName).string().toUInt();
2850}
2851
2852void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
2853{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002854 setAttribute(attributeName, AtomicString::number(value));
2855}
2856
2857double Element::getFloatingPointAttribute(const QualifiedName& attributeName, double fallbackValue) const
2858{
2859 return parseToDoubleForNumberType(getAttribute(attributeName), fallbackValue);
2860}
2861
2862void Element::setFloatingPointAttribute(const QualifiedName& attributeName, double value)
2863{
2864 setAttribute(attributeName, AtomicString::number(value));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002865}
2866
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002867bool Element::childShouldCreateRenderer(const Node& child) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002868{
2869 // 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 +01002870 if (child.isSVGElement())
2871 return child.hasTagName(SVGNames::svgTag) || isSVGElement();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002872
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002873 return ContainerNode::childShouldCreateRenderer(child);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002874}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002875
2876void Element::webkitRequestFullscreen()
2877{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002878 FullscreenElementStack::from(&document())->requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002879}
2880
2881void Element::webkitRequestFullScreen(unsigned short flags)
2882{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002883 FullscreenElementStack::from(&document())->requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002884}
2885
2886bool Element::containsFullScreenElement() const
2887{
2888 return hasRareData() && elementRareData()->containsFullScreenElement();
2889}
2890
2891void Element::setContainsFullScreenElement(bool flag)
2892{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002893 ensureElementRareData().setContainsFullScreenElement(flag);
Ben Murdoche69819b2013-07-17 14:56:49 +01002894 setNeedsStyleRecalc(SubtreeStyleChange);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002895}
2896
2897static Element* parentCrossingFrameBoundaries(Element* element)
2898{
2899 ASSERT(element);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002900 return element->parentElement() ? element->parentElement() : element->document().ownerElement();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002901}
2902
2903void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool flag)
2904{
2905 Element* element = this;
2906 while ((element = parentCrossingFrameBoundaries(element)))
2907 element->setContainsFullScreenElement(flag);
2908}
2909
2910bool Element::isInTopLayer() const
2911{
2912 return hasRareData() && elementRareData()->isInTopLayer();
2913}
2914
2915void Element::setIsInTopLayer(bool inTopLayer)
2916{
2917 if (isInTopLayer() == inTopLayer)
2918 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002919 ensureElementRareData().setIsInTopLayer(inTopLayer);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002920
2921 // We must ensure a reattach occurs so the renderer is inserted in the correct sibling order under RenderView according to its
2922 // top layer position, or in its usual place if not in the top layer.
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002923 lazyReattachIfAttached();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002924}
2925
2926void Element::webkitRequestPointerLock()
2927{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002928 if (document().page())
2929 document().page()->pointerLockController().requestPointerLock(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002930}
2931
2932SpellcheckAttributeState Element::spellcheckAttributeState() const
2933{
2934 const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
2935 if (value == nullAtom)
2936 return SpellcheckAttributeDefault;
2937 if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
2938 return SpellcheckAttributeTrue;
2939 if (equalIgnoringCase(value, "false"))
2940 return SpellcheckAttributeFalse;
2941
2942 return SpellcheckAttributeDefault;
2943}
2944
2945bool Element::isSpellCheckingEnabled() const
2946{
2947 for (const Element* element = this; element; element = element->parentOrShadowHostElement()) {
2948 switch (element->spellcheckAttributeState()) {
2949 case SpellcheckAttributeTrue:
2950 return true;
2951 case SpellcheckAttributeFalse:
2952 return false;
2953 case SpellcheckAttributeDefault:
2954 break;
2955 }
2956 }
2957
2958 return true;
2959}
2960
2961RenderRegion* Element::renderRegion() const
2962{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002963 if (renderer() && renderer()->isRenderNamedFlowFragmentContainer())
2964 return toRenderBlockFlow(renderer())->renderNamedFlowFragment();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002965
2966 return 0;
2967}
2968
Ben Murdoch591b9582013-07-10 11:41:44 +01002969bool Element::shouldMoveToFlowThread(RenderStyle* styleToUse) const
2970{
2971 ASSERT(styleToUse);
2972
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002973 if (FullscreenElementStack::isActiveFullScreenElement(this))
Ben Murdoch591b9582013-07-10 11:41:44 +01002974 return false;
2975
2976 if (isInShadowTree())
2977 return false;
2978
2979 if (styleToUse->flowThread().isEmpty())
2980 return false;
2981
2982 return !isRegisteredWithNamedFlow();
2983}
2984
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002985const AtomicString& Element::webkitRegionOverset() const
2986{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002987 DEFINE_STATIC_LOCAL(AtomicString, undefinedState, ("undefined", AtomicString::ConstructFromLiteral));
2988 if (!RuntimeEnabledFeatures::cssRegionsEnabled())
2989 return undefinedState;
2990
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002991 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002992
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002993 if (!renderRegion())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002994 return undefinedState;
2995
Ben Murdoch591b9582013-07-10 11:41:44 +01002996 switch (renderRegion()->regionOversetState()) {
2997 case RegionFit: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002998 DEFINE_STATIC_LOCAL(AtomicString, fitState, ("fit", AtomicString::ConstructFromLiteral));
2999 return fitState;
3000 }
Ben Murdoch591b9582013-07-10 11:41:44 +01003001 case RegionEmpty: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003002 DEFINE_STATIC_LOCAL(AtomicString, emptyState, ("empty", AtomicString::ConstructFromLiteral));
3003 return emptyState;
3004 }
Ben Murdoch591b9582013-07-10 11:41:44 +01003005 case RegionOverset: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003006 DEFINE_STATIC_LOCAL(AtomicString, overflowState, ("overset", AtomicString::ConstructFromLiteral));
3007 return overflowState;
3008 }
Ben Murdoch591b9582013-07-10 11:41:44 +01003009 case RegionUndefined:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003010 return undefinedState;
3011 }
3012
3013 ASSERT_NOT_REACHED();
3014 return undefinedState;
3015}
3016
3017Vector<RefPtr<Range> > Element::webkitGetRegionFlowRanges() const
3018{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00003019 Vector<RefPtr<Range> > rangeObjects;
3020 if (!RuntimeEnabledFeatures::cssRegionsEnabled())
3021 return rangeObjects;
3022
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003023 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003024
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00003025 if (renderer() && renderer()->isRenderNamedFlowFragmentContainer()) {
3026 RenderNamedFlowFragment* region = toRenderBlockFlow(renderer())->renderNamedFlowFragment();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003027 if (region->isValid())
3028 region->getRanges(rangeObjects);
3029 }
3030
3031 return rangeObjects;
3032}
3033
3034#ifndef NDEBUG
3035bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
3036{
3037 if (name == HTMLNames::styleAttr)
3038 return false;
3039
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003040 if (isSVGElement())
3041 return !static_cast<const SVGElement*>(this)->isAnimatableAttribute(name);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003042
3043 return true;
3044}
3045#endif
3046
3047#ifdef DUMP_NODE_STATISTICS
3048bool Element::hasNamedNodeMap() const
3049{
3050 return hasRareData() && elementRareData()->attributeMap();
3051}
3052#endif
3053
Ben Murdoch00d3faa2013-08-14 11:52:03 +01003054inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003055{
Ben Murdoch00d3faa2013-08-14 11:52:03 +01003056 if (!inDocument() || isInShadowTree())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003057 return;
3058
3059 if (oldName == newName)
3060 return;
3061
Ben Murdochdf957042013-08-06 11:01:27 +01003062 if (shouldRegisterAsNamedItem())
3063 updateNamedItemRegistration(oldName, newName);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003064}
3065
Ben Murdoch00d3faa2013-08-14 11:52:03 +01003066inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003067{
3068 if (!isInTreeScope())
3069 return;
3070
3071 if (oldId == newId)
3072 return;
3073
Ben Murdoch00d3faa2013-08-14 11:52:03 +01003074 updateId(treeScope(), oldId, newId);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003075}
3076
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003077inline void Element::updateId(TreeScope& scope, const AtomicString& oldId, const AtomicString& newId)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003078{
3079 ASSERT(isInTreeScope());
3080 ASSERT(oldId != newId);
3081
3082 if (!oldId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003083 scope.removeElementById(oldId, this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003084 if (!newId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003085 scope.addElementById(newId, this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003086
Ben Murdochdf957042013-08-06 11:01:27 +01003087 if (shouldRegisterAsExtraNamedItem())
3088 updateExtraNamedItemRegistration(oldId, newId);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003089}
3090
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003091void Element::updateLabel(TreeScope& scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003092{
3093 ASSERT(hasTagName(labelTag));
3094
3095 if (!inDocument())
3096 return;
3097
3098 if (oldForAttributeValue == newForAttributeValue)
3099 return;
3100
3101 if (!oldForAttributeValue.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003102 scope.removeLabel(oldForAttributeValue, toHTMLLabelElement(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003103 if (!newForAttributeValue.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003104 scope.addLabel(newForAttributeValue, toHTMLLabelElement(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003105}
3106
Ben Murdoch7757ec22013-07-23 11:17:36 +01003107static bool hasSelectorForAttribute(Document* document, const AtomicString& localName)
3108{
Torne (Richard Coles)a854de02013-12-18 16:25:25 +00003109 return document->ensureStyleResolver().ensureRuleFeatureSet().hasSelectorForAttribute(localName);
Ben Murdoch7757ec22013-07-23 11:17:36 +01003110}
3111
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003112void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
3113{
3114 if (isIdAttributeName(name))
3115 updateId(oldValue, newValue);
3116 else if (name == HTMLNames::nameAttr)
3117 updateName(oldValue, newValue);
3118 else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003119 TreeScope& scope = treeScope();
3120 if (scope.shouldCacheLabelsByForAttribute())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003121 updateLabel(scope, oldValue, newValue);
3122 }
3123
3124 if (oldValue != newValue) {
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003125 if (inActiveDocument() && hasSelectorForAttribute(&document(), name.localName()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003126 setNeedsStyleRecalc();
Ben Murdoche69819b2013-07-17 14:56:49 +01003127
3128 if (isUpgradedCustomElement())
Ben Murdoch83750172013-07-24 10:36:59 +01003129 CustomElement::attributeDidChange(this, name.localName(), oldValue, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003130 }
3131
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003132 if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(*this, name))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003133 recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue));
3134
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003135 InspectorInstrumentation::willModifyDOMAttr(this, oldValue, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003136}
3137
3138void Element::didAddAttribute(const QualifiedName& name, const AtomicString& value)
3139{
3140 attributeChanged(name, value);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003141 InspectorInstrumentation::didModifyDOMAttr(this, name.localName(), value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003142 dispatchSubtreeModifiedEvent();
3143}
3144
3145void Element::didModifyAttribute(const QualifiedName& name, const AtomicString& value)
3146{
3147 attributeChanged(name, value);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003148 InspectorInstrumentation::didModifyDOMAttr(this, name.localName(), value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003149 // Do not dispatch a DOMSubtreeModified event here; see bug 81141.
3150}
3151
3152void Element::didRemoveAttribute(const QualifiedName& name)
3153{
3154 attributeChanged(name, nullAtom);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003155 InspectorInstrumentation::didRemoveDOMAttr(this, name.localName());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003156 dispatchSubtreeModifiedEvent();
3157}
3158
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01003159void Element::didMoveToNewDocument(Document& oldDocument)
Ben Murdoche69819b2013-07-17 14:56:49 +01003160{
3161 Node::didMoveToNewDocument(oldDocument);
3162
3163 // If the documents differ by quirks mode then they differ by case sensitivity
3164 // for class and id names so we need to go through the attribute change logic
3165 // to pick up the new casing in the ElementData.
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01003166 if (oldDocument.inQuirksMode() != document().inQuirksMode()) {
Ben Murdoche69819b2013-07-17 14:56:49 +01003167 if (hasID())
3168 setIdAttribute(getIdAttribute());
3169 if (hasClass())
3170 setAttribute(HTMLNames::classAttr, getClassAttribute());
3171 }
3172}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003173
Ben Murdochdf957042013-08-06 11:01:27 +01003174void Element::updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName)
3175{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003176 if (!document().isHTMLDocument())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01003177 return;
Ben Murdochdf957042013-08-06 11:01:27 +01003178
3179 if (!oldName.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003180 toHTMLDocument(document()).removeNamedItem(oldName);
Ben Murdochdf957042013-08-06 11:01:27 +01003181
3182 if (!newName.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003183 toHTMLDocument(document()).addNamedItem(newName);
Ben Murdochdf957042013-08-06 11:01:27 +01003184}
3185
3186void Element::updateExtraNamedItemRegistration(const AtomicString& oldId, const AtomicString& newId)
3187{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003188 if (!document().isHTMLDocument())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01003189 return;
Ben Murdochdf957042013-08-06 11:01:27 +01003190
3191 if (!oldId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003192 toHTMLDocument(document()).removeExtraNamedItem(oldId);
Ben Murdochdf957042013-08-06 11:01:27 +01003193
3194 if (!newId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003195 toHTMLDocument(document()).addExtraNamedItem(newId);
Ben Murdochdf957042013-08-06 11:01:27 +01003196}
3197
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003198PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
3199{
3200 if (HTMLCollection* collection = cachedHTMLCollection(type))
3201 return collection;
3202
3203 RefPtr<HTMLCollection> collection;
3204 if (type == TableRows) {
3205 ASSERT(hasTagName(tableTag));
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003206 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003207 } else if (type == SelectOptions) {
3208 ASSERT(hasTagName(selectTag));
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003209 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003210 } else if (type == FormControls) {
3211 ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003212 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003213 }
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003214 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003215}
3216
Ben Murdoch591b9582013-07-10 11:41:44 +01003217static void scheduleLayerUpdateCallback(Node* node)
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003218{
Ben Murdoche69819b2013-07-17 14:56:49 +01003219 // Notify the renderer even is the styles are identical since it may need to
3220 // create or destroy a RenderLayer.
3221 node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003222}
3223
Ben Murdoch591b9582013-07-10 11:41:44 +01003224void Element::scheduleLayerUpdate()
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003225{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003226 if (document().inStyleRecalc())
3227 PostAttachCallbacks::queueCallback(scheduleLayerUpdateCallback, this);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003228 else
Ben Murdoche69819b2013-07-17 14:56:49 +01003229 scheduleLayerUpdateCallback(this);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003230}
3231
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003232HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
3233{
3234 return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0;
3235}
3236
3237IntSize Element::savedLayerScrollOffset() const
3238{
3239 return hasRareData() ? elementRareData()->savedLayerScrollOffset() : IntSize();
3240}
3241
3242void Element::setSavedLayerScrollOffset(const IntSize& size)
3243{
3244 if (size.isZero() && !hasRareData())
3245 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003246 ensureElementRareData().setSavedLayerScrollOffset(size);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003247}
3248
3249PassRefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
3250{
3251 if (AttrNodeList* attrNodeList = attrNodeListForElement(this))
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003252 return findAttrNodeInList(*attrNodeList, name);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003253 return 0;
3254}
3255
3256PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name)
3257{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003258 AttrNodeList& attrNodeList = ensureAttrNodeListForElement(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003259 RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
3260 if (!attrNode) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003261 attrNode = Attr::create(*this, name);
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003262 treeScope().adoptIfNeeded(*attrNode);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003263 attrNodeList.append(attrNode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003264 }
3265 return attrNode.release();
3266}
3267
3268void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value)
3269{
3270 ASSERT(hasSyntheticAttrChildNodes());
3271 attrNode->detachFromElementWithValue(value);
3272
3273 AttrNodeList* attrNodeList = attrNodeListForElement(this);
3274 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
3275 if (attrNodeList->at(i)->qualifiedName() == attrNode->qualifiedName()) {
3276 attrNodeList->remove(i);
3277 if (attrNodeList->isEmpty())
3278 removeAttrNodeListForElement(this);
3279 return;
3280 }
3281 }
3282 ASSERT_NOT_REACHED();
3283}
3284
3285void Element::detachAllAttrNodesFromElement()
3286{
3287 AttrNodeList* attrNodeList = attrNodeListForElement(this);
3288 ASSERT(attrNodeList);
3289
3290 for (unsigned i = 0; i < attributeCount(); ++i) {
3291 const Attribute* attribute = attributeItem(i);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003292 if (RefPtr<Attr> attrNode = findAttrNodeInList(*attrNodeList, attribute->name()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003293 attrNode->detachFromElementWithValue(attribute->value());
3294 }
3295
3296 removeAttrNodeListForElement(this);
3297}
3298
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003299void Element::willRecalcStyle(StyleRecalcChange)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003300{
3301 ASSERT(hasCustomStyleCallbacks());
3302}
3303
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003304void Element::didRecalcStyle(StyleRecalcChange)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003305{
3306 ASSERT(hasCustomStyleCallbacks());
3307}
3308
3309
3310PassRefPtr<RenderStyle> Element::customStyleForRenderer()
3311{
3312 ASSERT(hasCustomStyleCallbacks());
3313 return 0;
3314}
3315
3316void Element::cloneAttributesFromElement(const Element& other)
3317{
3318 if (hasSyntheticAttrChildNodes())
3319 detachAllAttrNodesFromElement();
3320
3321 other.synchronizeAllAttributes();
3322 if (!other.m_elementData) {
3323 m_elementData.clear();
3324 return;
3325 }
3326
3327 const AtomicString& oldID = getIdAttribute();
3328 const AtomicString& newID = other.getIdAttribute();
3329
3330 if (!oldID.isNull() || !newID.isNull())
3331 updateId(oldID, newID);
3332
3333 const AtomicString& oldName = getNameAttribute();
3334 const AtomicString& newName = other.getNameAttribute();
3335
3336 if (!oldName.isNull() || !newName.isNull())
3337 updateName(oldName, newName);
3338
Ben Murdoche69819b2013-07-17 14:56:49 +01003339 // Quirks mode makes class and id not case sensitive. We can't share the ElementData
3340 // if the idForStyleResolution and the className need different casing.
3341 bool ownerDocumentsHaveDifferentCaseSensitivity = false;
3342 if (other.hasClass() || other.hasID())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003343 ownerDocumentsHaveDifferentCaseSensitivity = other.document().inQuirksMode() != document().inQuirksMode();
Ben Murdoche69819b2013-07-17 14:56:49 +01003344
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003345 // 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 +01003346 // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes,
3347 // and sharing the data won't result in different case sensitivity of class or id.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003348 if (other.m_elementData->isUnique()
Ben Murdoche69819b2013-07-17 14:56:49 +01003349 && !ownerDocumentsHaveDifferentCaseSensitivity
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003350 && !other.m_elementData->presentationAttributeStyle()
3351 && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper()))
3352 const_cast<Element&>(other).m_elementData = static_cast<const UniqueElementData*>(other.m_elementData.get())->makeShareableCopy();
3353
Ben Murdoche69819b2013-07-17 14:56:49 +01003354 if (!other.m_elementData->isUnique() && !ownerDocumentsHaveDifferentCaseSensitivity)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003355 m_elementData = other.m_elementData;
3356 else
3357 m_elementData = other.m_elementData->makeUniqueCopy();
3358
3359 for (unsigned i = 0; i < m_elementData->length(); ++i) {
3360 const Attribute* attribute = const_cast<const ElementData*>(m_elementData.get())->attributeItem(i);
3361 attributeChangedFromParserOrByCloning(attribute->name(), attribute->value(), ModifiedByCloning);
3362 }
3363}
3364
3365void Element::cloneDataFromElement(const Element& other)
3366{
3367 cloneAttributesFromElement(other);
3368 copyNonAttributePropertiesFromElement(other);
3369}
3370
3371void Element::createUniqueElementData()
3372{
3373 if (!m_elementData)
3374 m_elementData = UniqueElementData::create();
3375 else {
3376 ASSERT(!m_elementData->isUnique());
3377 m_elementData = static_cast<ShareableElementData*>(m_elementData.get())->makeUniqueCopy();
3378 }
3379}
3380
Ben Murdoch1fad5ca2013-08-07 11:05:11 +01003381InputMethodContext* Element::inputMethodContext()
Torne (Richard Coles)81a51572013-05-13 16:52:28 +01003382{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003383 return ensureElementRareData().ensureInputMethodContext(toHTMLElement(this));
Torne (Richard Coles)81a51572013-05-13 16:52:28 +01003384}
3385
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00003386bool Element::hasInputMethodContext() const
3387{
3388 return hasRareData() && elementRareData()->hasInputMethodContext();
3389}
3390
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003391bool Element::hasPendingResources() const
3392{
3393 return hasRareData() && elementRareData()->hasPendingResources();
3394}
3395
3396void Element::setHasPendingResources()
3397{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003398 ensureElementRareData().setHasPendingResources(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003399}
3400
3401void Element::clearHasPendingResources()
3402{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003403 ensureElementRareData().setHasPendingResources(false);
Ben Murdoch591b9582013-07-10 11:41:44 +01003404}
3405
3406void Element::synchronizeStyleAttributeInternal() const
3407{
3408 ASSERT(isStyledElement());
3409 ASSERT(elementData());
3410 ASSERT(elementData()->m_styleAttributeIsDirty);
3411 elementData()->m_styleAttributeIsDirty = false;
3412 if (const StylePropertySet* inlineStyle = this->inlineStyle())
3413 const_cast<Element*>(this)->setSynchronizedLazyAttribute(styleAttr, inlineStyle->asText());
3414}
3415
3416CSSStyleDeclaration* Element::style()
3417{
3418 if (!isStyledElement())
3419 return 0;
3420 return ensureMutableInlineStyle()->ensureInlineCSSStyleDeclaration(this);
3421}
3422
3423MutableStylePropertySet* Element::ensureMutableInlineStyle()
3424{
3425 ASSERT(isStyledElement());
3426 RefPtr<StylePropertySet>& inlineStyle = ensureUniqueElementData()->m_inlineStyle;
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003427 if (!inlineStyle) {
3428 CSSParserMode mode = (!isHTMLElement() || document().inQuirksMode()) ? HTMLQuirksMode : HTMLStandardMode;
3429 inlineStyle = MutableStylePropertySet::create(mode);
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00003430 } else if (!inlineStyle->isMutable()) {
Ben Murdoch591b9582013-07-10 11:41:44 +01003431 inlineStyle = inlineStyle->mutableCopy();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00003432 }
3433 return toMutableStylePropertySet(inlineStyle);
Ben Murdoch591b9582013-07-10 11:41:44 +01003434}
3435
3436PropertySetCSSStyleDeclaration* Element::inlineStyleCSSOMWrapper()
3437{
3438 if (!inlineStyle() || !inlineStyle()->hasCSSOMWrapper())
3439 return 0;
3440 PropertySetCSSStyleDeclaration* cssomWrapper = ensureMutableInlineStyle()->cssStyleDeclaration();
3441 ASSERT(cssomWrapper && cssomWrapper->parentElement() == this);
3442 return cssomWrapper;
3443}
3444
3445inline void Element::setInlineStyleFromString(const AtomicString& newStyleString)
3446{
3447 ASSERT(isStyledElement());
3448 RefPtr<StylePropertySet>& inlineStyle = elementData()->m_inlineStyle;
3449
3450 // Avoid redundant work if we're using shared attribute data with already parsed inline style.
3451 if (inlineStyle && !elementData()->isUnique())
3452 return;
3453
3454 // We reconstruct the property set instead of mutating if there is no CSSOM wrapper.
3455 // This makes wrapperless property sets immutable and so cacheable.
3456 if (inlineStyle && !inlineStyle->isMutable())
3457 inlineStyle.clear();
3458
3459 if (!inlineStyle) {
3460 inlineStyle = CSSParser::parseInlineStyleDeclaration(newStyleString, this);
3461 } else {
3462 ASSERT(inlineStyle->isMutable());
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003463 static_pointer_cast<MutableStylePropertySet>(inlineStyle)->parseDeclaration(newStyleString, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003464 }
3465}
3466
3467void Element::styleAttributeChanged(const AtomicString& newStyleString, AttributeModificationReason modificationReason)
3468{
3469 ASSERT(isStyledElement());
3470 WTF::OrdinalNumber startLineNumber = WTF::OrdinalNumber::beforeFirst();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003471 if (document().scriptableDocumentParser() && !document().isInDocumentWrite())
3472 startLineNumber = document().scriptableDocumentParser()->lineNumber();
Ben Murdoch591b9582013-07-10 11:41:44 +01003473
3474 if (newStyleString.isNull()) {
3475 if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
3476 cssomWrapper->clearParentElement();
3477 ensureUniqueElementData()->m_inlineStyle.clear();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003478 } else if (modificationReason == ModifiedByCloning || document().contentSecurityPolicy()->allowInlineStyle(document().url(), startLineNumber)) {
Ben Murdoch591b9582013-07-10 11:41:44 +01003479 setInlineStyleFromString(newStyleString);
3480 }
3481
3482 elementData()->m_styleAttributeIsDirty = false;
3483
Ben Murdoche69819b2013-07-17 14:56:49 +01003484 setNeedsStyleRecalc(LocalStyleChange);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003485 InspectorInstrumentation::didInvalidateStyleAttr(this);
Ben Murdoch591b9582013-07-10 11:41:44 +01003486}
3487
3488void Element::inlineStyleChanged()
3489{
3490 ASSERT(isStyledElement());
Ben Murdoche69819b2013-07-17 14:56:49 +01003491 setNeedsStyleRecalc(LocalStyleChange);
Ben Murdoch591b9582013-07-10 11:41:44 +01003492 ASSERT(elementData());
3493 elementData()->m_styleAttributeIsDirty = true;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003494 InspectorInstrumentation::didInvalidateStyleAttr(this);
Ben Murdoch591b9582013-07-10 11:41:44 +01003495}
3496
3497bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
3498{
3499 ASSERT(isStyledElement());
3500 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
3501 inlineStyleChanged();
3502 return true;
3503}
3504
3505bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
3506{
3507 ASSERT(isStyledElement());
3508 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
3509 inlineStyleChanged();
3510 return true;
3511}
3512
3513bool Element::setInlineStyleProperty(CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit, bool important)
3514{
3515 ASSERT(isStyledElement());
3516 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createValue(value, unit), important);
3517 inlineStyleChanged();
3518 return true;
3519}
3520
3521bool Element::setInlineStyleProperty(CSSPropertyID propertyID, const String& value, bool important)
3522{
3523 ASSERT(isStyledElement());
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003524 bool changes = ensureMutableInlineStyle()->setProperty(propertyID, value, important, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003525 if (changes)
3526 inlineStyleChanged();
3527 return changes;
3528}
3529
3530bool Element::removeInlineStyleProperty(CSSPropertyID propertyID)
3531{
3532 ASSERT(isStyledElement());
3533 if (!inlineStyle())
3534 return false;
3535 bool changes = ensureMutableInlineStyle()->removeProperty(propertyID);
3536 if (changes)
3537 inlineStyleChanged();
3538 return changes;
3539}
3540
3541void Element::removeAllInlineStyleProperties()
3542{
3543 ASSERT(isStyledElement());
3544 if (!inlineStyle() || inlineStyle()->isEmpty())
3545 return;
3546 ensureMutableInlineStyle()->clear();
3547 inlineStyleChanged();
3548}
3549
3550void Element::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
3551{
3552 ASSERT(isStyledElement());
3553 if (const StylePropertySet* inlineStyle = elementData() ? elementData()->inlineStyle() : 0)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003554 inlineStyle->addSubresourceStyleURLs(urls, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003555}
3556
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003557void Element::updatePresentationAttributeStyle()
Ben Murdoch591b9582013-07-10 11:41:44 +01003558{
Ben Murdoch591b9582013-07-10 11:41:44 +01003559 // ShareableElementData doesn't store presentation attribute style, so make sure we have a UniqueElementData.
3560 UniqueElementData* elementData = ensureUniqueElementData();
Ben Murdoch591b9582013-07-10 11:41:44 +01003561 elementData->m_presentationAttributeStyleIsDirty = false;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003562 elementData->m_presentationAttributeStyle = computePresentationAttributeStyle(*this);
Ben Murdoch591b9582013-07-10 11:41:44 +01003563}
3564
3565void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, CSSValueID identifier)
3566{
3567 ASSERT(isStyledElement());
3568 style->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier));
3569}
3570
3571void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit)
3572{
3573 ASSERT(isStyledElement());
3574 style->setProperty(propertyID, cssValuePool().createValue(value, unit));
3575}
3576
3577void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, const String& value)
3578{
3579 ASSERT(isStyledElement());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01003580 style->setProperty(propertyID, value, false);
Ben Murdoch591b9582013-07-10 11:41:44 +01003581}
3582
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003583bool Element::supportsStyleSharing() const
3584{
3585 if (!isStyledElement() || !parentElement())
3586 return false;
3587 // If the element has inline style it is probably unique.
3588 if (inlineStyle())
3589 return false;
3590 if (isSVGElement() && toSVGElement(this)->animatedSMILStyleProperties())
3591 return false;
3592 // Ids stop style sharing if they show up in the stylesheets.
Torne (Richard Coles)a854de02013-12-18 16:25:25 +00003593 if (hasID() && document().ensureStyleResolver().hasRulesForId(idForStyleResolution()))
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003594 return false;
3595 // Active and hovered elements always make a chain towards the document node
3596 // and no siblings or cousins will have the same state.
3597 if (hovered())
3598 return false;
3599 if (active())
3600 return false;
3601 if (focused())
3602 return false;
3603 if (!parentElement()->childrenSupportStyleSharing())
3604 return false;
3605 if (hasScopedHTMLStyleChild())
3606 return false;
3607 if (this == document().cssTarget())
3608 return false;
3609 if (isHTMLElement() && toHTMLElement(this)->hasDirectionAuto())
3610 return false;
3611 if (hasActiveAnimations())
3612 return false;
3613 if (shadow() && shadow()->containsActiveStyles())
3614 return false;
3615 // Turn off style sharing for elements that can gain layers for reasons outside of the style system.
3616 // See comments in RenderObject::setStyle().
3617 // FIXME: Why does gaining a layer from outside the style system require disabling sharing?
3618 if (hasTagName(iframeTag)
3619 || hasTagName(frameTag)
3620 || hasTagName(embedTag)
3621 || hasTagName(objectTag)
3622 || hasTagName(appletTag)
3623 || hasTagName(canvasTag))
3624 return false;
3625 // FIXME: We should share style for option and optgroup whenever possible.
3626 // Before doing so, we need to resolve issues in HTMLSelectElement::recalcListItems
3627 // and RenderMenuList::setText. See also https://bugs.webkit.org/show_bug.cgi?id=88405
3628 if (hasTagName(optionTag) || hasTagName(optgroupTag))
3629 return false;
3630 if (FullscreenElementStack::isActiveFullScreenElement(this))
3631 return false;
3632 return true;
3633}
3634
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003635} // namespace WebCore