blob: cb0906602eaefb71228e14e35c6c374ad235beaf [file] [log] [blame]
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Peter Kelly (pmk@post.com)
5 * (C) 2001 Dirk Mueller (mueller@kde.org)
6 * (C) 2007 David Smith (catfish.man@gmail.com)
7 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2013 Apple Inc. All rights reserved.
8 * (C) 2007 Eric Seidel (eric@webkit.org)
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26#include "config.h"
27#include "core/dom/Element.h"
28
Ben Murdoch591b9582013-07-10 11:41:44 +010029#include "CSSPropertyNames.h"
30#include "CSSValueKeywords.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010031#include "HTMLNames.h"
Ben Murdoch7757ec22013-07-23 11:17:36 +010032#include "RuntimeEnabledFeatures.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010033#include "SVGNames.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010034#include "XMLNames.h"
Ben Murdochdf957042013-08-06 11:01:27 +010035#include "bindings/v8/ExceptionState.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010036#include "core/accessibility/AXObjectCache.h"
Ben Murdoch83750172013-07-24 10:36:59 +010037#include "core/animation/DocumentTimeline.h"
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +010038#include "core/animation/css/CSSAnimations.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010039#include "core/css/CSSParser.h"
40#include "core/css/CSSStyleSheet.h"
41#include "core/css/CSSValuePool.h"
42#include "core/css/PropertySetCSSStyleDeclaration.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010043#include "core/css/StylePropertySet.h"
Torne (Richard Coles)81a51572013-05-13 16:52:28 +010044#include "core/css/resolver/StyleResolver.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010045#include "core/dom/Attr.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010046#include "core/dom/Attribute.h"
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010047#include "core/dom/CSSSelectorWatch.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010048#include "core/dom/ClientRect.h"
49#include "core/dom/ClientRectList.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010050#include "core/dom/DatasetDOMStringMap.h"
51#include "core/dom/Document.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010052#include "core/dom/DocumentSharedObjectPool.h"
53#include "core/dom/ElementRareData.h"
54#include "core/dom/ExceptionCode.h"
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +010055#include "core/dom/FullscreenElementStack.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010056#include "core/dom/MutationObserverInterestGroup.h"
57#include "core/dom/MutationRecord.h"
58#include "core/dom/NamedNodeMap.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010059#include "core/dom/NodeRenderStyle.h"
60#include "core/dom/NodeRenderingContext.h"
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +010061#include "core/dom/PostAttachCallbacks.h"
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +010062#include "core/dom/PresentationAttributeStyle.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010063#include "core/dom/PseudoElement.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010064#include "core/dom/ScriptableDocumentParser.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010065#include "core/dom/SelectorQuery.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010066#include "core/dom/Text.h"
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010067#include "core/dom/WhitespaceChildList.h"
68#include "core/dom/custom/CustomElement.h"
69#include "core/dom/custom/CustomElementRegistrationContext.h"
Torne (Richard Coles)e5249552013-05-15 11:35:13 +010070#include "core/dom/shadow/InsertionPoint.h"
71#include "core/dom/shadow/ShadowRoot.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010072#include "core/editing/FrameSelection.h"
73#include "core/editing/TextIterator.h"
74#include "core/editing/htmlediting.h"
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010075#include "core/events/EventDispatcher.h"
76#include "core/events/FocusEvent.h"
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +010077#include "core/frame/ContentSecurityPolicy.h"
78#include "core/frame/Frame.h"
79#include "core/frame/FrameView.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010080#include "core/html/ClassList.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010081#include "core/html/HTMLCollection.h"
82#include "core/html/HTMLDocument.h"
83#include "core/html/HTMLElement.h"
84#include "core/html/HTMLFormControlsCollection.h"
85#include "core/html/HTMLFrameOwnerElement.h"
86#include "core/html/HTMLLabelElement.h"
87#include "core/html/HTMLOptionsCollection.h"
88#include "core/html/HTMLTableRowsCollection.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010089#include "core/html/parser/HTMLParserIdioms.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010090#include "core/page/FocusController.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010091#include "core/page/Page.h"
92#include "core/page/PointerLockController.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010093#include "core/rendering/FlowThreadController.h"
94#include "core/rendering/RenderRegion.h"
95#include "core/rendering/RenderView.h"
96#include "core/rendering/RenderWidget.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010097#include "core/svg/SVGDocumentExtensions.h"
98#include "core/svg/SVGElement.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010099#include "wtf/BitVector.h"
Ben Murdoch591b9582013-07-10 11:41:44 +0100100#include "wtf/HashFunctions.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100101#include "wtf/text/CString.h"
Ben Murdoch591b9582013-07-10 11:41:44 +0100102#include "wtf/text/TextPosition.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100103
104namespace WebCore {
105
106using namespace HTMLNames;
107using namespace XMLNames;
108
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100109class StyleResolverParentPusher {
110public:
111 StyleResolverParentPusher(Element* parent)
112 : m_parent(parent)
113 , m_pushedStyleResolver(0)
114 {
115 }
116 void push()
117 {
118 if (m_pushedStyleResolver)
119 return;
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100120 m_pushedStyleResolver = m_parent->document().styleResolver();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100121 m_pushedStyleResolver->pushParentElement(m_parent);
122 }
123 ~StyleResolverParentPusher()
124 {
125
126 if (!m_pushedStyleResolver)
127 return;
128
129 // This tells us that our pushed style selector is in a bad state,
130 // so we should just bail out in that scenario.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100131 ASSERT(m_pushedStyleResolver == m_parent->document().styleResolver());
132 if (m_pushedStyleResolver != m_parent->document().styleResolver())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100133 return;
134
135 m_pushedStyleResolver->popParentElement(m_parent);
136 }
137
138private:
139 Element* m_parent;
140 StyleResolver* m_pushedStyleResolver;
141};
142
143typedef Vector<RefPtr<Attr> > AttrNodeList;
144typedef HashMap<Element*, OwnPtr<AttrNodeList> > AttrNodeListMap;
145
146static AttrNodeListMap& attrNodeListMap()
147{
148 DEFINE_STATIC_LOCAL(AttrNodeListMap, map, ());
149 return map;
150}
151
152static AttrNodeList* attrNodeListForElement(Element* element)
153{
154 if (!element->hasSyntheticAttrChildNodes())
155 return 0;
156 ASSERT(attrNodeListMap().contains(element));
157 return attrNodeListMap().get(element);
158}
159
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100160static AttrNodeList& ensureAttrNodeListForElement(Element* element)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100161{
162 if (element->hasSyntheticAttrChildNodes()) {
163 ASSERT(attrNodeListMap().contains(element));
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100164 return *attrNodeListMap().get(element);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100165 }
166 ASSERT(!attrNodeListMap().contains(element));
167 element->setHasSyntheticAttrChildNodes(true);
168 AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList));
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100169 return *result.iterator->value;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100170}
171
172static void removeAttrNodeListForElement(Element* element)
173{
174 ASSERT(element->hasSyntheticAttrChildNodes());
175 ASSERT(attrNodeListMap().contains(element));
176 attrNodeListMap().remove(element);
177 element->setHasSyntheticAttrChildNodes(false);
178}
179
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100180static Attr* findAttrNodeInList(AttrNodeList& attrNodeList, const QualifiedName& name)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100181{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100182 for (unsigned i = 0; i < attrNodeList.size(); ++i) {
183 if (attrNodeList[i]->qualifiedName() == name)
184 return attrNodeList[i].get();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100185 }
186 return 0;
187}
188
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100189PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document)
190{
191 return adoptRef(new Element(tagName, document, CreateElement));
192}
193
194Element::~Element()
195{
196#ifndef NDEBUG
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100197 if (document().renderer()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100198 // When the document is not destroyed, an element that was part of a named flow
199 // content nodes should have been removed from the content nodes collection
200 // and the inNamedFlow flag reset.
201 ASSERT(!inNamedFlow());
202 }
203#endif
204
Ben Murdoch591b9582013-07-10 11:41:44 +0100205 if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
206 cssomWrapper->clearParentElement();
207
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100208 if (hasRareData()) {
209 ElementRareData* data = elementRareData();
210 data->setPseudoElement(BEFORE, 0);
211 data->setPseudoElement(AFTER, 0);
Ben Murdoche69819b2013-07-17 14:56:49 +0100212 data->setPseudoElement(BACKDROP, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100213 data->clearShadow();
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100214
215 if (RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
216 if (ActiveAnimations* activeAnimations = data->activeAnimations())
217 activeAnimations->cssAnimations()->cancel();
218 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100219 }
220
Ben Murdoch83750172013-07-24 10:36:59 +0100221 if (isCustomElement())
222 CustomElement::wasDestroyed(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100223
224 if (hasSyntheticAttrChildNodes())
225 detachAllAttrNodesFromElement();
226
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100227 if (hasPendingResources()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100228 document().accessSVGExtensions()->removeElementFromPendingResources(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100229 ASSERT(!hasPendingResources());
230 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100231}
232
233inline ElementRareData* Element::elementRareData() const
234{
235 ASSERT(hasRareData());
236 return static_cast<ElementRareData*>(rareData());
237}
238
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100239inline ElementRareData& Element::ensureElementRareData()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100240{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100241 return static_cast<ElementRareData&>(ensureRareData());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100242}
243
244void Element::clearTabIndexExplicitlyIfNeeded()
245{
246 if (hasRareData())
247 elementRareData()->clearTabIndexExplicitly();
248}
249
250void Element::setTabIndexExplicitly(short tabIndex)
251{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100252 ensureElementRareData().setTabIndexExplicitly(tabIndex);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100253}
254
255bool Element::supportsFocus() const
256{
257 return hasRareData() && elementRareData()->tabIndexSetExplicitly();
258}
259
260short Element::tabIndex() const
261{
262 return hasRareData() ? elementRareData()->tabIndex() : 0;
263}
264
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100265bool Element::rendererIsFocusable() const
266{
267 // Elements in canvas fallback content are not rendered, but they are allowed to be
268 // focusable as long as their canvas is displayed and visible.
269 if (isInCanvasSubtree()) {
270 const Element* e = this;
271 while (e && !e->hasLocalName(canvasTag))
272 e = e->parentElement();
273 ASSERT(e);
274 return e->renderer() && e->renderer()->style()->visibility() == VISIBLE;
275 }
276
277 // FIXME: These asserts should be in Node::isFocusable, but there are some
Ben Murdoche69819b2013-07-17 14:56:49 +0100278 // callsites like Document::setFocusedElement that would currently fail on
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100279 // them. See crbug.com/251163
280 if (renderer()) {
281 ASSERT(!renderer()->needsLayout());
282 } else {
283 // We can't just use needsStyleRecalc() because if the node is in a
284 // display:none tree it might say it needs style recalc but the whole
285 // document is actually up to date.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100286 ASSERT(!document().childNeedsStyleRecalc());
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100287 }
288
289 // FIXME: Even if we are not visible, we might have a child that is visible.
290 // Hyatt wants to fix that some day with a "has visible content" flag or the like.
291 if (!renderer() || renderer()->style()->visibility() != VISIBLE)
292 return false;
293
294 return true;
295}
296
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100297DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, blur);
298DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, error);
299DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, focus);
300DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, load);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100301DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, scroll);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100302
303PassRefPtr<Node> Element::cloneNode(bool deep)
304{
305 return deep ? cloneElementWithChildren() : cloneElementWithoutChildren();
306}
307
308PassRefPtr<Element> Element::cloneElementWithChildren()
309{
310 RefPtr<Element> clone = cloneElementWithoutChildren();
311 cloneChildNodes(clone.get());
312 return clone.release();
313}
314
315PassRefPtr<Element> Element::cloneElementWithoutChildren()
316{
317 RefPtr<Element> clone = cloneElementWithoutAttributesAndChildren();
318 // This will catch HTML elements in the wrong namespace that are not correctly copied.
319 // This is a sanity check as HTML overloads some of the DOM methods.
320 ASSERT(isHTMLElement() == clone->isHTMLElement());
321
322 clone->cloneDataFromElement(*this);
323 return clone.release();
324}
325
326PassRefPtr<Element> Element::cloneElementWithoutAttributesAndChildren()
327{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100328 return document().createElement(tagQName(), false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100329}
330
331PassRefPtr<Attr> Element::detachAttribute(size_t index)
332{
333 ASSERT(elementData());
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100334 const Attribute* attribute = elementData()->attributeItem(index);
335 RefPtr<Attr> attrNode = attrIfExists(attribute->name());
336 if (attrNode)
337 detachAttrNodeAtIndex(attrNode.get(), index);
338 else {
339 attrNode = Attr::create(document(), attribute->name(), attribute->value());
340 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
341 }
342 return attrNode.release();
343}
344
345void Element::detachAttrNodeAtIndex(Attr* attr, size_t index)
346{
347 ASSERT(attr);
348 ASSERT(elementData());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100349
350 const Attribute* attribute = elementData()->attributeItem(index);
351 ASSERT(attribute);
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100352 ASSERT(attribute->name() == attr->qualifiedName());
353 detachAttrNodeFromElementWithValue(attr, attribute->value());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100354 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100355}
356
357void Element::removeAttribute(const QualifiedName& name)
358{
359 if (!elementData())
360 return;
361
362 size_t index = elementData()->getAttributeItemIndex(name);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100363 if (index == kNotFound)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100364 return;
365
366 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
367}
368
369void Element::setBooleanAttribute(const QualifiedName& name, bool value)
370{
371 if (value)
372 setAttribute(name, emptyAtom);
373 else
374 removeAttribute(name);
375}
376
377NamedNodeMap* Element::attributes() const
378{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100379 ElementRareData& rareData = const_cast<Element*>(this)->ensureElementRareData();
380 if (NamedNodeMap* attributeMap = rareData.attributeMap())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100381 return attributeMap;
382
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100383 rareData.setAttributeMap(NamedNodeMap::create(const_cast<Element*>(this)));
384 return rareData.attributeMap();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100385}
386
Ben Murdoch83750172013-07-24 10:36:59 +0100387ActiveAnimations* Element::activeAnimations() const
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100388{
Ben Murdoch83750172013-07-24 10:36:59 +0100389 if (hasActiveAnimations())
390 return elementRareData()->activeAnimations();
391 return 0;
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100392}
393
Ben Murdoch83750172013-07-24 10:36:59 +0100394ActiveAnimations* Element::ensureActiveAnimations()
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100395{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100396 ElementRareData& rareData = ensureElementRareData();
397 if (!rareData.activeAnimations())
398 rareData.setActiveAnimations(adoptPtr(new ActiveAnimations()));
399 return rareData.activeAnimations();
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100400}
401
402bool Element::hasActiveAnimations() const
403{
Ben Murdoch83750172013-07-24 10:36:59 +0100404 if (!RuntimeEnabledFeatures::webAnimationsEnabled())
405 return false;
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100406
Ben Murdoch83750172013-07-24 10:36:59 +0100407 if (!hasRareData())
408 return false;
409
410 ActiveAnimations* activeAnimations = elementRareData()->activeAnimations();
411 return activeAnimations && !activeAnimations->isEmpty();
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100412}
413
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100414Node::NodeType Element::nodeType() const
415{
416 return ELEMENT_NODE;
417}
418
419bool Element::hasAttribute(const QualifiedName& name) const
420{
421 return hasAttributeNS(name.namespaceURI(), name.localName());
422}
423
424void Element::synchronizeAllAttributes() const
425{
426 if (!elementData())
427 return;
428 if (elementData()->m_styleAttributeIsDirty) {
429 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100430 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100431 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100432 if (elementData()->m_animatedSVGAttributesAreDirty) {
433 ASSERT(isSVGElement());
434 toSVGElement(this)->synchronizeAnimatedSVGAttribute(anyQName());
435 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100436}
437
438inline void Element::synchronizeAttribute(const QualifiedName& name) const
439{
440 if (!elementData())
441 return;
442 if (UNLIKELY(name == styleAttr && elementData()->m_styleAttributeIsDirty)) {
443 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100444 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100445 return;
446 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100447 if (UNLIKELY(elementData()->m_animatedSVGAttributesAreDirty)) {
448 ASSERT(isSVGElement());
449 toSVGElement(this)->synchronizeAnimatedSVGAttribute(name);
450 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100451}
452
453inline void Element::synchronizeAttribute(const AtomicString& localName) const
454{
455 // This version of synchronizeAttribute() is streamlined for the case where you don't have a full QualifiedName,
456 // e.g when called from DOM API.
457 if (!elementData())
458 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100459 if (elementData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(localName, styleAttr.localName(), shouldIgnoreAttributeCase())) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100460 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100461 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100462 return;
463 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100464 if (elementData()->m_animatedSVGAttributesAreDirty) {
465 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
466 ASSERT(isSVGElement());
467 static_cast<const SVGElement*>(this)->synchronizeAnimatedSVGAttribute(QualifiedName(nullAtom, localName, nullAtom));
468 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100469}
470
471const AtomicString& Element::getAttribute(const QualifiedName& name) const
472{
473 if (!elementData())
474 return nullAtom;
475 synchronizeAttribute(name);
476 if (const Attribute* attribute = getAttributeItem(name))
477 return attribute->value();
478 return nullAtom;
479}
480
Ben Murdoch591b9582013-07-10 11:41:44 +0100481void Element::scrollIntoView(bool alignToTop)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100482{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100483 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100484
485 if (!renderer())
486 return;
487
488 LayoutRect bounds = boundingBox();
489 // Align to the top / bottom and to the closest edge.
490 if (alignToTop)
491 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
492 else
493 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
494}
495
496void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
497{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100498 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100499
500 if (!renderer())
501 return;
502
503 LayoutRect bounds = boundingBox();
504 if (centerIfNeeded)
505 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
506 else
507 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
508}
509
510void Element::scrollByUnits(int units, ScrollGranularity granularity)
511{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100512 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100513
514 if (!renderer())
515 return;
516
517 if (!renderer()->hasOverflowClip())
518 return;
519
520 ScrollDirection direction = ScrollDown;
521 if (units < 0) {
522 direction = ScrollUp;
523 units = -units;
524 }
525 Node* stopNode = this;
526 toRenderBox(renderer())->scroll(direction, granularity, units, &stopNode);
527}
528
529void Element::scrollByLines(int lines)
530{
531 scrollByUnits(lines, ScrollByLine);
532}
533
534void Element::scrollByPages(int pages)
535{
536 scrollByUnits(pages, ScrollByPage);
537}
538
539static float localZoomForRenderer(RenderObject* renderer)
540{
541 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
542 // other out, but the alternative is that we'd have to crawl up the whole render tree every
543 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
544 float zoomFactor = 1;
545 if (renderer->style()->effectiveZoom() != 1) {
546 // Need to find the nearest enclosing RenderObject that set up
547 // a differing zoom, and then we divide our result by it to eliminate the zoom.
548 RenderObject* prev = renderer;
549 for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) {
550 if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) {
551 zoomFactor = prev->style()->zoom();
552 break;
553 }
554 prev = curr;
555 }
556 if (prev->isRenderView())
557 zoomFactor = prev->style()->zoom();
558 }
559 return zoomFactor;
560}
561
562static int adjustForLocalZoom(LayoutUnit value, RenderObject* renderer)
563{
564 float zoomFactor = localZoomForRenderer(renderer);
565 if (zoomFactor == 1)
566 return value;
567 return lroundf(value / zoomFactor);
568}
569
570int Element::offsetLeft()
571{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100572 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100573 if (RenderBoxModelObject* renderer = renderBoxModelObject())
574 return adjustForLocalZoom(renderer->pixelSnappedOffsetLeft(), renderer);
575 return 0;
576}
577
578int Element::offsetTop()
579{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100580 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100581 if (RenderBoxModelObject* renderer = renderBoxModelObject())
582 return adjustForLocalZoom(renderer->pixelSnappedOffsetTop(), renderer);
583 return 0;
584}
585
586int Element::offsetWidth()
587{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100588 document().updateStyleForNodeIfNeeded(this);
Ben Murdoch591b9582013-07-10 11:41:44 +0100589
590 if (RenderBox* renderer = renderBox()) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100591 if (renderer->canDetermineWidthWithoutLayout())
Ben Murdoch591b9582013-07-10 11:41:44 +0100592 return adjustLayoutUnitForAbsoluteZoom(renderer->fixedOffsetWidth(), renderer).round();
593 }
594
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100595 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100596 if (RenderBoxModelObject* renderer = renderBoxModelObject())
597 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetWidth(), renderer).round();
598 return 0;
599}
600
601int Element::offsetHeight()
602{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100603 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100604 if (RenderBoxModelObject* renderer = renderBoxModelObject())
605 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetHeight(), renderer).round();
606 return 0;
607}
608
609Element* Element::bindingsOffsetParent()
610{
611 Element* element = offsetParent();
612 if (!element || !element->isInShadowTree())
613 return element;
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100614 return element->containingShadowRoot()->shouldExposeToBindings() ? element : 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100615}
616
617Element* Element::offsetParent()
618{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100619 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100620 if (RenderObject* renderer = this->renderer())
621 return renderer->offsetParent();
622 return 0;
623}
624
625int Element::clientLeft()
626{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100627 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100628
629 if (RenderBox* renderer = renderBox())
630 return adjustForAbsoluteZoom(roundToInt(renderer->clientLeft()), renderer);
631 return 0;
632}
633
634int Element::clientTop()
635{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100636 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100637
638 if (RenderBox* renderer = renderBox())
639 return adjustForAbsoluteZoom(roundToInt(renderer->clientTop()), renderer);
640 return 0;
641}
642
643int Element::clientWidth()
644{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100645 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100646
647 // When in strict mode, clientWidth for the document element should return the width of the containing frame.
648 // 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 +0100649 bool inQuirksMode = document().inQuirksMode();
650 if ((!inQuirksMode && document().documentElement() == this)
651 || (inQuirksMode && isHTMLElement() && document().body() == this)) {
652 if (FrameView* view = document().view()) {
653 if (RenderView* renderView = document().renderView())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100654 return adjustForAbsoluteZoom(view->layoutSize().width(), renderView);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100655 }
656 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100657
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100658 if (RenderBox* renderer = renderBox())
659 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientWidth(), renderer).round();
660 return 0;
661}
662
663int Element::clientHeight()
664{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100665 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100666
667 // When in strict mode, clientHeight for the document element should return the height of the containing frame.
668 // 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 +0100669 bool inQuirksMode = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100670
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100671 if ((!inQuirksMode && document().documentElement() == this)
672 || (inQuirksMode && isHTMLElement() && document().body() == this)) {
673 if (FrameView* view = document().view()) {
674 if (RenderView* renderView = document().renderView())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100675 return adjustForAbsoluteZoom(view->layoutSize().height(), renderView);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100676 }
677 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100678
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100679 if (RenderBox* renderer = renderBox())
680 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientHeight(), renderer).round();
681 return 0;
682}
683
684int Element::scrollLeft()
685{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100686 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100687
688 if (document().documentElement() == this) {
689 if (document().inQuirksMode())
690 return 0;
691
692 if (FrameView* view = document().view()) {
693 if (RenderView* renderView = document().renderView())
694 return adjustForAbsoluteZoom(view->scrollX(), renderView);
695 }
696 }
697
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100698 if (RenderBox* rend = renderBox())
699 return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
700 return 0;
701}
702
703int Element::scrollTop()
704{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100705 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100706
707 if (document().documentElement() == this) {
708 if (document().inQuirksMode())
709 return 0;
710
711 if (FrameView* view = document().view()) {
712 if (RenderView* renderView = document().renderView())
713 return adjustForAbsoluteZoom(view->scrollY(), renderView);
714 }
715 }
716
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100717 if (RenderBox* rend = renderBox())
718 return adjustForAbsoluteZoom(rend->scrollTop(), rend);
719 return 0;
720}
721
722void Element::setScrollLeft(int newLeft)
723{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100724 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100725
726 if (document().documentElement() == this) {
727 if (document().inQuirksMode())
728 return;
729
730 Frame* frame = document().frame();
731 if (!frame)
732 return;
733 FrameView* view = frame->view();
734 if (!view)
735 return;
736
737 // WHATWG spec says [1]: "If the element is the root element invoke scroll()
738 // with x as first argument and zero as second". Blink intentionally matches
739 // other engine's behaviors here, instead, where the 'y' scroll position is
740 // preversed. See [2].
741 // [1] http://dev.w3.org/csswg/cssom-view/#dom-element-scrollleft
742 // [2] https://www.w3.org/Bugs/Public/show_bug.cgi?id=23448
743 view->setScrollPosition(IntPoint(static_cast<int>(newLeft * frame->pageZoomFactor()), view->scrollY()));
744 }
745
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100746 if (RenderBox* rend = renderBox())
747 rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
748}
749
750void Element::setScrollTop(int newTop)
751{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100752 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100753
754 if (document().documentElement() == this) {
755 if (document().inQuirksMode())
756 return;
757
758 Frame* frame = document().frame();
759 if (!frame)
760 return;
761 FrameView* view = frame->view();
762 if (!view)
763 return;
764
765 // WHATWG spec says [1]: "If the element is the root element invoke scroll()
766 // with zero as first argument and y as second". Blink intentionally
767 // matches other engine's behaviors here, instead, where the 'x' scroll
768 // position is preversed. See [2].
769 // [1] http://dev.w3.org/csswg/cssom-view/#dom-element-scrolltop
770 // [2] https://www.w3.org/Bugs/Public/show_bug.cgi?id=23448
771 view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(newTop * frame->pageZoomFactor())));
772 }
773
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100774 if (RenderBox* rend = renderBox())
775 rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
776}
777
778int Element::scrollWidth()
779{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100780 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100781 if (RenderBox* rend = renderBox())
782 return adjustForAbsoluteZoom(rend->scrollWidth(), rend);
783 return 0;
784}
785
786int Element::scrollHeight()
787{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100788 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100789 if (RenderBox* rend = renderBox())
790 return adjustForAbsoluteZoom(rend->scrollHeight(), rend);
791 return 0;
792}
793
794IntRect Element::boundsInRootViewSpace()
795{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100796 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100797
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100798 FrameView* view = document().view();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100799 if (!view)
800 return IntRect();
801
802 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100803 if (isSVGElement() && renderer()) {
804 // Get the bounding rectangle from the SVG model.
805 SVGElement* svgElement = toSVGElement(this);
806 FloatRect localRect;
807 if (svgElement->getBoundingBox(localRect))
808 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100809 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100810 // Get the bounding rectangle from the box model.
811 if (renderBoxModelObject())
812 renderBoxModelObject()->absoluteQuads(quads);
813 }
814
815 if (quads.isEmpty())
816 return IntRect();
817
818 IntRect result = quads[0].enclosingBoundingBox();
819 for (size_t i = 1; i < quads.size(); ++i)
820 result.unite(quads[i].enclosingBoundingBox());
821
822 result = view->contentsToRootView(result);
823 return result;
824}
825
826PassRefPtr<ClientRectList> Element::getClientRects()
827{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100828 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100829
830 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject();
831 if (!renderBoxModelObject)
832 return ClientRectList::create();
833
834 // FIXME: Handle SVG elements.
835 // FIXME: Handle table/inline-table with a caption.
836
837 Vector<FloatQuad> quads;
838 renderBoxModelObject->absoluteQuads(quads);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100839 document().adjustFloatQuadsForScrollAndAbsoluteZoom(quads, renderBoxModelObject);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100840 return ClientRectList::create(quads);
841}
842
843PassRefPtr<ClientRect> Element::getBoundingClientRect()
844{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100845 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100846
847 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100848 if (isSVGElement() && renderer() && !renderer()->isSVGRoot()) {
849 // Get the bounding rectangle from the SVG model.
850 SVGElement* svgElement = toSVGElement(this);
851 FloatRect localRect;
852 if (svgElement->getBoundingBox(localRect))
853 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100854 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100855 // Get the bounding rectangle from the box model.
856 if (renderBoxModelObject())
857 renderBoxModelObject()->absoluteQuads(quads);
858 }
859
860 if (quads.isEmpty())
861 return ClientRect::create();
862
863 FloatRect result = quads[0].boundingBox();
864 for (size_t i = 1; i < quads.size(); ++i)
865 result.unite(quads[i].boundingBox());
866
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100867 document().adjustFloatRectForScrollAndAbsoluteZoom(result, renderer());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100868 return ClientRect::create(result);
869}
Ben Murdoch591b9582013-07-10 11:41:44 +0100870
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100871IntRect Element::screenRect() const
872{
873 if (!renderer())
874 return IntRect();
875 // FIXME: this should probably respect transforms
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100876 return document().view()->contentsToScreen(renderer()->absoluteBoundingBoxRectIgnoringTransforms());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100877}
878
879const AtomicString& Element::getAttribute(const AtomicString& localName) const
880{
881 if (!elementData())
882 return nullAtom;
883 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100884 if (const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100885 return attribute->value();
886 return nullAtom;
887}
888
889const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
890{
891 return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
892}
893
Ben Murdochdf957042013-08-06 11:01:27 +0100894void Element::setAttribute(const AtomicString& localName, const AtomicString& value, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100895{
896 if (!Document::isValidName(localName)) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100897 es.throwUninformativeAndGenericDOMException(InvalidCharacterError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100898 return;
899 }
900
901 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100902 const AtomicString& caseAdjustedLocalName = shouldIgnoreAttributeCase() ? localName.lower() : localName;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100903
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100904 size_t index = elementData() ? elementData()->getAttributeItemIndex(caseAdjustedLocalName, false) : kNotFound;
905 const QualifiedName& qName = index != kNotFound ? attributeItem(index)->name() : QualifiedName(nullAtom, caseAdjustedLocalName, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100906 setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute);
907}
908
909void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
910{
911 synchronizeAttribute(name);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100912 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : kNotFound;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100913 setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute);
914}
915
916void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value)
917{
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100918 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : kNotFound;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100919 setAttributeInternal(index, name, value, InSynchronizationOfLazyAttribute);
920}
921
922inline void Element::setAttributeInternal(size_t index, const QualifiedName& name, const AtomicString& newValue, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
923{
924 if (newValue.isNull()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100925 if (index != kNotFound)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100926 removeAttributeInternal(index, inSynchronizationOfLazyAttribute);
927 return;
928 }
929
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100930 if (index == kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100931 addAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute);
932 return;
933 }
934
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100935 QualifiedName existingAttributeName = attributeItem(index)->name();
936
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100937 if (!inSynchronizationOfLazyAttribute)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100938 willModifyAttribute(existingAttributeName, attributeItem(index)->value(), newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100939
940 if (newValue != attributeItem(index)->value()) {
941 // If there is an Attr node hooked to this attribute, the Attr::setValue() call below
942 // will write into the ElementData.
943 // FIXME: Refactor this so it makes some sense.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100944 if (RefPtr<Attr> attrNode = inSynchronizationOfLazyAttribute ? 0 : attrIfExists(existingAttributeName))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100945 attrNode->setValue(newValue);
946 else
947 ensureUniqueElementData()->attributeItem(index)->setValue(newValue);
948 }
949
950 if (!inSynchronizationOfLazyAttribute)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100951 didModifyAttribute(existingAttributeName, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100952}
953
954static inline AtomicString makeIdForStyleResolution(const AtomicString& value, bool inQuirksMode)
955{
956 if (inQuirksMode)
957 return value.lower();
958 return value;
959}
960
Ben Murdoch7757ec22013-07-23 11:17:36 +0100961static bool checkNeedsStyleInvalidationForIdChange(const AtomicString& oldId, const AtomicString& newId, const RuleFeatureSet& features)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100962{
963 ASSERT(newId != oldId);
Ben Murdoch7757ec22013-07-23 11:17:36 +0100964 if (!oldId.isEmpty() && features.hasSelectorForId(oldId))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100965 return true;
Ben Murdoch7757ec22013-07-23 11:17:36 +0100966 if (!newId.isEmpty() && features.hasSelectorForId(newId))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100967 return true;
968 return false;
969}
970
Ben Murdoch591b9582013-07-10 11:41:44 +0100971void Element::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100972{
973 if (ElementShadow* parentElementShadow = shadowOfParentForDistribution(this)) {
974 if (shouldInvalidateDistributionWhenAttributeChanged(parentElementShadow, name, newValue))
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100975 parentElementShadow->setNeedsDistributionRecalc();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100976 }
977
978 parseAttribute(name, newValue);
979
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100980 document().incDOMTreeVersion();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100981
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100982 StyleResolver* styleResolver = document().styleResolverIfExists();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100983 bool testShouldInvalidateStyle = confusingAndOftenMisusedAttached() && styleResolver && styleChangeType() < SubtreeStyleChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100984 bool shouldInvalidateStyle = false;
985
Ben Murdoch591b9582013-07-10 11:41:44 +0100986 if (isStyledElement() && name == styleAttr) {
987 styleAttributeChanged(newValue, reason);
988 } else if (isStyledElement() && isPresentationAttribute(name)) {
989 elementData()->m_presentationAttributeStyleIsDirty = true;
Ben Murdoche69819b2013-07-17 14:56:49 +0100990 setNeedsStyleRecalc(LocalStyleChange);
Ben Murdoch591b9582013-07-10 11:41:44 +0100991 }
992
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100993 if (isIdAttributeName(name)) {
994 AtomicString oldId = elementData()->idForStyleResolution();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100995 AtomicString newId = makeIdForStyleResolution(newValue, document().inQuirksMode());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100996 if (newId != oldId) {
997 elementData()->setIdForStyleResolution(newId);
Ben Murdoch7757ec22013-07-23 11:17:36 +0100998 shouldInvalidateStyle = testShouldInvalidateStyle && checkNeedsStyleInvalidationForIdChange(oldId, newId, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100999 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001000 } else if (name == classAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001001 classAttributeChanged(newValue);
Ben Murdoch591b9582013-07-10 11:41:44 +01001002 } else if (name == HTMLNames::nameAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001003 setHasName(!newValue.isNull());
Ben Murdoch591b9582013-07-10 11:41:44 +01001004 } else if (name == HTMLNames::pseudoAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001005 shouldInvalidateStyle |= testShouldInvalidateStyle && isInShadowTree();
Ben Murdoch591b9582013-07-10 11:41:44 +01001006 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001007
1008 invalidateNodeListCachesInAncestors(&name, this);
1009
1010 // If there is currently no StyleResolver, we can't be sure that this attribute change won't affect style.
1011 shouldInvalidateStyle |= !styleResolver;
1012
1013 if (shouldInvalidateStyle)
1014 setNeedsStyleRecalc();
1015
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001016 if (AXObjectCache* cache = document().existingAXObjectCache())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001017 cache->handleAttributeChanged(name, this);
1018}
1019
1020inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
1021{
Ben Murdoche69819b2013-07-17 14:56:49 +01001022 if (name == isAttr)
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001023 CustomElementRegistrationContext::setTypeExtension(this, newValue, reason == ModifiedDirectly ? CustomElementRegistrationContext::CreatedByParser : CustomElementRegistrationContext::NotCreatedByParser);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001024 attributeChanged(name, newValue, reason);
1025}
1026
1027template <typename CharacterType>
1028static inline bool classStringHasClassName(const CharacterType* characters, unsigned length)
1029{
1030 ASSERT(length > 0);
1031
1032 unsigned i = 0;
1033 do {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001034 if (isNotHTMLSpace<CharacterType>(characters[i]))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001035 break;
1036 ++i;
1037 } while (i < length);
1038
1039 return i < length;
1040}
1041
1042static inline bool classStringHasClassName(const AtomicString& newClassString)
1043{
1044 unsigned length = newClassString.length();
1045
1046 if (!length)
1047 return false;
1048
1049 if (newClassString.is8Bit())
1050 return classStringHasClassName(newClassString.characters8(), length);
1051 return classStringHasClassName(newClassString.characters16(), length);
1052}
1053
1054template<typename Checker>
1055static bool checkSelectorForClassChange(const SpaceSplitString& changedClasses, const Checker& checker)
1056{
1057 unsigned changedSize = changedClasses.size();
1058 for (unsigned i = 0; i < changedSize; ++i) {
1059 if (checker.hasSelectorForClass(changedClasses[i]))
1060 return true;
1061 }
1062 return false;
1063}
1064
1065template<typename Checker>
1066static bool checkSelectorForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, const Checker& checker)
1067{
1068 unsigned oldSize = oldClasses.size();
1069 if (!oldSize)
1070 return checkSelectorForClassChange(newClasses, checker);
1071 BitVector remainingClassBits;
1072 remainingClassBits.ensureSize(oldSize);
1073 // Class vectors tend to be very short. This is faster than using a hash table.
1074 unsigned newSize = newClasses.size();
1075 for (unsigned i = 0; i < newSize; ++i) {
1076 for (unsigned j = 0; j < oldSize; ++j) {
1077 if (newClasses[i] == oldClasses[j]) {
1078 remainingClassBits.quickSet(j);
1079 continue;
1080 }
1081 }
1082 if (checker.hasSelectorForClass(newClasses[i]))
1083 return true;
1084 }
1085 for (unsigned i = 0; i < oldSize; ++i) {
1086 // If the bit is not set the the corresponding class has been removed.
1087 if (remainingClassBits.quickGet(i))
1088 continue;
1089 if (checker.hasSelectorForClass(oldClasses[i]))
1090 return true;
1091 }
1092 return false;
1093}
1094
1095void Element::classAttributeChanged(const AtomicString& newClassString)
1096{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001097 StyleResolver* styleResolver = document().styleResolverIfExists();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001098 bool testShouldInvalidateStyle = confusingAndOftenMisusedAttached() && styleResolver && styleChangeType() < SubtreeStyleChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001099 bool shouldInvalidateStyle = false;
1100
1101 if (classStringHasClassName(newClassString)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001102 const bool shouldFoldCase = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001103 const SpaceSplitString oldClasses = elementData()->classNames();
1104 elementData()->setClass(newClassString, shouldFoldCase);
1105 const SpaceSplitString& newClasses = elementData()->classNames();
Ben Murdoch7757ec22013-07-23 11:17:36 +01001106 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, newClasses, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001107 } else {
1108 const SpaceSplitString& oldClasses = elementData()->classNames();
Ben Murdoch7757ec22013-07-23 11:17:36 +01001109 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001110 elementData()->clearClass();
1111 }
1112
1113 if (hasRareData())
1114 elementRareData()->clearClassListValueForQuirksMode();
1115
1116 if (shouldInvalidateStyle)
1117 setNeedsStyleRecalc();
1118}
1119
1120bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
1121{
1122 ASSERT(elementShadow);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001123 const SelectRuleFeatureSet& featureSet = elementShadow->ensureSelectFeatureSet();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001124
1125 if (isIdAttributeName(name)) {
1126 AtomicString oldId = elementData()->idForStyleResolution();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001127 AtomicString newId = makeIdForStyleResolution(newValue, document().inQuirksMode());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001128 if (newId != oldId) {
1129 if (!oldId.isEmpty() && featureSet.hasSelectorForId(oldId))
1130 return true;
1131 if (!newId.isEmpty() && featureSet.hasSelectorForId(newId))
1132 return true;
1133 }
1134 }
1135
1136 if (name == HTMLNames::classAttr) {
1137 const AtomicString& newClassString = newValue;
1138 if (classStringHasClassName(newClassString)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001139 const bool shouldFoldCase = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001140 const SpaceSplitString& oldClasses = elementData()->classNames();
1141 const SpaceSplitString newClasses(newClassString, shouldFoldCase);
1142 if (checkSelectorForClassChange(oldClasses, newClasses, featureSet))
1143 return true;
1144 } else {
1145 const SpaceSplitString& oldClasses = elementData()->classNames();
1146 if (checkSelectorForClassChange(oldClasses, featureSet))
1147 return true;
1148 }
1149 }
1150
1151 return featureSet.hasSelectorForAttribute(name.localName());
1152}
1153
1154// Returns true is the given attribute is an event handler.
1155// We consider an event handler any attribute that begins with "on".
1156// It is a simple solution that has the advantage of not requiring any
1157// code or configuration change if a new event handler is defined.
1158
1159static inline bool isEventHandlerAttribute(const Attribute& attribute)
1160{
1161 return attribute.name().namespaceURI().isNull() && attribute.name().localName().startsWith("on");
1162}
1163
1164bool Element::isJavaScriptURLAttribute(const Attribute& attribute) const
1165{
1166 return isURLAttribute(attribute) && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(attribute.value()));
1167}
1168
1169void Element::stripScriptingAttributes(Vector<Attribute>& attributeVector) const
1170{
1171 size_t destination = 0;
1172 for (size_t source = 0; source < attributeVector.size(); ++source) {
1173 if (isEventHandlerAttribute(attributeVector[source])
1174 || isJavaScriptURLAttribute(attributeVector[source])
1175 || isHTMLContentAttribute(attributeVector[source]))
1176 continue;
1177
1178 if (source != destination)
1179 attributeVector[destination] = attributeVector[source];
1180
1181 ++destination;
1182 }
1183 attributeVector.shrink(destination);
1184}
1185
1186void Element::parserSetAttributes(const Vector<Attribute>& attributeVector)
1187{
1188 ASSERT(!inDocument());
1189 ASSERT(!parentNode());
1190 ASSERT(!m_elementData);
1191
1192 if (attributeVector.isEmpty())
1193 return;
1194
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001195 if (document().sharedObjectPool())
1196 m_elementData = document().sharedObjectPool()->cachedShareableElementDataWithAttributes(attributeVector);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001197 else
1198 m_elementData = ShareableElementData::createWithAttributes(attributeVector);
1199
1200 // Use attributeVector instead of m_elementData because attributeChanged might modify m_elementData.
1201 for (unsigned i = 0; i < attributeVector.size(); ++i)
1202 attributeChangedFromParserOrByCloning(attributeVector[i].name(), attributeVector[i].value(), ModifiedDirectly);
1203}
1204
1205bool Element::hasAttributes() const
1206{
1207 synchronizeAllAttributes();
1208 return elementData() && elementData()->length();
1209}
1210
1211bool Element::hasEquivalentAttributes(const Element* other) const
1212{
1213 synchronizeAllAttributes();
1214 other->synchronizeAllAttributes();
1215 if (elementData() == other->elementData())
1216 return true;
1217 if (elementData())
1218 return elementData()->isEquivalent(other->elementData());
1219 if (other->elementData())
1220 return other->elementData()->isEquivalent(elementData());
1221 return true;
1222}
1223
1224String Element::nodeName() const
1225{
1226 return m_tagName.toString();
1227}
1228
1229String Element::nodeNamePreservingCase() const
1230{
1231 return m_tagName.toString();
1232}
1233
Ben Murdochdf957042013-08-06 11:01:27 +01001234void Element::setPrefix(const AtomicString& prefix, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001235{
Ben Murdochdf957042013-08-06 11:01:27 +01001236 checkSetPrefix(prefix, es);
1237 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001238 return;
1239
1240 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
1241}
1242
1243KURL Element::baseURI() const
1244{
1245 const AtomicString& baseAttribute = getAttribute(baseAttr);
1246 KURL base(KURL(), baseAttribute);
1247 if (!base.protocol().isEmpty())
1248 return base;
1249
1250 ContainerNode* parent = parentNode();
1251 if (!parent)
1252 return base;
1253
1254 const KURL& parentBase = parent->baseURI();
1255 if (parentBase.isNull())
1256 return base;
1257
1258 return KURL(parentBase, baseAttribute);
1259}
1260
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001261const AtomicString Element::imageSourceURL() const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001262{
1263 return getAttribute(srcAttr);
1264}
1265
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001266bool Element::rendererIsNeeded(const RenderStyle& style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001267{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001268 return style.display() != NONE;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001269}
1270
Ben Murdoch591b9582013-07-10 11:41:44 +01001271RenderObject* Element::createRenderer(RenderStyle* style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001272{
1273 return RenderObject::createObject(this, style);
1274}
1275
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001276Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertionPoint)
1277{
1278 // need to do superclass processing first so inDocument() is true
1279 // by the time we reach updateId
1280 ContainerNode::insertedInto(insertionPoint);
1281
1282 if (containsFullScreenElement() && parentElement() && !parentElement()->containsFullScreenElement())
1283 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
1284
1285 if (Element* before = pseudoElement(BEFORE))
1286 before->insertedInto(insertionPoint);
1287
1288 if (Element* after = pseudoElement(AFTER))
1289 after->insertedInto(insertionPoint);
1290
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001291 if (Element* backdrop = pseudoElement(BACKDROP))
1292 backdrop->insertedInto(insertionPoint);
1293
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001294 if (!insertionPoint->isInTreeScope())
1295 return InsertionDone;
1296
1297 if (hasRareData())
1298 elementRareData()->clearClassListValueForQuirksMode();
1299
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001300 if (isUpgradedCustomElement() && inDocument())
1301 CustomElement::didEnterDocument(this, document());
1302
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001303 TreeScope& scope = insertionPoint->treeScope();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001304 if (scope != treeScope())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001305 return InsertionDone;
1306
1307 const AtomicString& idValue = getIdAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001308 if (!idValue.isNull())
1309 updateId(scope, nullAtom, idValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001310
1311 const AtomicString& nameValue = getNameAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001312 if (!nameValue.isNull())
1313 updateName(nullAtom, nameValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001314
1315 if (hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001316 if (scope.shouldCacheLabelsByForAttribute())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001317 updateLabel(scope, nullAtom, fastGetAttribute(forAttr));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001318 }
1319
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001320 if (parentElement() && parentElement()->isInCanvasSubtree())
1321 setIsInCanvasSubtree(true);
1322
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001323 return InsertionDone;
1324}
1325
1326void Element::removedFrom(ContainerNode* insertionPoint)
1327{
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001328 bool wasInDocument = insertionPoint->inDocument();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001329
1330 if (Element* before = pseudoElement(BEFORE))
1331 before->removedFrom(insertionPoint);
1332
1333 if (Element* after = pseudoElement(AFTER))
1334 after->removedFrom(insertionPoint);
1335
Ben Murdoche69819b2013-07-17 14:56:49 +01001336 if (Element* backdrop = pseudoElement(BACKDROP))
1337 backdrop->removedFrom(insertionPoint);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001338 document().removeFromTopLayer(this);
Ben Murdoche69819b2013-07-17 14:56:49 +01001339
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001340 if (containsFullScreenElement())
1341 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
1342
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001343 if (document().page())
1344 document().page()->pointerLockController().elementRemoved(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001345
1346 setSavedLayerScrollOffset(IntSize());
1347
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001348 if (insertionPoint->isInTreeScope() && treeScope() == document()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001349 const AtomicString& idValue = getIdAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001350 if (!idValue.isNull())
1351 updateId(insertionPoint->treeScope(), idValue, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001352
1353 const AtomicString& nameValue = getNameAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001354 if (!nameValue.isNull())
1355 updateName(nameValue, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001356
1357 if (hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001358 TreeScope& treeScope = insertionPoint->treeScope();
1359 if (treeScope.shouldCacheLabelsByForAttribute())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001360 updateLabel(treeScope, fastGetAttribute(forAttr), nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001361 }
1362 }
1363
1364 ContainerNode::removedFrom(insertionPoint);
Ben Murdoche69819b2013-07-17 14:56:49 +01001365 if (wasInDocument) {
1366 if (hasPendingResources())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001367 document().accessSVGExtensions()->removeElementFromPendingResources(this);
Ben Murdoche69819b2013-07-17 14:56:49 +01001368
Ben Murdoch83750172013-07-24 10:36:59 +01001369 if (isUpgradedCustomElement())
Ben Murdochfff88842013-07-30 15:20:09 +01001370 CustomElement::didLeaveDocument(this, insertionPoint->document());
Ben Murdoche69819b2013-07-17 14:56:49 +01001371 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001372
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001373 if (hasRareData())
1374 elementRareData()->setIsInCanvasSubtree(false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001375}
1376
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001377void Element::attach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001378{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001379 ASSERT(document().inStyleRecalc());
1380
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001381 StyleResolverParentPusher parentPusher(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001382
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001383 // We've already been through detach when doing a lazyAttach, but we might
1384 // need to clear any state that's been added since then.
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001385 if (hasRareData() && styleChangeType() == NeedsReattachStyleChange) {
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001386 ElementRareData* data = elementRareData();
1387 data->clearComputedStyle();
1388 data->resetDynamicRestyleObservations();
1389 if (!context.resolvedStyle)
1390 data->resetStyleState();
1391 }
1392
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001393 NodeRenderingContext(this, context.resolvedStyle).createRendererForElementIfNeeded();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001394
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001395 if (RenderStyle* style = renderStyle())
1396 updateCallbackSelectors(0, style);
1397
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001398 createPseudoElementIfNeeded(BEFORE);
1399
1400 // When a shadow root exists, it does the work of attaching the children.
1401 if (ElementShadow* shadow = this->shadow()) {
1402 parentPusher.push();
Ben Murdoch591b9582013-07-10 11:41:44 +01001403 shadow->attach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001404 } else if (firstChild())
1405 parentPusher.push();
1406
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001407 ContainerNode::attach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001408
1409 createPseudoElementIfNeeded(AFTER);
Ben Murdoche69819b2013-07-17 14:56:49 +01001410 createPseudoElementIfNeeded(BACKDROP);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001411
Ben Murdoch591b9582013-07-10 11:41:44 +01001412 if (hasRareData()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001413 ElementRareData* data = elementRareData();
1414 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001415 if (isFocusable() && document().focusedElement() == this)
1416 document().updateFocusAppearanceSoon(false /* don't restore selection */);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001417 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1418 }
1419 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001420
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001421 InspectorInstrumentation::didRecalculateStyleForElement(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001422}
1423
1424void Element::unregisterNamedFlowContentNode()
1425{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001426 if (RuntimeEnabledFeatures::cssRegionsEnabled() && inNamedFlow() && document().renderView())
1427 document().renderView()->flowThreadController()->unregisterNamedFlowContentNode(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001428}
1429
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001430void Element::detach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001431{
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001432 RenderWidget::UpdateSuspendScope suspendWidgetHierarchyUpdates;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001433 unregisterNamedFlowContentNode();
1434 cancelFocusAppearanceUpdate();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001435 if (RenderStyle* style = renderStyle()) {
1436 if (!style->callbackSelectors().isEmpty())
1437 updateCallbackSelectors(style, 0);
1438 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001439 if (hasRareData()) {
1440 ElementRareData* data = elementRareData();
1441 data->setPseudoElement(BEFORE, 0);
1442 data->setPseudoElement(AFTER, 0);
Ben Murdoche69819b2013-07-17 14:56:49 +01001443 data->setPseudoElement(BACKDROP, 0);
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001444 data->clearComputedStyle();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001445 data->resetDynamicRestyleObservations();
Ben Murdoch591b9582013-07-10 11:41:44 +01001446 data->setIsInsideRegion(false);
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001447
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001448 // Only clear the style state if we're not going to reuse the style from recalcStyle.
1449 if (!context.resolvedStyle)
1450 data->resetStyleState();
1451
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001452 if (RuntimeEnabledFeatures::webAnimationsCSSEnabled() && !context.performingReattach) {
1453 if (ActiveAnimations* activeAnimations = data->activeAnimations())
1454 activeAnimations->cssAnimations()->cancel();
1455 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001456 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001457 if (ElementShadow* shadow = this->shadow())
1458 shadow->detach(context);
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001459 ContainerNode::detach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001460}
1461
1462bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle)
1463{
1464 ASSERT(currentStyle == renderStyle());
1465 ASSERT(renderer());
1466
1467 if (!currentStyle)
1468 return false;
1469
1470 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles();
1471 if (!pseudoStyleCache)
1472 return false;
1473
1474 size_t cacheSize = pseudoStyleCache->size();
1475 for (size_t i = 0; i < cacheSize; ++i) {
1476 RefPtr<RenderStyle> newPseudoStyle;
1477 PseudoId pseudoId = pseudoStyleCache->at(i)->styleType();
1478 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
1479 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle);
1480 else
1481 newPseudoStyle = renderer()->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
1482 if (!newPseudoStyle)
1483 return true;
1484 if (*newPseudoStyle != *pseudoStyleCache->at(i)) {
1485 if (pseudoId < FIRST_INTERNAL_PSEUDOID)
1486 newStyle->setHasPseudoStyle(pseudoId);
1487 newStyle->addCachedPseudoStyle(newPseudoStyle);
1488 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
1489 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
1490 // is needed, but for now just assume a layout will be required. The diff code
1491 // in RenderObject::setStyle would need to be factored out so that it could be reused.
1492 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
1493 }
1494 return true;
1495 }
1496 }
1497 return false;
1498}
1499
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001500PassRefPtr<RenderStyle> Element::styleForRenderer()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001501{
1502 if (hasCustomStyleCallbacks()) {
1503 if (RefPtr<RenderStyle> style = customStyleForRenderer())
1504 return style.release();
1505 }
1506
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001507 return originalStyleForRenderer();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001508}
1509
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001510PassRefPtr<RenderStyle> Element::originalStyleForRenderer()
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001511{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001512 return document().styleResolver()->styleForElement(this);
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001513}
1514
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001515bool Element::recalcStyle(StyleRecalcChange change)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001516{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001517 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001518
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001519 if (hasCustomStyleCallbacks())
1520 willRecalcStyle(change);
1521
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001522 if (hasRareData() && (change > NoChange || needsStyleRecalc())) {
1523 ElementRareData* data = elementRareData();
1524 data->resetStyleState();
1525 data->clearComputedStyle();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001526 }
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001527
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001528 // Active InsertionPoints have no renderers so they never need to go through a recalc.
1529 if ((change >= Inherit || needsStyleRecalc()) && parentRenderStyle() && !isActiveInsertionPoint(this))
1530 change = recalcOwnStyle(change);
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001531
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001532 // If we reattached we don't need to recalc the style of our descendants anymore.
1533 if (change < Reattach)
1534 recalcChildStyle(change);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001535
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001536 clearNeedsStyleRecalc();
1537 clearChildNeedsStyleRecalc();
Ben Murdoch591b9582013-07-10 11:41:44 +01001538
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001539 if (hasCustomStyleCallbacks())
1540 didRecalcStyle(change);
1541
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001542 return change == Reattach;
1543}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001544
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001545static bool callbackSelectorsDiffer(RenderStyle* style1, RenderStyle* style2)
1546{
1547 const Vector<String> emptyVector;
1548 const Vector<String>& callbackSelectors1 = style1 ? style1->callbackSelectors() : emptyVector;
1549 const Vector<String>& callbackSelectors2 = style2 ? style2->callbackSelectors() : emptyVector;
1550 if (callbackSelectors1.isEmpty() && callbackSelectors2.isEmpty()) {
1551 // Help the inliner with this common case.
1552 return false;
1553 }
1554 return callbackSelectors1 != callbackSelectors2;
1555}
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)c0e19a62013-08-30 15:15:11 +01001560
1561 CSSAnimationUpdateScope cssAnimationUpdateScope(this);
1562 RefPtr<RenderStyle> oldStyle = renderStyle();
1563 RefPtr<RenderStyle> newStyle = styleForRenderer();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001564 StyleRecalcChange localChange = RenderStyle::compare(oldStyle.get(), newStyle.get());
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001565
1566 if (localChange == Reattach) {
1567 AttachContext reattachContext;
1568 reattachContext.resolvedStyle = newStyle.get();
1569 reattach(reattachContext);
1570 return Reattach;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001571 }
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001572
1573 InspectorInstrumentation::didRecalculateStyleForElement(this);
1574
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001575 if (localChange != NoChange && callbackSelectorsDiffer(oldStyle.get(), newStyle.get()))
1576 updateCallbackSelectors(oldStyle.get(), newStyle.get());
1577
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001578 if (RenderObject* renderer = this->renderer()) {
1579 if (localChange != NoChange || pseudoStyleCacheIsInvalid(oldStyle.get(), newStyle.get()) || (change == Force && renderer->requiresForcedStyleRecalcPropagation()) || shouldNotifyRendererWithIdenticalStyles()) {
1580 renderer->setAnimatableStyle(newStyle.get());
1581 } else if (needsStyleRecalc()) {
1582 // Although no change occurred, we use the new style so that the cousin style sharing code won't get
1583 // fooled into believing this style is the same.
1584 renderer->setStyleInternal(newStyle.get());
1585 }
1586 }
1587
1588 // 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
1589 // all the way down the tree. This is simpler than having to maintain a cache of objects (and such font size changes should be rare anyway).
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01001590 if (document().styleEngine()->usesRemUnits() && document().documentElement() == this && oldStyle && newStyle && oldStyle->fontSize() != newStyle->fontSize()) {
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001591 // Cached RenderStyles may depend on the re units.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001592 document().styleResolver()->invalidateMatchedPropertiesCache();
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001593 return Force;
1594 }
1595
1596 if (styleChangeType() >= SubtreeStyleChange)
1597 return Force;
1598
1599 return max(localChange, change);
1600}
1601
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001602void Element::recalcChildStyle(StyleRecalcChange change)
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001603{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001604 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001605
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001606 StyleResolverParentPusher parentPusher(this);
1607
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001608 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
1609 if (shouldRecalcStyle(change, root)) {
1610 parentPusher.push();
1611 root->recalcStyle(change);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001612 }
1613 }
1614
1615 if (shouldRecalcStyle(change, this))
1616 updatePseudoElement(BEFORE, change);
1617
1618 // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
1619 // For now we will just worry about the common case, since it's a lot trickier to get the second case right
1620 // without doing way too much re-resolution.
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001621 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
1622 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001623 bool forceCheckOfNextElementSibling = false;
1624 bool forceCheckOfAnyElementSibling = false;
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001625 if (hasDirectAdjacentRules || hasIndirectAdjacentRules) {
1626 for (Node* child = firstChild(); child; child = child->nextSibling()) {
1627 if (!child->isElementNode())
1628 continue;
Ben Murdoche69819b2013-07-17 14:56:49 +01001629 Element* element = toElement(child);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001630 bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() >= SubtreeStyleChange;
Ben Murdoche69819b2013-07-17 14:56:49 +01001631 if (forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling)
1632 element->setNeedsStyleRecalc();
Ben Murdoche69819b2013-07-17 14:56:49 +01001633 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
1634 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001635 }
1636 }
1637 // This loop is deliberately backwards because we use insertBefore in the rendering tree, and want to avoid
1638 // a potentially n^2 loop to find the insertion point while resolving style. Having us start from the last
1639 // child and work our way back means in the common case, we'll find the insertion point in O(1) time.
1640 // Reversing this loop can lead to non-deterministic results in our code to optimize out empty whitespace
1641 // RenderTexts. We try to put off recalcing their style until the end to avoid this issue.
1642 // See crbug.com/288225
1643 WhitespaceChildList whitespaceChildList(change);
1644 for (Node* child = lastChild(); child; child = child->previousSibling()) {
1645 if (child->isTextNode()) {
1646 Text* textChild = toText(child);
1647 // FIXME: This check is expensive and may negate the performance gained by the optimization of
1648 // avoiding whitespace renderers.
1649 if (textChild->containsOnlyWhitespace())
1650 whitespaceChildList.append(textChild);
1651 else
1652 textChild->recalcTextStyle(change);
1653 } else if (child->isElementNode()) {
1654 Element* element = toElement(child);
Ben Murdoche69819b2013-07-17 14:56:49 +01001655 if (shouldRecalcStyle(change, element)) {
1656 parentPusher.push();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001657 element->recalcStyle(change);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001658 } else if (element->supportsStyleSharing()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001659 document().styleResolver()->addToStyleSharingList(element);
Ben Murdoche69819b2013-07-17 14:56:49 +01001660 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001661 }
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001662 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001663
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001664 whitespaceChildList.recalcStyle();
1665
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001666 if (shouldRecalcStyle(change, this)) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001667 updatePseudoElement(AFTER, change);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001668 updatePseudoElement(BACKDROP, change);
1669 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001670}
1671
1672ElementShadow* Element::shadow() const
1673{
1674 return hasRareData() ? elementRareData()->shadow() : 0;
1675}
1676
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001677ElementShadow& Element::ensureShadow()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001678{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001679 return ensureElementRareData().ensureShadow();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001680}
1681
1682void Element::didAffectSelector(AffectedSelectorMask mask)
1683{
1684 setNeedsStyleRecalc();
1685 if (ElementShadow* elementShadow = shadowOfParentForDistribution(this))
1686 elementShadow->didAffectSelector(mask);
1687}
1688
Ben Murdochdf957042013-08-06 11:01:27 +01001689PassRefPtr<ShadowRoot> Element::createShadowRoot(ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001690{
1691 if (alwaysCreateUserAgentShadowRoot())
1692 ensureUserAgentShadowRoot();
1693
1694 if (RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001695 return ensureShadow().addShadowRoot(this, ShadowRoot::AuthorShadowRoot);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001696
1697 // Since some elements recreates shadow root dynamically, multiple shadow
1698 // subtrees won't work well in that element. Until they are fixed, we disable
1699 // adding author shadow root for them.
1700 if (!areAuthorShadowsAllowed()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001701 es.throwUninformativeAndGenericDOMException(HierarchyRequestError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001702 return 0;
1703 }
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001704 return ensureShadow().addShadowRoot(this, ShadowRoot::AuthorShadowRoot);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001705}
1706
1707ShadowRoot* Element::shadowRoot() const
1708{
1709 ElementShadow* elementShadow = shadow();
1710 if (!elementShadow)
1711 return 0;
1712 ShadowRoot* shadowRoot = elementShadow->youngestShadowRoot();
1713 if (shadowRoot->type() == ShadowRoot::AuthorShadowRoot)
1714 return shadowRoot;
1715 return 0;
1716}
1717
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001718void Element::didAddShadowRoot(ShadowRoot&)
1719{
1720}
1721
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001722ShadowRoot* Element::userAgentShadowRoot() const
1723{
1724 if (ElementShadow* elementShadow = shadow()) {
1725 if (ShadowRoot* shadowRoot = elementShadow->oldestShadowRoot()) {
1726 ASSERT(shadowRoot->type() == ShadowRoot::UserAgentShadowRoot);
1727 return shadowRoot;
1728 }
1729 }
1730
1731 return 0;
1732}
1733
1734ShadowRoot* Element::ensureUserAgentShadowRoot()
1735{
1736 if (ShadowRoot* shadowRoot = userAgentShadowRoot())
1737 return shadowRoot;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001738 ShadowRoot* shadowRoot = ensureShadow().addShadowRoot(this, ShadowRoot::UserAgentShadowRoot);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001739 didAddUserAgentShadowRoot(shadowRoot);
1740 return shadowRoot;
1741}
1742
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001743bool Element::childTypeAllowed(NodeType type) const
1744{
1745 switch (type) {
1746 case ELEMENT_NODE:
1747 case TEXT_NODE:
1748 case COMMENT_NODE:
1749 case PROCESSING_INSTRUCTION_NODE:
1750 case CDATA_SECTION_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001751 return true;
1752 default:
1753 break;
1754 }
1755 return false;
1756}
1757
Ben Murdoch83750172013-07-24 10:36:59 +01001758static void inline checkForEmptyStyleChange(Element* element, RenderStyle* style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001759{
1760 if (!style && !element->styleAffectedByEmpty())
1761 return;
1762
1763 if (!style || (element->styleAffectedByEmpty() && (!style->emptyState() || element->hasChildNodes())))
1764 element->setNeedsStyleRecalc();
1765}
1766
1767static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
1768 Node* beforeChange, Node* afterChange, int childCountDelta)
1769{
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001770 if (!e->confusingAndOftenMisusedAttached() || e->document().hasPendingForcedStyleRecalc() || e->styleChangeType() >= SubtreeStyleChange)
Ben Murdoch83750172013-07-24 10:36:59 +01001771 return;
1772
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001773 // :empty selector.
1774 checkForEmptyStyleChange(e, style);
Ben Murdoch591b9582013-07-10 11:41:44 +01001775
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001776 if (!style || (e->needsStyleRecalc() && e->childrenAffectedByPositionalRules()))
1777 return;
1778
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001779 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
1780 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1781 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
1782 // backward case.
1783 // |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.
1784 // 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 +01001785 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
1786 if ((e->childrenAffectedByForwardPositionalRules() && afterChange) || (e->childrenAffectedByBackwardPositionalRules() && beforeChange)) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001787 e->setNeedsStyleRecalc();
Ben Murdoch83750172013-07-24 10:36:59 +01001788 return;
1789 }
1790
1791 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1792 // In the DOM case, we only need to do something if |afterChange| is not 0.
1793 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
1794 if (e->childrenAffectedByFirstChildRules() && afterChange) {
1795 // Find our new first child.
1796 Node* newFirstChild = e->firstElementChild();
1797 RenderStyle* newFirstChildStyle = newFirstChild ? newFirstChild->renderStyle() : 0;
1798
1799 // Find the first element node following |afterChange|
1800 Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling();
1801 RenderStyle* firstElementAfterInsertionStyle = firstElementAfterInsertion ? firstElementAfterInsertion->renderStyle() : 0;
1802
1803 // This is the insert/append case.
1804 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertionStyle && firstElementAfterInsertionStyle->firstChildState())
1805 firstElementAfterInsertion->setNeedsStyleRecalc();
1806
1807 // We also have to handle node removal.
1808 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChildStyle || !newFirstChildStyle->firstChildState()))
1809 newFirstChild->setNeedsStyleRecalc();
1810 }
1811
1812 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1813 // In the DOM case, we only need to do something if |afterChange| is not 0.
1814 if (e->childrenAffectedByLastChildRules() && beforeChange) {
1815 // Find our new last child.
1816 Node* newLastChild = e->lastElementChild();
1817 RenderStyle* newLastChildStyle = newLastChild ? newLastChild->renderStyle() : 0;
1818
1819 // Find the last element node going backwards from |beforeChange|
1820 Node* lastElementBeforeInsertion = beforeChange->isElementNode() ? beforeChange : beforeChange->previousElementSibling();
1821 RenderStyle* lastElementBeforeInsertionStyle = lastElementBeforeInsertion ? lastElementBeforeInsertion->renderStyle() : 0;
1822
1823 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertionStyle && lastElementBeforeInsertionStyle->lastChildState())
1824 lastElementBeforeInsertion->setNeedsStyleRecalc();
1825
1826 // 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
1827 // to match now.
1828 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChildStyle || !newLastChildStyle->lastChildState()))
1829 newLastChild->setNeedsStyleRecalc();
1830 }
1831
1832 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
1833 // that could be affected by this DOM change.
1834 if (e->childrenAffectedByDirectAdjacentRules() && afterChange) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001835 if (Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling())
Ben Murdoch83750172013-07-24 10:36:59 +01001836 firstElementAfterInsertion->setNeedsStyleRecalc();
1837 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001838}
1839
1840void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
1841{
1842 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
1843 if (changedByParser)
1844 checkForEmptyStyleChange(this, renderStyle());
1845 else
1846 checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
1847
Ben Murdoch83750172013-07-24 10:36:59 +01001848 if (ElementShadow* shadow = this->shadow())
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001849 shadow->setNeedsDistributionRecalc();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001850}
1851
1852void Element::removeAllEventListeners()
1853{
1854 ContainerNode::removeAllEventListeners();
1855 if (ElementShadow* shadow = this->shadow())
1856 shadow->removeAllEventListeners();
1857}
1858
1859void Element::beginParsingChildren()
1860{
1861 clearIsParsingChildrenFinished();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001862}
1863
1864void Element::finishParsingChildren()
1865{
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001866 setIsParsingChildrenFinished();
1867 checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001868 if (isCustomElement())
1869 CustomElement::didFinishParsingChildren(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001870}
1871
1872#ifndef NDEBUG
1873void Element::formatForDebugger(char* buffer, unsigned length) const
1874{
1875 StringBuilder result;
1876 String s;
1877
1878 result.append(nodeName());
1879
1880 s = getIdAttribute();
1881 if (s.length() > 0) {
1882 if (result.length() > 0)
1883 result.appendLiteral("; ");
1884 result.appendLiteral("id=");
1885 result.append(s);
1886 }
1887
1888 s = getAttribute(classAttr);
1889 if (s.length() > 0) {
1890 if (result.length() > 0)
1891 result.appendLiteral("; ");
1892 result.appendLiteral("class=");
1893 result.append(s);
1894 }
1895
1896 strncpy(buffer, result.toString().utf8().data(), length - 1);
1897}
1898#endif
1899
1900const Vector<RefPtr<Attr> >& Element::attrNodeList()
1901{
1902 ASSERT(hasSyntheticAttrChildNodes());
1903 return *attrNodeListForElement(this);
1904}
1905
Ben Murdochdf957042013-08-06 11:01:27 +01001906PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001907{
1908 if (!attrNode) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001909 es.throwUninformativeAndGenericDOMException(TypeMismatchError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001910 return 0;
1911 }
1912
1913 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName());
1914 if (oldAttrNode.get() == attrNode)
1915 return attrNode; // This Attr is already attached to the element.
1916
Ben Murdoche69819b2013-07-17 14:56:49 +01001917 // 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 +01001918 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
1919 if (attrNode->ownerElement()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001920 es.throwUninformativeAndGenericDOMException(InUseAttributeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001921 return 0;
1922 }
1923
1924 synchronizeAllAttributes();
1925 UniqueElementData* elementData = ensureUniqueElementData();
1926
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001927 size_t index = elementData->getAttributeItemIndex(attrNode->qualifiedName(), shouldIgnoreAttributeCase());
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001928 if (index != kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001929 if (oldAttrNode)
1930 detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData->attributeItem(index)->value());
1931 else
1932 oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), elementData->attributeItem(index)->value());
1933 }
1934
1935 setAttributeInternal(index, attrNode->qualifiedName(), attrNode->value(), NotInSynchronizationOfLazyAttribute);
1936
1937 attrNode->attachToElement(this);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001938 treeScope().adoptIfNeeded(attrNode);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001939 ensureAttrNodeListForElement(this).append(attrNode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001940
1941 return oldAttrNode.release();
1942}
1943
Ben Murdochdf957042013-08-06 11:01:27 +01001944PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001945{
Ben Murdochdf957042013-08-06 11:01:27 +01001946 return setAttributeNode(attr, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001947}
1948
Ben Murdochdf957042013-08-06 11:01:27 +01001949PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001950{
1951 if (!attr) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001952 es.throwUninformativeAndGenericDOMException(TypeMismatchError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001953 return 0;
1954 }
1955 if (attr->ownerElement() != this) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001956 es.throwUninformativeAndGenericDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001957 return 0;
1958 }
1959
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001960 ASSERT(document() == attr->document());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001961
1962 synchronizeAttribute(attr->qualifiedName());
1963
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001964 size_t index = elementData()->getAttrIndex(attr);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001965 if (index == kNotFound) {
1966 es.throwUninformativeAndGenericDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001967 return 0;
1968 }
1969
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001970 RefPtr<Attr> guard(attr);
1971 detachAttrNodeAtIndex(attr, index);
1972 return guard.release();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001973}
1974
Ben Murdochdf957042013-08-06 11:01:27 +01001975bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001976{
1977 String prefix, localName;
Ben Murdochdf957042013-08-06 11:01:27 +01001978 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, es))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001979 return false;
Ben Murdochdf957042013-08-06 11:01:27 +01001980 ASSERT(!es.hadException());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001981
1982 QualifiedName qName(prefix, localName, namespaceURI);
1983
1984 if (!Document::hasValidNamespaceForAttributes(qName)) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001985 es.throwUninformativeAndGenericDOMException(NamespaceError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001986 return false;
1987 }
1988
1989 out = qName;
1990 return true;
1991}
1992
Ben Murdochdf957042013-08-06 11:01:27 +01001993void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001994{
1995 QualifiedName parsedName = anyName;
Ben Murdochdf957042013-08-06 11:01:27 +01001996 if (!parseAttributeName(parsedName, namespaceURI, qualifiedName, es))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001997 return;
1998 setAttribute(parsedName, value);
1999}
2000
2001void Element::removeAttributeInternal(size_t index, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
2002{
2003 ASSERT_WITH_SECURITY_IMPLICATION(index < attributeCount());
2004
2005 UniqueElementData* elementData = ensureUniqueElementData();
2006
2007 QualifiedName name = elementData->attributeItem(index)->name();
2008 AtomicString valueBeingRemoved = elementData->attributeItem(index)->value();
2009
2010 if (!inSynchronizationOfLazyAttribute) {
2011 if (!valueBeingRemoved.isNull())
2012 willModifyAttribute(name, valueBeingRemoved, nullAtom);
2013 }
2014
2015 if (RefPtr<Attr> attrNode = attrIfExists(name))
2016 detachAttrNodeFromElementWithValue(attrNode.get(), elementData->attributeItem(index)->value());
2017
2018 elementData->removeAttribute(index);
2019
2020 if (!inSynchronizationOfLazyAttribute)
2021 didRemoveAttribute(name);
2022}
2023
2024void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
2025{
2026 if (!inSynchronizationOfLazyAttribute)
2027 willModifyAttribute(name, nullAtom, value);
2028 ensureUniqueElementData()->addAttribute(name, value);
2029 if (!inSynchronizationOfLazyAttribute)
2030 didAddAttribute(name, value);
2031}
2032
2033void Element::removeAttribute(const AtomicString& name)
2034{
2035 if (!elementData())
2036 return;
2037
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002038 AtomicString localName = shouldIgnoreAttributeCase() ? name.lower() : name;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002039 size_t index = elementData()->getAttributeItemIndex(localName, false);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01002040 if (index == kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002041 if (UNLIKELY(localName == styleAttr) && elementData()->m_styleAttributeIsDirty && isStyledElement())
Ben Murdoch591b9582013-07-10 11:41:44 +01002042 removeAllInlineStyleProperties();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002043 return;
2044 }
2045
2046 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
2047}
2048
2049void Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName)
2050{
2051 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI));
2052}
2053
2054PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& localName)
2055{
2056 if (!elementData())
2057 return 0;
2058 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002059 const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002060 if (!attribute)
2061 return 0;
2062 return ensureAttr(attribute->name());
2063}
2064
2065PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
2066{
2067 if (!elementData())
2068 return 0;
2069 QualifiedName qName(nullAtom, localName, namespaceURI);
2070 synchronizeAttribute(qName);
2071 const Attribute* attribute = elementData()->getAttributeItem(qName);
2072 if (!attribute)
2073 return 0;
2074 return ensureAttr(attribute->name());
2075}
2076
2077bool Element::hasAttribute(const AtomicString& localName) const
2078{
2079 if (!elementData())
2080 return false;
2081 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002082 return elementData()->getAttributeItem(shouldIgnoreAttributeCase() ? localName.lower() : localName, false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002083}
2084
2085bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
2086{
2087 if (!elementData())
2088 return false;
2089 QualifiedName qName(nullAtom, localName, namespaceURI);
2090 synchronizeAttribute(qName);
2091 return elementData()->getAttributeItem(qName);
2092}
2093
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002094void Element::focus(bool restorePreviousSelection, FocusDirection direction)
2095{
2096 if (!inDocument())
2097 return;
2098
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002099 Document& doc = document();
2100 if (doc.focusedElement() == this)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002101 return;
2102
2103 // If the stylesheets have already been loaded we can reliably check isFocusable.
2104 // If not, we continue and set the focused node on the focus controller below so
Ben Murdoch591b9582013-07-10 11:41:44 +01002105 // that it can be updated soon after attach.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002106 if (doc.haveStylesheetsLoaded()) {
2107 doc.updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002108 if (!isFocusable())
2109 return;
2110 }
2111
2112 if (!supportsFocus())
2113 return;
2114
2115 RefPtr<Node> protect;
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002116 if (Page* page = doc.page()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002117 // Focus and change event handlers can cause us to lose our last ref.
2118 // If a focus event handler changes the focus to a different node it
2119 // does not make sense to continue and update appearence.
2120 protect = this;
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002121 if (!page->focusController().setFocusedElement(this, doc.frame(), direction))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002122 return;
2123 }
2124
2125 // Setting the focused node above might have invalidated the layout due to scripts.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002126 doc.updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002127
2128 if (!isFocusable()) {
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002129 ensureElementRareData().setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002130 return;
2131 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002132
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002133 cancelFocusAppearanceUpdate();
2134 updateFocusAppearance(restorePreviousSelection);
2135}
2136
2137void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
2138{
2139 if (isRootEditableElement()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002140 Frame* frame = document().frame();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002141 if (!frame)
2142 return;
Ben Murdoch591b9582013-07-10 11:41:44 +01002143
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002144 // 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 +01002145 if (this == frame->selection().rootEditableElement())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002146 return;
2147
2148 // FIXME: We should restore the previous selection if there is one.
2149 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002150 frame->selection().setSelection(newSelection);
2151 frame->selection().revealSelection();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002152 } else if (renderer() && !renderer()->isWidget())
2153 renderer()->scrollRectToVisible(boundingBox());
2154}
2155
2156void Element::blur()
2157{
2158 cancelFocusAppearanceUpdate();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002159 if (treeScope().adjustedFocusedElement() == this) {
2160 Document& doc = document();
2161 if (doc.page())
2162 doc.page()->focusController().setFocusedElement(0, doc.frame());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002163 else
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002164 doc.setFocusedElement(0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002165 }
2166}
2167
Ben Murdochdf957042013-08-06 11:01:27 +01002168bool Element::isFocusable() const
2169{
2170 return inDocument() && supportsFocus() && !isInert() && rendererIsFocusable();
2171}
2172
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002173bool Element::isKeyboardFocusable() const
2174{
2175 return isFocusable() && tabIndex() >= 0;
2176}
2177
2178bool Element::isMouseFocusable() const
2179{
2180 return isFocusable();
2181}
2182
Ben Murdoch02772c62013-07-26 10:21:05 +01002183void Element::dispatchFocusEvent(Element* oldFocusedElement, FocusDirection)
2184{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002185 RefPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::focus, false, false, document().domWindow(), 0, oldFocusedElement);
Ben Murdoch02772c62013-07-26 10:21:05 +01002186 EventDispatcher::dispatchEvent(this, FocusEventDispatchMediator::create(event.release()));
2187}
2188
2189void Element::dispatchBlurEvent(Element* newFocusedElement)
2190{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002191 RefPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::blur, false, false, document().domWindow(), 0, newFocusedElement);
Ben Murdoch02772c62013-07-26 10:21:05 +01002192 EventDispatcher::dispatchEvent(this, BlurEventDispatchMediator::create(event.release()));
2193}
2194
2195void Element::dispatchFocusInEvent(const AtomicString& eventType, Element* oldFocusedElement)
2196{
2197 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002198 ASSERT(eventType == EventTypeNames::focusin || eventType == EventTypeNames::DOMFocusIn);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002199 dispatchScopedEventDispatchMediator(FocusInEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document().domWindow(), 0, oldFocusedElement)));
Ben Murdoch02772c62013-07-26 10:21:05 +01002200}
2201
2202void Element::dispatchFocusOutEvent(const AtomicString& eventType, Element* newFocusedElement)
2203{
2204 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002205 ASSERT(eventType == EventTypeNames::focusout || eventType == EventTypeNames::DOMFocusOut);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002206 dispatchScopedEventDispatchMediator(FocusOutEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document().domWindow(), 0, newFocusedElement)));
Ben Murdoch02772c62013-07-26 10:21:05 +01002207}
2208
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002209String Element::innerText()
2210{
2211 // We need to update layout, since plainText uses line boxes in the render tree.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002212 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002213
2214 if (!renderer())
2215 return textContent(true);
2216
2217 return plainText(rangeOfContents(const_cast<Element*>(this)).get());
2218}
2219
2220String Element::outerText()
2221{
2222 // Getting outerText is the same as getting innerText, only
2223 // setting is different. You would think this should get the plain
2224 // text for the outer range, but this is wrong, <br> for instance
2225 // would return different values for inner and outer text by such
2226 // a rule, but it doesn't in WinIE, and we want to match that.
2227 return innerText();
2228}
2229
Ben Murdoch591b9582013-07-10 11:41:44 +01002230String Element::textFromChildren()
2231{
2232 Text* firstTextNode = 0;
2233 bool foundMultipleTextNodes = false;
2234 unsigned totalLength = 0;
2235
2236 for (Node* child = firstChild(); child; child = child->nextSibling()) {
2237 if (!child->isTextNode())
2238 continue;
2239 Text* text = toText(child);
2240 if (!firstTextNode)
2241 firstTextNode = text;
2242 else
2243 foundMultipleTextNodes = true;
2244 unsigned length = text->data().length();
2245 if (length > std::numeric_limits<unsigned>::max() - totalLength)
2246 return emptyString();
2247 totalLength += length;
2248 }
2249
2250 if (!firstTextNode)
2251 return emptyString();
2252
2253 if (firstTextNode && !foundMultipleTextNodes) {
2254 firstTextNode->atomize();
2255 return firstTextNode->data();
2256 }
2257
2258 StringBuilder content;
2259 content.reserveCapacity(totalLength);
2260 for (Node* child = firstTextNode; child; child = child->nextSibling()) {
2261 if (!child->isTextNode())
2262 continue;
2263 content.append(toText(child)->data());
2264 }
2265
2266 ASSERT(content.length() == totalLength);
2267 return content.toString();
2268}
2269
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01002270// pseudo is used via shadowPseudoId.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002271const AtomicString& Element::pseudo() const
2272{
2273 return getAttribute(pseudoAttr);
2274}
2275
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002276const AtomicString& Element::part() const
2277{
2278 return getAttribute(partAttr);
2279}
2280
2281void Element::setPart(const AtomicString& value)
2282{
2283 setAttribute(partAttr, value);
2284}
2285
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002286LayoutSize Element::minimumSizeForResizing() const
2287{
2288 return hasRareData() ? elementRareData()->minimumSizeForResizing() : defaultMinimumSizeForResizing();
2289}
2290
2291void Element::setMinimumSizeForResizing(const LayoutSize& size)
2292{
2293 if (!hasRareData() && size == defaultMinimumSizeForResizing())
2294 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002295 ensureElementRareData().setMinimumSizeForResizing(size);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002296}
2297
2298RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
2299{
2300 if (PseudoElement* element = pseudoElement(pseudoElementSpecifier))
2301 return element->computedStyle();
2302
2303 // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
2304 // properties, which are only known by the renderer because it did the layout, will be correct and so that the
2305 // values returned for the ":selection" pseudo-element will be correct.
2306 if (RenderStyle* usedStyle = renderStyle()) {
2307 if (pseudoElementSpecifier) {
2308 RenderStyle* cachedPseudoStyle = usedStyle->getCachedPseudoStyle(pseudoElementSpecifier);
2309 return cachedPseudoStyle ? cachedPseudoStyle : usedStyle;
2310 } else
2311 return usedStyle;
2312 }
2313
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002314 if (!confusingAndOftenMisusedAttached())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002315 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
2316 // document tree and figure out when to destroy the computed style for such elements.
2317 return 0;
2318
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002319 ElementRareData& rareData = ensureElementRareData();
2320 if (!rareData.computedStyle())
2321 rareData.setComputedStyle(document().styleForElementIgnoringPendingStylesheets(this));
2322 return pseudoElementSpecifier ? rareData.computedStyle()->getCachedPseudoStyle(pseudoElementSpecifier) : rareData.computedStyle();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002323}
2324
2325void Element::setStyleAffectedByEmpty()
2326{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002327 ensureElementRareData().setStyleAffectedByEmpty(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002328}
2329
2330void Element::setChildrenAffectedByHover(bool value)
2331{
2332 if (value || hasRareData())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002333 ensureElementRareData().setChildrenAffectedByHover(value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002334}
2335
2336void Element::setChildrenAffectedByActive(bool value)
2337{
2338 if (value || hasRareData())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002339 ensureElementRareData().setChildrenAffectedByActive(value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002340}
2341
2342void Element::setChildrenAffectedByDrag(bool value)
2343{
2344 if (value || hasRareData())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002345 ensureElementRareData().setChildrenAffectedByDrag(value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002346}
2347
2348void Element::setChildrenAffectedByFirstChildRules()
2349{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002350 ensureElementRareData().setChildrenAffectedByFirstChildRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002351}
2352
2353void Element::setChildrenAffectedByLastChildRules()
2354{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002355 ensureElementRareData().setChildrenAffectedByLastChildRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002356}
2357
2358void Element::setChildrenAffectedByDirectAdjacentRules()
2359{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002360 ensureElementRareData().setChildrenAffectedByDirectAdjacentRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002361}
2362
2363void Element::setChildrenAffectedByForwardPositionalRules()
2364{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002365 ensureElementRareData().setChildrenAffectedByForwardPositionalRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002366}
2367
2368void Element::setChildrenAffectedByBackwardPositionalRules()
2369{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002370 ensureElementRareData().setChildrenAffectedByBackwardPositionalRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002371}
2372
2373void Element::setChildIndex(unsigned index)
2374{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002375 ElementRareData& rareData = ensureElementRareData();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002376 if (RenderStyle* style = renderStyle())
2377 style->setUnique();
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002378 rareData.setChildIndex(index);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002379}
2380
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002381bool Element::childrenSupportStyleSharing() const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002382{
2383 if (!hasRareData())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002384 return true;
2385 return !rareDataChildrenAffectedByHover()
2386 && !rareDataChildrenAffectedByActive()
2387 && !rareDataChildrenAffectedByDrag()
2388 && !rareDataChildrenAffectedByFirstChildRules()
2389 && !rareDataChildrenAffectedByLastChildRules()
2390 && !rareDataChildrenAffectedByDirectAdjacentRules()
2391 && !rareDataChildrenAffectedByForwardPositionalRules()
2392 && !rareDataChildrenAffectedByBackwardPositionalRules();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002393}
2394
2395bool Element::rareDataStyleAffectedByEmpty() const
2396{
2397 ASSERT(hasRareData());
2398 return elementRareData()->styleAffectedByEmpty();
2399}
2400
2401bool Element::rareDataChildrenAffectedByHover() const
2402{
2403 ASSERT(hasRareData());
2404 return elementRareData()->childrenAffectedByHover();
2405}
2406
2407bool Element::rareDataChildrenAffectedByActive() const
2408{
2409 ASSERT(hasRareData());
2410 return elementRareData()->childrenAffectedByActive();
2411}
2412
2413bool Element::rareDataChildrenAffectedByDrag() const
2414{
2415 ASSERT(hasRareData());
2416 return elementRareData()->childrenAffectedByDrag();
2417}
2418
2419bool Element::rareDataChildrenAffectedByFirstChildRules() const
2420{
2421 ASSERT(hasRareData());
2422 return elementRareData()->childrenAffectedByFirstChildRules();
2423}
2424
2425bool Element::rareDataChildrenAffectedByLastChildRules() const
2426{
2427 ASSERT(hasRareData());
2428 return elementRareData()->childrenAffectedByLastChildRules();
2429}
2430
2431bool Element::rareDataChildrenAffectedByDirectAdjacentRules() const
2432{
2433 ASSERT(hasRareData());
2434 return elementRareData()->childrenAffectedByDirectAdjacentRules();
2435}
2436
2437bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
2438{
2439 ASSERT(hasRareData());
2440 return elementRareData()->childrenAffectedByForwardPositionalRules();
2441}
2442
2443bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
2444{
2445 ASSERT(hasRareData());
2446 return elementRareData()->childrenAffectedByBackwardPositionalRules();
2447}
2448
2449unsigned Element::rareDataChildIndex() const
2450{
2451 ASSERT(hasRareData());
2452 return elementRareData()->childIndex();
2453}
2454
2455void Element::setIsInCanvasSubtree(bool isInCanvasSubtree)
2456{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002457 ensureElementRareData().setIsInCanvasSubtree(isInCanvasSubtree);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002458}
2459
2460bool Element::isInCanvasSubtree() const
2461{
2462 return hasRareData() && elementRareData()->isInCanvasSubtree();
2463}
2464
Ben Murdoch591b9582013-07-10 11:41:44 +01002465void Element::setIsInsideRegion(bool value)
2466{
2467 if (value == isInsideRegion())
2468 return;
2469
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002470 ensureElementRareData().setIsInsideRegion(value);
Ben Murdoch591b9582013-07-10 11:41:44 +01002471}
2472
2473bool Element::isInsideRegion() const
2474{
2475 return hasRareData() ? elementRareData()->isInsideRegion() : false;
2476}
2477
2478void Element::setRegionOversetState(RegionOversetState state)
2479{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002480 ensureElementRareData().setRegionOversetState(state);
Ben Murdoch591b9582013-07-10 11:41:44 +01002481}
2482
2483RegionOversetState Element::regionOversetState() const
2484{
2485 return hasRareData() ? elementRareData()->regionOversetState() : RegionUndefined;
2486}
2487
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002488AtomicString Element::computeInheritedLanguage() const
2489{
2490 const Node* n = this;
2491 AtomicString value;
2492 // The language property is inherited, so we iterate over the parents to find the first language.
2493 do {
2494 if (n->isElementNode()) {
2495 if (const ElementData* elementData = toElement(n)->elementData()) {
2496 // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7
2497 if (const Attribute* attribute = elementData->getAttributeItem(XMLNames::langAttr))
2498 value = attribute->value();
2499 else if (const Attribute* attribute = elementData->getAttributeItem(HTMLNames::langAttr))
2500 value = attribute->value();
2501 }
2502 } else if (n->isDocumentNode()) {
2503 // checking the MIME content-language
2504 value = toDocument(n)->contentLanguage();
2505 }
2506
2507 n = n->parentNode();
2508 } while (n && value.isNull());
2509
2510 return value;
2511}
2512
2513Locale& Element::locale() const
2514{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002515 return document().getCachedLocale(computeInheritedLanguage());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002516}
2517
2518void Element::cancelFocusAppearanceUpdate()
2519{
2520 if (hasRareData())
2521 elementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002522 if (document().focusedElement() == this)
2523 document().cancelFocusAppearanceUpdate();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002524}
2525
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002526void Element::updateCallbackSelectors(RenderStyle* oldStyle, RenderStyle* newStyle)
2527{
2528 const Vector<String> emptyVector;
2529 const Vector<String>& oldCallbackSelectors = oldStyle ? oldStyle->callbackSelectors() : emptyVector;
2530 const Vector<String>& newCallbackSelectors = newStyle ? newStyle->callbackSelectors() : emptyVector;
2531
2532 CSSSelectorWatch::from(document()).updateSelectorMatches(oldCallbackSelectors, newCallbackSelectors);
2533}
2534
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002535void Element::normalizeAttributes()
2536{
2537 if (!hasAttributes())
2538 return;
2539 for (unsigned i = 0; i < attributeCount(); ++i) {
2540 if (RefPtr<Attr> attr = attrIfExists(attributeItem(i)->name()))
2541 attr->normalize();
2542 }
2543}
2544
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002545void Element::updatePseudoElement(PseudoId pseudoId, StyleRecalcChange change)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002546{
2547 PseudoElement* element = pseudoElement(pseudoId);
2548 if (element && (needsStyleRecalc() || shouldRecalcStyle(change, element))) {
2549 // PseudoElement styles hang off their parent element's style so if we needed
2550 // a style recalc we should Force one on the pseudo.
2551 element->recalcStyle(needsStyleRecalc() ? Force : change);
2552
2553 // Wait until our parent is not displayed or pseudoElementRendererIsNeeded
2554 // is false, otherwise we could continously create and destroy PseudoElements
2555 // when RenderObject::isChildAllowed on our parent returns false for the
2556 // PseudoElement's renderer for each style recalc.
2557 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01002558 elementRareData()->setPseudoElement(pseudoId, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002559 } else if (change >= Inherit || needsStyleRecalc())
2560 createPseudoElementIfNeeded(pseudoId);
2561}
2562
2563void Element::createPseudoElementIfNeeded(PseudoId pseudoId)
2564{
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002565 if (needsPseudoElement(pseudoId))
2566 createPseudoElement(pseudoId);
2567}
2568
2569bool Element::needsPseudoElement(PseudoId pseudoId) const
2570{
Ben Murdoche69819b2013-07-17 14:56:49 +01002571 if (pseudoId == BACKDROP && !isInTopLayer())
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002572 return false;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002573 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002574 return false;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002575 if (!renderer()->canHaveGeneratedChildren())
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002576 return false;
2577 return true;
2578}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002579
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002580void Element::createPseudoElement(PseudoId pseudoId)
2581{
2582 ASSERT(needsPseudoElement(pseudoId));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002583 ASSERT(!isPseudoElement());
2584 RefPtr<PseudoElement> element = PseudoElement::create(this, pseudoId);
Ben Murdoche69819b2013-07-17 14:56:49 +01002585 if (pseudoId == BACKDROP)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002586 document().addToTopLayer(element.get(), this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002587 element->attach();
Ben Murdoche69819b2013-07-17 14:56:49 +01002588
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002589 ensureElementRareData().setPseudoElement(pseudoId, element.release());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002590}
2591
2592PseudoElement* Element::pseudoElement(PseudoId pseudoId) const
2593{
2594 return hasRareData() ? elementRareData()->pseudoElement(pseudoId) : 0;
2595}
2596
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002597RenderObject* Element::pseudoElementRenderer(PseudoId pseudoId) const
2598{
2599 if (PseudoElement* element = pseudoElement(pseudoId))
2600 return element->renderer();
2601 return 0;
2602}
2603
Ben Murdochdf957042013-08-06 11:01:27 +01002604bool Element::webkitMatchesSelector(const String& selector, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002605{
2606 if (selector.isEmpty()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01002607 es.throwUninformativeAndGenericDOMException(SyntaxError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002608 return false;
2609 }
2610
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002611 SelectorQuery* selectorQuery = document().selectorQueryCache()->add(selector, document(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002612 if (!selectorQuery)
2613 return false;
2614 return selectorQuery->matches(this);
2615}
2616
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002617DOMTokenList* Element::classList()
2618{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002619 ElementRareData& rareData = ensureElementRareData();
2620 if (!rareData.classList())
2621 rareData.setClassList(ClassList::create(this));
2622 return rareData.classList();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002623}
2624
2625DOMStringMap* Element::dataset()
2626{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002627 ElementRareData& rareData = ensureElementRareData();
2628 if (!rareData.dataset())
2629 rareData.setDataset(DatasetDOMStringMap::create(this));
2630 return rareData.dataset();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002631}
2632
2633KURL Element::getURLAttribute(const QualifiedName& name) const
2634{
2635#if !ASSERT_DISABLED
2636 if (elementData()) {
2637 if (const Attribute* attribute = getAttributeItem(name))
2638 ASSERT(isURLAttribute(*attribute));
2639 }
2640#endif
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002641 return document().completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002642}
2643
2644KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
2645{
2646#if !ASSERT_DISABLED
2647 if (elementData()) {
2648 if (const Attribute* attribute = getAttributeItem(name))
2649 ASSERT(isURLAttribute(*attribute));
2650 }
2651#endif
2652 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
2653 if (value.isEmpty())
2654 return KURL();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002655 return document().completeURL(value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002656}
2657
2658int Element::getIntegralAttribute(const QualifiedName& attributeName) const
2659{
2660 return getAttribute(attributeName).string().toInt();
2661}
2662
2663void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
2664{
2665 // FIXME: Need an AtomicString version of String::number.
2666 setAttribute(attributeName, String::number(value));
2667}
2668
2669unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
2670{
2671 return getAttribute(attributeName).string().toUInt();
2672}
2673
2674void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
2675{
2676 // FIXME: Need an AtomicString version of String::number.
2677 setAttribute(attributeName, String::number(value));
2678}
2679
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002680bool Element::childShouldCreateRenderer(const Node& child) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002681{
2682 // 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 +01002683 if (child.isSVGElement())
2684 return child.hasTagName(SVGNames::svgTag) || isSVGElement();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002685
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002686 return ContainerNode::childShouldCreateRenderer(child);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002687}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002688
2689void Element::webkitRequestFullscreen()
2690{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002691 FullscreenElementStack::from(&document())->requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002692}
2693
2694void Element::webkitRequestFullScreen(unsigned short flags)
2695{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002696 FullscreenElementStack::from(&document())->requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002697}
2698
2699bool Element::containsFullScreenElement() const
2700{
2701 return hasRareData() && elementRareData()->containsFullScreenElement();
2702}
2703
2704void Element::setContainsFullScreenElement(bool flag)
2705{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002706 ensureElementRareData().setContainsFullScreenElement(flag);
Ben Murdoche69819b2013-07-17 14:56:49 +01002707 setNeedsStyleRecalc(SubtreeStyleChange);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002708}
2709
2710static Element* parentCrossingFrameBoundaries(Element* element)
2711{
2712 ASSERT(element);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002713 return element->parentElement() ? element->parentElement() : element->document().ownerElement();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002714}
2715
2716void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool flag)
2717{
2718 Element* element = this;
2719 while ((element = parentCrossingFrameBoundaries(element)))
2720 element->setContainsFullScreenElement(flag);
2721}
2722
2723bool Element::isInTopLayer() const
2724{
2725 return hasRareData() && elementRareData()->isInTopLayer();
2726}
2727
2728void Element::setIsInTopLayer(bool inTopLayer)
2729{
2730 if (isInTopLayer() == inTopLayer)
2731 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002732 ensureElementRareData().setIsInTopLayer(inTopLayer);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002733
2734 // We must ensure a reattach occurs so the renderer is inserted in the correct sibling order under RenderView according to its
2735 // top layer position, or in its usual place if not in the top layer.
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002736 lazyReattachIfAttached();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002737}
2738
2739void Element::webkitRequestPointerLock()
2740{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002741 if (document().page())
2742 document().page()->pointerLockController().requestPointerLock(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002743}
2744
2745SpellcheckAttributeState Element::spellcheckAttributeState() const
2746{
2747 const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
2748 if (value == nullAtom)
2749 return SpellcheckAttributeDefault;
2750 if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
2751 return SpellcheckAttributeTrue;
2752 if (equalIgnoringCase(value, "false"))
2753 return SpellcheckAttributeFalse;
2754
2755 return SpellcheckAttributeDefault;
2756}
2757
2758bool Element::isSpellCheckingEnabled() const
2759{
2760 for (const Element* element = this; element; element = element->parentOrShadowHostElement()) {
2761 switch (element->spellcheckAttributeState()) {
2762 case SpellcheckAttributeTrue:
2763 return true;
2764 case SpellcheckAttributeFalse:
2765 return false;
2766 case SpellcheckAttributeDefault:
2767 break;
2768 }
2769 }
2770
2771 return true;
2772}
2773
2774RenderRegion* Element::renderRegion() const
2775{
2776 if (renderer() && renderer()->isRenderRegion())
2777 return toRenderRegion(renderer());
2778
2779 return 0;
2780}
2781
Ben Murdoch591b9582013-07-10 11:41:44 +01002782bool Element::shouldMoveToFlowThread(RenderStyle* styleToUse) const
2783{
2784 ASSERT(styleToUse);
2785
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002786 if (FullscreenElementStack::isActiveFullScreenElement(this))
Ben Murdoch591b9582013-07-10 11:41:44 +01002787 return false;
2788
2789 if (isInShadowTree())
2790 return false;
2791
2792 if (styleToUse->flowThread().isEmpty())
2793 return false;
2794
2795 return !isRegisteredWithNamedFlow();
2796}
2797
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002798const AtomicString& Element::webkitRegionOverset() const
2799{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002800 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002801
2802 DEFINE_STATIC_LOCAL(AtomicString, undefinedState, ("undefined", AtomicString::ConstructFromLiteral));
2803 if (!RuntimeEnabledFeatures::cssRegionsEnabled() || !renderRegion())
2804 return undefinedState;
2805
Ben Murdoch591b9582013-07-10 11:41:44 +01002806 switch (renderRegion()->regionOversetState()) {
2807 case RegionFit: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002808 DEFINE_STATIC_LOCAL(AtomicString, fitState, ("fit", AtomicString::ConstructFromLiteral));
2809 return fitState;
2810 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002811 case RegionEmpty: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002812 DEFINE_STATIC_LOCAL(AtomicString, emptyState, ("empty", AtomicString::ConstructFromLiteral));
2813 return emptyState;
2814 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002815 case RegionOverset: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002816 DEFINE_STATIC_LOCAL(AtomicString, overflowState, ("overset", AtomicString::ConstructFromLiteral));
2817 return overflowState;
2818 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002819 case RegionUndefined:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002820 return undefinedState;
2821 }
2822
2823 ASSERT_NOT_REACHED();
2824 return undefinedState;
2825}
2826
2827Vector<RefPtr<Range> > Element::webkitGetRegionFlowRanges() const
2828{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002829 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002830
2831 Vector<RefPtr<Range> > rangeObjects;
2832 if (RuntimeEnabledFeatures::cssRegionsEnabled() && renderer() && renderer()->isRenderRegion()) {
2833 RenderRegion* region = toRenderRegion(renderer());
2834 if (region->isValid())
2835 region->getRanges(rangeObjects);
2836 }
2837
2838 return rangeObjects;
2839}
2840
2841#ifndef NDEBUG
2842bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
2843{
2844 if (name == HTMLNames::styleAttr)
2845 return false;
2846
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002847 if (isSVGElement())
2848 return !static_cast<const SVGElement*>(this)->isAnimatableAttribute(name);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002849
2850 return true;
2851}
2852#endif
2853
2854#ifdef DUMP_NODE_STATISTICS
2855bool Element::hasNamedNodeMap() const
2856{
2857 return hasRareData() && elementRareData()->attributeMap();
2858}
2859#endif
2860
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002861inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002862{
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002863 if (!inDocument() || isInShadowTree())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002864 return;
2865
2866 if (oldName == newName)
2867 return;
2868
Ben Murdochdf957042013-08-06 11:01:27 +01002869 if (shouldRegisterAsNamedItem())
2870 updateNamedItemRegistration(oldName, newName);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002871}
2872
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002873inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002874{
2875 if (!isInTreeScope())
2876 return;
2877
2878 if (oldId == newId)
2879 return;
2880
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002881 updateId(treeScope(), oldId, newId);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002882}
2883
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002884inline void Element::updateId(TreeScope& scope, const AtomicString& oldId, const AtomicString& newId)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002885{
2886 ASSERT(isInTreeScope());
2887 ASSERT(oldId != newId);
2888
2889 if (!oldId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002890 scope.removeElementById(oldId, this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002891 if (!newId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002892 scope.addElementById(newId, this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002893
Ben Murdochdf957042013-08-06 11:01:27 +01002894 if (shouldRegisterAsExtraNamedItem())
2895 updateExtraNamedItemRegistration(oldId, newId);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002896}
2897
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002898void Element::updateLabel(TreeScope& scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002899{
2900 ASSERT(hasTagName(labelTag));
2901
2902 if (!inDocument())
2903 return;
2904
2905 if (oldForAttributeValue == newForAttributeValue)
2906 return;
2907
2908 if (!oldForAttributeValue.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002909 scope.removeLabel(oldForAttributeValue, toHTMLLabelElement(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002910 if (!newForAttributeValue.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002911 scope.addLabel(newForAttributeValue, toHTMLLabelElement(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002912}
2913
Ben Murdoch7757ec22013-07-23 11:17:36 +01002914static bool hasSelectorForAttribute(Document* document, const AtomicString& localName)
2915{
2916 return document->styleResolver() && document->styleResolver()->ruleFeatureSet().hasSelectorForAttribute(localName);
2917}
2918
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002919void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
2920{
2921 if (isIdAttributeName(name))
2922 updateId(oldValue, newValue);
2923 else if (name == HTMLNames::nameAttr)
2924 updateName(oldValue, newValue);
2925 else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002926 TreeScope& scope = treeScope();
2927 if (scope.shouldCacheLabelsByForAttribute())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002928 updateLabel(scope, oldValue, newValue);
2929 }
2930
2931 if (oldValue != newValue) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002932 if (confusingAndOftenMisusedAttached() && hasSelectorForAttribute(&document(), name.localName()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002933 setNeedsStyleRecalc();
Ben Murdoche69819b2013-07-17 14:56:49 +01002934
2935 if (isUpgradedCustomElement())
Ben Murdoch83750172013-07-24 10:36:59 +01002936 CustomElement::attributeDidChange(this, name.localName(), oldValue, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002937 }
2938
2939 if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(this, name))
2940 recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue));
2941
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002942 InspectorInstrumentation::willModifyDOMAttr(this, oldValue, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002943}
2944
2945void Element::didAddAttribute(const QualifiedName& name, const AtomicString& value)
2946{
2947 attributeChanged(name, value);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002948 InspectorInstrumentation::didModifyDOMAttr(this, name.localName(), value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002949 dispatchSubtreeModifiedEvent();
2950}
2951
2952void Element::didModifyAttribute(const QualifiedName& name, const AtomicString& value)
2953{
2954 attributeChanged(name, value);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002955 InspectorInstrumentation::didModifyDOMAttr(this, name.localName(), value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002956 // Do not dispatch a DOMSubtreeModified event here; see bug 81141.
2957}
2958
2959void Element::didRemoveAttribute(const QualifiedName& name)
2960{
2961 attributeChanged(name, nullAtom);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002962 InspectorInstrumentation::didRemoveDOMAttr(this, name.localName());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002963 dispatchSubtreeModifiedEvent();
2964}
2965
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002966void Element::didMoveToNewDocument(Document& oldDocument)
Ben Murdoche69819b2013-07-17 14:56:49 +01002967{
2968 Node::didMoveToNewDocument(oldDocument);
2969
2970 // If the documents differ by quirks mode then they differ by case sensitivity
2971 // for class and id names so we need to go through the attribute change logic
2972 // to pick up the new casing in the ElementData.
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002973 if (oldDocument.inQuirksMode() != document().inQuirksMode()) {
Ben Murdoche69819b2013-07-17 14:56:49 +01002974 if (hasID())
2975 setIdAttribute(getIdAttribute());
2976 if (hasClass())
2977 setAttribute(HTMLNames::classAttr, getClassAttribute());
2978 }
2979}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002980
Ben Murdochdf957042013-08-06 11:01:27 +01002981void Element::updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName)
2982{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002983 if (!document().isHTMLDocument())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002984 return;
Ben Murdochdf957042013-08-06 11:01:27 +01002985
2986 if (!oldName.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002987 toHTMLDocument(document()).removeNamedItem(oldName);
Ben Murdochdf957042013-08-06 11:01:27 +01002988
2989 if (!newName.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002990 toHTMLDocument(document()).addNamedItem(newName);
Ben Murdochdf957042013-08-06 11:01:27 +01002991}
2992
2993void Element::updateExtraNamedItemRegistration(const AtomicString& oldId, const AtomicString& newId)
2994{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002995 if (!document().isHTMLDocument())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002996 return;
Ben Murdochdf957042013-08-06 11:01:27 +01002997
2998 if (!oldId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002999 toHTMLDocument(document()).removeExtraNamedItem(oldId);
Ben Murdochdf957042013-08-06 11:01:27 +01003000
3001 if (!newId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003002 toHTMLDocument(document()).addExtraNamedItem(newId);
Ben Murdochdf957042013-08-06 11:01:27 +01003003}
3004
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003005PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
3006{
3007 if (HTMLCollection* collection = cachedHTMLCollection(type))
3008 return collection;
3009
3010 RefPtr<HTMLCollection> collection;
3011 if (type == TableRows) {
3012 ASSERT(hasTagName(tableTag));
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003013 return ensureRareData().ensureNodeLists()->addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003014 } else if (type == SelectOptions) {
3015 ASSERT(hasTagName(selectTag));
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003016 return ensureRareData().ensureNodeLists()->addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003017 } else if (type == FormControls) {
3018 ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003019 return ensureRareData().ensureNodeLists()->addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003020 }
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003021 return ensureRareData().ensureNodeLists()->addCacheWithAtomicName<HTMLCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003022}
3023
Ben Murdoch591b9582013-07-10 11:41:44 +01003024static void scheduleLayerUpdateCallback(Node* node)
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003025{
Ben Murdoche69819b2013-07-17 14:56:49 +01003026 // Notify the renderer even is the styles are identical since it may need to
3027 // create or destroy a RenderLayer.
3028 node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003029}
3030
Ben Murdoch591b9582013-07-10 11:41:44 +01003031void Element::scheduleLayerUpdate()
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003032{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003033 if (document().inStyleRecalc())
3034 PostAttachCallbacks::queueCallback(scheduleLayerUpdateCallback, this);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003035 else
Ben Murdoche69819b2013-07-17 14:56:49 +01003036 scheduleLayerUpdateCallback(this);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003037}
3038
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003039HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
3040{
3041 return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0;
3042}
3043
3044IntSize Element::savedLayerScrollOffset() const
3045{
3046 return hasRareData() ? elementRareData()->savedLayerScrollOffset() : IntSize();
3047}
3048
3049void Element::setSavedLayerScrollOffset(const IntSize& size)
3050{
3051 if (size.isZero() && !hasRareData())
3052 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003053 ensureElementRareData().setSavedLayerScrollOffset(size);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003054}
3055
3056PassRefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
3057{
3058 if (AttrNodeList* attrNodeList = attrNodeListForElement(this))
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003059 return findAttrNodeInList(*attrNodeList, name);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003060 return 0;
3061}
3062
3063PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name)
3064{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003065 AttrNodeList& attrNodeList = ensureAttrNodeListForElement(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003066 RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
3067 if (!attrNode) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003068 attrNode = Attr::create(*this, name);
3069 treeScope().adoptIfNeeded(attrNode.get());
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003070 attrNodeList.append(attrNode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003071 }
3072 return attrNode.release();
3073}
3074
3075void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value)
3076{
3077 ASSERT(hasSyntheticAttrChildNodes());
3078 attrNode->detachFromElementWithValue(value);
3079
3080 AttrNodeList* attrNodeList = attrNodeListForElement(this);
3081 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
3082 if (attrNodeList->at(i)->qualifiedName() == attrNode->qualifiedName()) {
3083 attrNodeList->remove(i);
3084 if (attrNodeList->isEmpty())
3085 removeAttrNodeListForElement(this);
3086 return;
3087 }
3088 }
3089 ASSERT_NOT_REACHED();
3090}
3091
3092void Element::detachAllAttrNodesFromElement()
3093{
3094 AttrNodeList* attrNodeList = attrNodeListForElement(this);
3095 ASSERT(attrNodeList);
3096
3097 for (unsigned i = 0; i < attributeCount(); ++i) {
3098 const Attribute* attribute = attributeItem(i);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003099 if (RefPtr<Attr> attrNode = findAttrNodeInList(*attrNodeList, attribute->name()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003100 attrNode->detachFromElementWithValue(attribute->value());
3101 }
3102
3103 removeAttrNodeListForElement(this);
3104}
3105
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003106void Element::willRecalcStyle(StyleRecalcChange)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003107{
3108 ASSERT(hasCustomStyleCallbacks());
3109}
3110
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003111void Element::didRecalcStyle(StyleRecalcChange)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003112{
3113 ASSERT(hasCustomStyleCallbacks());
3114}
3115
3116
3117PassRefPtr<RenderStyle> Element::customStyleForRenderer()
3118{
3119 ASSERT(hasCustomStyleCallbacks());
3120 return 0;
3121}
3122
3123void Element::cloneAttributesFromElement(const Element& other)
3124{
3125 if (hasSyntheticAttrChildNodes())
3126 detachAllAttrNodesFromElement();
3127
3128 other.synchronizeAllAttributes();
3129 if (!other.m_elementData) {
3130 m_elementData.clear();
3131 return;
3132 }
3133
3134 const AtomicString& oldID = getIdAttribute();
3135 const AtomicString& newID = other.getIdAttribute();
3136
3137 if (!oldID.isNull() || !newID.isNull())
3138 updateId(oldID, newID);
3139
3140 const AtomicString& oldName = getNameAttribute();
3141 const AtomicString& newName = other.getNameAttribute();
3142
3143 if (!oldName.isNull() || !newName.isNull())
3144 updateName(oldName, newName);
3145
Ben Murdoche69819b2013-07-17 14:56:49 +01003146 // Quirks mode makes class and id not case sensitive. We can't share the ElementData
3147 // if the idForStyleResolution and the className need different casing.
3148 bool ownerDocumentsHaveDifferentCaseSensitivity = false;
3149 if (other.hasClass() || other.hasID())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003150 ownerDocumentsHaveDifferentCaseSensitivity = other.document().inQuirksMode() != document().inQuirksMode();
Ben Murdoche69819b2013-07-17 14:56:49 +01003151
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003152 // 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 +01003153 // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes,
3154 // and sharing the data won't result in different case sensitivity of class or id.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003155 if (other.m_elementData->isUnique()
Ben Murdoche69819b2013-07-17 14:56:49 +01003156 && !ownerDocumentsHaveDifferentCaseSensitivity
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003157 && !other.m_elementData->presentationAttributeStyle()
3158 && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper()))
3159 const_cast<Element&>(other).m_elementData = static_cast<const UniqueElementData*>(other.m_elementData.get())->makeShareableCopy();
3160
Ben Murdoche69819b2013-07-17 14:56:49 +01003161 if (!other.m_elementData->isUnique() && !ownerDocumentsHaveDifferentCaseSensitivity)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003162 m_elementData = other.m_elementData;
3163 else
3164 m_elementData = other.m_elementData->makeUniqueCopy();
3165
3166 for (unsigned i = 0; i < m_elementData->length(); ++i) {
3167 const Attribute* attribute = const_cast<const ElementData*>(m_elementData.get())->attributeItem(i);
3168 attributeChangedFromParserOrByCloning(attribute->name(), attribute->value(), ModifiedByCloning);
3169 }
3170}
3171
3172void Element::cloneDataFromElement(const Element& other)
3173{
3174 cloneAttributesFromElement(other);
3175 copyNonAttributePropertiesFromElement(other);
3176}
3177
3178void Element::createUniqueElementData()
3179{
3180 if (!m_elementData)
3181 m_elementData = UniqueElementData::create();
3182 else {
3183 ASSERT(!m_elementData->isUnique());
3184 m_elementData = static_cast<ShareableElementData*>(m_elementData.get())->makeUniqueCopy();
3185 }
3186}
3187
Ben Murdoch1fad5ca2013-08-07 11:05:11 +01003188InputMethodContext* Element::inputMethodContext()
Torne (Richard Coles)81a51572013-05-13 16:52:28 +01003189{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003190 return ensureElementRareData().ensureInputMethodContext(toHTMLElement(this));
Torne (Richard Coles)81a51572013-05-13 16:52:28 +01003191}
3192
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003193bool Element::hasPendingResources() const
3194{
3195 return hasRareData() && elementRareData()->hasPendingResources();
3196}
3197
3198void Element::setHasPendingResources()
3199{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003200 ensureElementRareData().setHasPendingResources(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003201}
3202
3203void Element::clearHasPendingResources()
3204{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003205 ensureElementRareData().setHasPendingResources(false);
Ben Murdoch591b9582013-07-10 11:41:44 +01003206}
3207
3208void Element::synchronizeStyleAttributeInternal() const
3209{
3210 ASSERT(isStyledElement());
3211 ASSERT(elementData());
3212 ASSERT(elementData()->m_styleAttributeIsDirty);
3213 elementData()->m_styleAttributeIsDirty = false;
3214 if (const StylePropertySet* inlineStyle = this->inlineStyle())
3215 const_cast<Element*>(this)->setSynchronizedLazyAttribute(styleAttr, inlineStyle->asText());
3216}
3217
3218CSSStyleDeclaration* Element::style()
3219{
3220 if (!isStyledElement())
3221 return 0;
3222 return ensureMutableInlineStyle()->ensureInlineCSSStyleDeclaration(this);
3223}
3224
3225MutableStylePropertySet* Element::ensureMutableInlineStyle()
3226{
3227 ASSERT(isStyledElement());
3228 RefPtr<StylePropertySet>& inlineStyle = ensureUniqueElementData()->m_inlineStyle;
3229 if (!inlineStyle)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003230 inlineStyle = MutableStylePropertySet::create(strictToCSSParserMode(isHTMLElement() && !document().inQuirksMode()));
Ben Murdoch591b9582013-07-10 11:41:44 +01003231 else if (!inlineStyle->isMutable())
3232 inlineStyle = inlineStyle->mutableCopy();
3233 ASSERT(inlineStyle->isMutable());
3234 return static_cast<MutableStylePropertySet*>(inlineStyle.get());
3235}
3236
3237PropertySetCSSStyleDeclaration* Element::inlineStyleCSSOMWrapper()
3238{
3239 if (!inlineStyle() || !inlineStyle()->hasCSSOMWrapper())
3240 return 0;
3241 PropertySetCSSStyleDeclaration* cssomWrapper = ensureMutableInlineStyle()->cssStyleDeclaration();
3242 ASSERT(cssomWrapper && cssomWrapper->parentElement() == this);
3243 return cssomWrapper;
3244}
3245
3246inline void Element::setInlineStyleFromString(const AtomicString& newStyleString)
3247{
3248 ASSERT(isStyledElement());
3249 RefPtr<StylePropertySet>& inlineStyle = elementData()->m_inlineStyle;
3250
3251 // Avoid redundant work if we're using shared attribute data with already parsed inline style.
3252 if (inlineStyle && !elementData()->isUnique())
3253 return;
3254
3255 // We reconstruct the property set instead of mutating if there is no CSSOM wrapper.
3256 // This makes wrapperless property sets immutable and so cacheable.
3257 if (inlineStyle && !inlineStyle->isMutable())
3258 inlineStyle.clear();
3259
3260 if (!inlineStyle) {
3261 inlineStyle = CSSParser::parseInlineStyleDeclaration(newStyleString, this);
3262 } else {
3263 ASSERT(inlineStyle->isMutable());
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003264 static_pointer_cast<MutableStylePropertySet>(inlineStyle)->parseDeclaration(newStyleString, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003265 }
3266}
3267
3268void Element::styleAttributeChanged(const AtomicString& newStyleString, AttributeModificationReason modificationReason)
3269{
3270 ASSERT(isStyledElement());
3271 WTF::OrdinalNumber startLineNumber = WTF::OrdinalNumber::beforeFirst();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003272 if (document().scriptableDocumentParser() && !document().isInDocumentWrite())
3273 startLineNumber = document().scriptableDocumentParser()->lineNumber();
Ben Murdoch591b9582013-07-10 11:41:44 +01003274
3275 if (newStyleString.isNull()) {
3276 if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
3277 cssomWrapper->clearParentElement();
3278 ensureUniqueElementData()->m_inlineStyle.clear();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003279 } else if (modificationReason == ModifiedByCloning || document().contentSecurityPolicy()->allowInlineStyle(document().url(), startLineNumber)) {
Ben Murdoch591b9582013-07-10 11:41:44 +01003280 setInlineStyleFromString(newStyleString);
3281 }
3282
3283 elementData()->m_styleAttributeIsDirty = false;
3284
Ben Murdoche69819b2013-07-17 14:56:49 +01003285 setNeedsStyleRecalc(LocalStyleChange);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003286 InspectorInstrumentation::didInvalidateStyleAttr(this);
Ben Murdoch591b9582013-07-10 11:41:44 +01003287}
3288
3289void Element::inlineStyleChanged()
3290{
3291 ASSERT(isStyledElement());
Ben Murdoche69819b2013-07-17 14:56:49 +01003292 setNeedsStyleRecalc(LocalStyleChange);
Ben Murdoch591b9582013-07-10 11:41:44 +01003293 ASSERT(elementData());
3294 elementData()->m_styleAttributeIsDirty = true;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003295 InspectorInstrumentation::didInvalidateStyleAttr(this);
Ben Murdoch591b9582013-07-10 11:41:44 +01003296}
3297
3298bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
3299{
3300 ASSERT(isStyledElement());
3301 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
3302 inlineStyleChanged();
3303 return true;
3304}
3305
3306bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
3307{
3308 ASSERT(isStyledElement());
3309 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
3310 inlineStyleChanged();
3311 return true;
3312}
3313
3314bool Element::setInlineStyleProperty(CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit, bool important)
3315{
3316 ASSERT(isStyledElement());
3317 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createValue(value, unit), important);
3318 inlineStyleChanged();
3319 return true;
3320}
3321
3322bool Element::setInlineStyleProperty(CSSPropertyID propertyID, const String& value, bool important)
3323{
3324 ASSERT(isStyledElement());
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003325 bool changes = ensureMutableInlineStyle()->setProperty(propertyID, value, important, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003326 if (changes)
3327 inlineStyleChanged();
3328 return changes;
3329}
3330
3331bool Element::removeInlineStyleProperty(CSSPropertyID propertyID)
3332{
3333 ASSERT(isStyledElement());
3334 if (!inlineStyle())
3335 return false;
3336 bool changes = ensureMutableInlineStyle()->removeProperty(propertyID);
3337 if (changes)
3338 inlineStyleChanged();
3339 return changes;
3340}
3341
3342void Element::removeAllInlineStyleProperties()
3343{
3344 ASSERT(isStyledElement());
3345 if (!inlineStyle() || inlineStyle()->isEmpty())
3346 return;
3347 ensureMutableInlineStyle()->clear();
3348 inlineStyleChanged();
3349}
3350
3351void Element::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
3352{
3353 ASSERT(isStyledElement());
3354 if (const StylePropertySet* inlineStyle = elementData() ? elementData()->inlineStyle() : 0)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003355 inlineStyle->addSubresourceStyleURLs(urls, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003356}
3357
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003358void Element::updatePresentationAttributeStyle()
Ben Murdoch591b9582013-07-10 11:41:44 +01003359{
Ben Murdoch591b9582013-07-10 11:41:44 +01003360 // ShareableElementData doesn't store presentation attribute style, so make sure we have a UniqueElementData.
3361 UniqueElementData* elementData = ensureUniqueElementData();
Ben Murdoch591b9582013-07-10 11:41:44 +01003362 elementData->m_presentationAttributeStyleIsDirty = false;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003363 elementData->m_presentationAttributeStyle = computePresentationAttributeStyle(*this);
Ben Murdoch591b9582013-07-10 11:41:44 +01003364}
3365
3366void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, CSSValueID identifier)
3367{
3368 ASSERT(isStyledElement());
3369 style->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier));
3370}
3371
3372void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit)
3373{
3374 ASSERT(isStyledElement());
3375 style->setProperty(propertyID, cssValuePool().createValue(value, unit));
3376}
3377
3378void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, const String& value)
3379{
3380 ASSERT(isStyledElement());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01003381 style->setProperty(propertyID, value, false);
Ben Murdoch591b9582013-07-10 11:41:44 +01003382}
3383
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003384bool Element::supportsStyleSharing() const
3385{
3386 if (!isStyledElement() || !parentElement())
3387 return false;
3388 // If the element has inline style it is probably unique.
3389 if (inlineStyle())
3390 return false;
3391 if (isSVGElement() && toSVGElement(this)->animatedSMILStyleProperties())
3392 return false;
3393 // Ids stop style sharing if they show up in the stylesheets.
3394 if (hasID() && document().styleResolver()->hasRulesForId(idForStyleResolution()))
3395 return false;
3396 // Active and hovered elements always make a chain towards the document node
3397 // and no siblings or cousins will have the same state.
3398 if (hovered())
3399 return false;
3400 if (active())
3401 return false;
3402 if (focused())
3403 return false;
3404 if (!parentElement()->childrenSupportStyleSharing())
3405 return false;
3406 if (hasScopedHTMLStyleChild())
3407 return false;
3408 if (this == document().cssTarget())
3409 return false;
3410 if (isHTMLElement() && toHTMLElement(this)->hasDirectionAuto())
3411 return false;
3412 if (hasActiveAnimations())
3413 return false;
3414 if (shadow() && shadow()->containsActiveStyles())
3415 return false;
3416 // Turn off style sharing for elements that can gain layers for reasons outside of the style system.
3417 // See comments in RenderObject::setStyle().
3418 // FIXME: Why does gaining a layer from outside the style system require disabling sharing?
3419 if (hasTagName(iframeTag)
3420 || hasTagName(frameTag)
3421 || hasTagName(embedTag)
3422 || hasTagName(objectTag)
3423 || hasTagName(appletTag)
3424 || hasTagName(canvasTag))
3425 return false;
3426 // FIXME: We should share style for option and optgroup whenever possible.
3427 // Before doing so, we need to resolve issues in HTMLSelectElement::recalcListItems
3428 // and RenderMenuList::setText. See also https://bugs.webkit.org/show_bug.cgi?id=88405
3429 if (hasTagName(optionTag) || hasTagName(optgroupTag))
3430 return false;
3431 if (FullscreenElementStack::isActiveFullScreenElement(this))
3432 return false;
3433 return true;
3434}
3435
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003436void ElementData::deref()
3437{
3438 if (!derefBase())
3439 return;
3440
3441 if (m_isUnique)
3442 delete static_cast<UniqueElementData*>(this);
3443 else
3444 delete static_cast<ShareableElementData*>(this);
3445}
3446
3447ElementData::ElementData()
3448 : m_isUnique(true)
3449 , m_arraySize(0)
3450 , m_presentationAttributeStyleIsDirty(false)
3451 , m_styleAttributeIsDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003452 , m_animatedSVGAttributesAreDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003453{
3454}
3455
3456ElementData::ElementData(unsigned arraySize)
3457 : m_isUnique(false)
3458 , m_arraySize(arraySize)
3459 , m_presentationAttributeStyleIsDirty(false)
3460 , m_styleAttributeIsDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003461 , m_animatedSVGAttributesAreDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003462{
3463}
3464
3465struct SameSizeAsElementData : public RefCounted<SameSizeAsElementData> {
3466 unsigned bitfield;
3467 void* refPtrs[3];
3468};
3469
3470COMPILE_ASSERT(sizeof(ElementData) == sizeof(SameSizeAsElementData), element_attribute_data_should_stay_small);
3471
3472static size_t sizeForShareableElementDataWithAttributeCount(unsigned count)
3473{
3474 return sizeof(ShareableElementData) + sizeof(Attribute) * count;
3475}
3476
3477PassRefPtr<ShareableElementData> ShareableElementData::createWithAttributes(const Vector<Attribute>& attributes)
3478{
3479 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(attributes.size()));
3480 return adoptRef(new (slot) ShareableElementData(attributes));
3481}
3482
3483PassRefPtr<UniqueElementData> UniqueElementData::create()
3484{
3485 return adoptRef(new UniqueElementData);
3486}
3487
3488ShareableElementData::ShareableElementData(const Vector<Attribute>& attributes)
3489 : ElementData(attributes.size())
3490{
3491 for (unsigned i = 0; i < m_arraySize; ++i)
3492 new (&m_attributeArray[i]) Attribute(attributes[i]);
3493}
3494
3495ShareableElementData::~ShareableElementData()
3496{
3497 for (unsigned i = 0; i < m_arraySize; ++i)
3498 m_attributeArray[i].~Attribute();
3499}
3500
3501ShareableElementData::ShareableElementData(const UniqueElementData& other)
3502 : ElementData(other, false)
3503{
3504 ASSERT(!other.m_presentationAttributeStyle);
3505
3506 if (other.m_inlineStyle) {
3507 ASSERT(!other.m_inlineStyle->hasCSSOMWrapper());
3508 m_inlineStyle = other.m_inlineStyle->immutableCopyIfNeeded();
3509 }
3510
3511 for (unsigned i = 0; i < m_arraySize; ++i)
3512 new (&m_attributeArray[i]) Attribute(other.m_attributeVector.at(i));
3513}
3514
3515ElementData::ElementData(const ElementData& other, bool isUnique)
3516 : m_isUnique(isUnique)
3517 , m_arraySize(isUnique ? 0 : other.length())
3518 , m_presentationAttributeStyleIsDirty(other.m_presentationAttributeStyleIsDirty)
3519 , m_styleAttributeIsDirty(other.m_styleAttributeIsDirty)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003520 , m_animatedSVGAttributesAreDirty(other.m_animatedSVGAttributesAreDirty)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003521 , m_classNames(other.m_classNames)
3522 , m_idForStyleResolution(other.m_idForStyleResolution)
3523{
3524 // NOTE: The inline style is copied by the subclass copy constructor since we don't know what to do with it here.
3525}
3526
3527UniqueElementData::UniqueElementData()
3528{
3529}
3530
3531UniqueElementData::UniqueElementData(const UniqueElementData& other)
3532 : ElementData(other, true)
3533 , m_presentationAttributeStyle(other.m_presentationAttributeStyle)
3534 , m_attributeVector(other.m_attributeVector)
3535{
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003536 m_inlineStyle = other.m_inlineStyle ? other.m_inlineStyle->mutableCopy() : 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003537}
3538
3539UniqueElementData::UniqueElementData(const ShareableElementData& other)
3540 : ElementData(other, true)
3541{
3542 // An ShareableElementData should never have a mutable inline StylePropertySet attached.
3543 ASSERT(!other.m_inlineStyle || !other.m_inlineStyle->isMutable());
3544 m_inlineStyle = other.m_inlineStyle;
3545
3546 m_attributeVector.reserveCapacity(other.length());
3547 for (unsigned i = 0; i < other.length(); ++i)
3548 m_attributeVector.uncheckedAppend(other.m_attributeArray[i]);
3549}
3550
3551PassRefPtr<UniqueElementData> ElementData::makeUniqueCopy() const
3552{
3553 if (isUnique())
3554 return adoptRef(new UniqueElementData(static_cast<const UniqueElementData&>(*this)));
3555 return adoptRef(new UniqueElementData(static_cast<const ShareableElementData&>(*this)));
3556}
3557
3558PassRefPtr<ShareableElementData> UniqueElementData::makeShareableCopy() const
3559{
3560 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(m_attributeVector.size()));
3561 return adoptRef(new (slot) ShareableElementData(*this));
3562}
3563
3564void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value)
3565{
3566 m_attributeVector.append(Attribute(attributeName, value));
3567}
3568
3569void UniqueElementData::removeAttribute(size_t index)
3570{
3571 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
3572 m_attributeVector.remove(index);
3573}
3574
3575bool ElementData::isEquivalent(const ElementData* other) const
3576{
3577 if (!other)
3578 return isEmpty();
3579
3580 unsigned len = length();
3581 if (len != other->length())
3582 return false;
3583
3584 for (unsigned i = 0; i < len; i++) {
3585 const Attribute* attribute = attributeItem(i);
3586 const Attribute* otherAttr = other->getAttributeItem(attribute->name());
3587 if (!otherAttr || attribute->value() != otherAttr->value())
3588 return false;
3589 }
3590
3591 return true;
3592}
3593
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01003594size_t ElementData::getAttrIndex(Attr* attr) const
3595{
3596 // This relies on the fact that Attr's QualifiedName == the Attribute's name.
3597 for (unsigned i = 0; i < length(); ++i) {
3598 if (attributeItem(i)->name() == attr->qualifiedName())
3599 return i;
3600 }
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01003601 return kNotFound;
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01003602}
3603
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003604size_t ElementData::getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const
3605{
3606 // Continue to checking case-insensitively and/or full namespaced names if necessary:
3607 for (unsigned i = 0; i < length(); ++i) {
3608 const Attribute* attribute = attributeItem(i);
3609 if (!attribute->name().hasPrefix()) {
3610 if (shouldIgnoreAttributeCase && equalIgnoringCase(name, attribute->localName()))
3611 return i;
3612 } else {
3613 // FIXME: Would be faster to do this comparison without calling toString, which
3614 // generates a temporary string by concatenation. But this branch is only reached
3615 // if the attribute name has a prefix, which is rare in HTML.
3616 if (equalPossiblyIgnoringCase(name, attribute->name().toString(), shouldIgnoreAttributeCase))
3617 return i;
3618 }
3619 }
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01003620 return kNotFound;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003621}
3622
3623Attribute* UniqueElementData::getAttributeItem(const QualifiedName& name)
3624{
3625 for (unsigned i = 0; i < length(); ++i) {
3626 if (m_attributeVector.at(i).name().matches(name))
3627 return &m_attributeVector.at(i);
3628 }
3629 return 0;
3630}
3631
3632Attribute* UniqueElementData::attributeItem(unsigned index)
3633{
3634 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
3635 return &m_attributeVector.at(index);
3636}
3637
3638} // namespace WebCore