blob: 8be89e5475e8c58fca172a4f6a5670000592f8c5 [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)53e740f2013-05-09 18:38:43 +010062#include "core/dom/PseudoElement.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010063#include "core/dom/ScriptableDocumentParser.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010064#include "core/dom/SelectorQuery.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010065#include "core/dom/Text.h"
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010066#include "core/dom/WhitespaceChildList.h"
67#include "core/dom/custom/CustomElement.h"
68#include "core/dom/custom/CustomElementRegistrationContext.h"
Torne (Richard Coles)e5249552013-05-15 11:35:13 +010069#include "core/dom/shadow/InsertionPoint.h"
70#include "core/dom/shadow/ShadowRoot.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010071#include "core/editing/FrameSelection.h"
72#include "core/editing/TextIterator.h"
73#include "core/editing/htmlediting.h"
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010074#include "core/events/EventDispatcher.h"
75#include "core/events/FocusEvent.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010076#include "core/html/ClassList.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010077#include "core/html/HTMLCollection.h"
78#include "core/html/HTMLDocument.h"
79#include "core/html/HTMLElement.h"
80#include "core/html/HTMLFormControlsCollection.h"
81#include "core/html/HTMLFrameOwnerElement.h"
82#include "core/html/HTMLLabelElement.h"
83#include "core/html/HTMLOptionsCollection.h"
84#include "core/html/HTMLTableRowsCollection.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010085#include "core/html/parser/HTMLParserIdioms.h"
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010086#include "core/frame/ContentSecurityPolicy.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010087#include "core/page/FocusController.h"
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010088#include "core/frame/Frame.h"
89#include "core/frame/FrameView.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010090#include "core/page/Page.h"
91#include "core/page/PointerLockController.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010092#include "core/rendering/FlowThreadController.h"
93#include "core/rendering/RenderRegion.h"
94#include "core/rendering/RenderView.h"
95#include "core/rendering/RenderWidget.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010096#include "core/svg/SVGDocumentExtensions.h"
97#include "core/svg/SVGElement.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010098#include "wtf/BitVector.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010099#include "wtf/HashFunctions.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100100#include "wtf/text/CString.h"
Ben Murdoch591b9582013-07-10 11:41:44 +0100101#include "wtf/text/TextPosition.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100102
103namespace WebCore {
104
105using namespace HTMLNames;
106using namespace XMLNames;
107
108static inline bool shouldIgnoreAttributeCase(const Element* e)
109{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100110 return e && e->document().isHTMLDocument() && e->isHTMLElement();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100111}
Ben Murdoch591b9582013-07-10 11:41:44 +0100112
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100113class StyleResolverParentPusher {
114public:
115 StyleResolverParentPusher(Element* parent)
116 : m_parent(parent)
117 , m_pushedStyleResolver(0)
118 {
119 }
120 void push()
121 {
122 if (m_pushedStyleResolver)
123 return;
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100124 m_pushedStyleResolver = m_parent->document().styleResolver();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100125 m_pushedStyleResolver->pushParentElement(m_parent);
126 }
127 ~StyleResolverParentPusher()
128 {
129
130 if (!m_pushedStyleResolver)
131 return;
132
133 // This tells us that our pushed style selector is in a bad state,
134 // so we should just bail out in that scenario.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100135 ASSERT(m_pushedStyleResolver == m_parent->document().styleResolver());
136 if (m_pushedStyleResolver != m_parent->document().styleResolver())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100137 return;
138
139 m_pushedStyleResolver->popParentElement(m_parent);
140 }
141
142private:
143 Element* m_parent;
144 StyleResolver* m_pushedStyleResolver;
145};
146
147typedef Vector<RefPtr<Attr> > AttrNodeList;
148typedef HashMap<Element*, OwnPtr<AttrNodeList> > AttrNodeListMap;
149
150static AttrNodeListMap& attrNodeListMap()
151{
152 DEFINE_STATIC_LOCAL(AttrNodeListMap, map, ());
153 return map;
154}
155
156static AttrNodeList* attrNodeListForElement(Element* element)
157{
158 if (!element->hasSyntheticAttrChildNodes())
159 return 0;
160 ASSERT(attrNodeListMap().contains(element));
161 return attrNodeListMap().get(element);
162}
163
164static AttrNodeList* ensureAttrNodeListForElement(Element* element)
165{
166 if (element->hasSyntheticAttrChildNodes()) {
167 ASSERT(attrNodeListMap().contains(element));
168 return attrNodeListMap().get(element);
169 }
170 ASSERT(!attrNodeListMap().contains(element));
171 element->setHasSyntheticAttrChildNodes(true);
172 AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList));
173 return result.iterator->value.get();
174}
175
176static void removeAttrNodeListForElement(Element* element)
177{
178 ASSERT(element->hasSyntheticAttrChildNodes());
179 ASSERT(attrNodeListMap().contains(element));
180 attrNodeListMap().remove(element);
181 element->setHasSyntheticAttrChildNodes(false);
182}
183
184static Attr* findAttrNodeInList(AttrNodeList* attrNodeList, const QualifiedName& name)
185{
186 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
187 if (attrNodeList->at(i)->qualifiedName() == name)
188 return attrNodeList->at(i).get();
189 }
190 return 0;
191}
192
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100193PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document)
194{
195 return adoptRef(new Element(tagName, document, CreateElement));
196}
197
198Element::~Element()
199{
200#ifndef NDEBUG
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100201 if (document().renderer()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100202 // When the document is not destroyed, an element that was part of a named flow
203 // content nodes should have been removed from the content nodes collection
204 // and the inNamedFlow flag reset.
205 ASSERT(!inNamedFlow());
206 }
207#endif
208
Ben Murdoch591b9582013-07-10 11:41:44 +0100209 if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
210 cssomWrapper->clearParentElement();
211
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100212 if (hasRareData()) {
213 ElementRareData* data = elementRareData();
214 data->setPseudoElement(BEFORE, 0);
215 data->setPseudoElement(AFTER, 0);
Ben Murdoche69819b2013-07-17 14:56:49 +0100216 data->setPseudoElement(BACKDROP, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100217 data->clearShadow();
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100218
219 if (RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
220 if (ActiveAnimations* activeAnimations = data->activeAnimations())
221 activeAnimations->cssAnimations()->cancel();
222 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100223 }
224
Ben Murdoch83750172013-07-24 10:36:59 +0100225 if (isCustomElement())
226 CustomElement::wasDestroyed(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100227
228 if (hasSyntheticAttrChildNodes())
229 detachAllAttrNodesFromElement();
230
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100231 if (hasPendingResources()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100232 document().accessSVGExtensions()->removeElementFromPendingResources(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100233 ASSERT(!hasPendingResources());
234 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100235}
236
237inline ElementRareData* Element::elementRareData() const
238{
239 ASSERT(hasRareData());
240 return static_cast<ElementRareData*>(rareData());
241}
242
243inline ElementRareData* Element::ensureElementRareData()
244{
245 return static_cast<ElementRareData*>(ensureRareData());
246}
247
248void Element::clearTabIndexExplicitlyIfNeeded()
249{
250 if (hasRareData())
251 elementRareData()->clearTabIndexExplicitly();
252}
253
254void Element::setTabIndexExplicitly(short tabIndex)
255{
256 ensureElementRareData()->setTabIndexExplicitly(tabIndex);
257}
258
259bool Element::supportsFocus() const
260{
261 return hasRareData() && elementRareData()->tabIndexSetExplicitly();
262}
263
264short Element::tabIndex() const
265{
266 return hasRareData() ? elementRareData()->tabIndex() : 0;
267}
268
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100269bool Element::rendererIsFocusable() const
270{
271 // Elements in canvas fallback content are not rendered, but they are allowed to be
272 // focusable as long as their canvas is displayed and visible.
273 if (isInCanvasSubtree()) {
274 const Element* e = this;
275 while (e && !e->hasLocalName(canvasTag))
276 e = e->parentElement();
277 ASSERT(e);
278 return e->renderer() && e->renderer()->style()->visibility() == VISIBLE;
279 }
280
281 // FIXME: These asserts should be in Node::isFocusable, but there are some
Ben Murdoche69819b2013-07-17 14:56:49 +0100282 // callsites like Document::setFocusedElement that would currently fail on
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100283 // them. See crbug.com/251163
284 if (renderer()) {
285 ASSERT(!renderer()->needsLayout());
286 } else {
287 // We can't just use needsStyleRecalc() because if the node is in a
288 // display:none tree it might say it needs style recalc but the whole
289 // document is actually up to date.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100290 ASSERT(!document().childNeedsStyleRecalc());
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100291 }
292
293 // FIXME: Even if we are not visible, we might have a child that is visible.
294 // Hyatt wants to fix that some day with a "has visible content" flag or the like.
295 if (!renderer() || renderer()->style()->visibility() != VISIBLE)
296 return false;
297
298 return true;
299}
300
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100301DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, blur);
302DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, error);
303DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, focus);
304DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, load);
305
306PassRefPtr<Node> Element::cloneNode(bool deep)
307{
308 return deep ? cloneElementWithChildren() : cloneElementWithoutChildren();
309}
310
311PassRefPtr<Element> Element::cloneElementWithChildren()
312{
313 RefPtr<Element> clone = cloneElementWithoutChildren();
314 cloneChildNodes(clone.get());
315 return clone.release();
316}
317
318PassRefPtr<Element> Element::cloneElementWithoutChildren()
319{
320 RefPtr<Element> clone = cloneElementWithoutAttributesAndChildren();
321 // This will catch HTML elements in the wrong namespace that are not correctly copied.
322 // This is a sanity check as HTML overloads some of the DOM methods.
323 ASSERT(isHTMLElement() == clone->isHTMLElement());
324
325 clone->cloneDataFromElement(*this);
326 return clone.release();
327}
328
329PassRefPtr<Element> Element::cloneElementWithoutAttributesAndChildren()
330{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100331 return document().createElement(tagQName(), false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100332}
333
334PassRefPtr<Attr> Element::detachAttribute(size_t index)
335{
336 ASSERT(elementData());
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100337 const Attribute* attribute = elementData()->attributeItem(index);
338 RefPtr<Attr> attrNode = attrIfExists(attribute->name());
339 if (attrNode)
340 detachAttrNodeAtIndex(attrNode.get(), index);
341 else {
342 attrNode = Attr::create(document(), attribute->name(), attribute->value());
343 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
344 }
345 return attrNode.release();
346}
347
348void Element::detachAttrNodeAtIndex(Attr* attr, size_t index)
349{
350 ASSERT(attr);
351 ASSERT(elementData());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100352
353 const Attribute* attribute = elementData()->attributeItem(index);
354 ASSERT(attribute);
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100355 ASSERT(attribute->name() == attr->qualifiedName());
356 detachAttrNodeFromElementWithValue(attr, attribute->value());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100357 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100358}
359
360void Element::removeAttribute(const QualifiedName& name)
361{
362 if (!elementData())
363 return;
364
365 size_t index = elementData()->getAttributeItemIndex(name);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100366 if (index == kNotFound)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100367 return;
368
369 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
370}
371
372void Element::setBooleanAttribute(const QualifiedName& name, bool value)
373{
374 if (value)
375 setAttribute(name, emptyAtom);
376 else
377 removeAttribute(name);
378}
379
380NamedNodeMap* Element::attributes() const
381{
382 ElementRareData* rareData = const_cast<Element*>(this)->ensureElementRareData();
383 if (NamedNodeMap* attributeMap = rareData->attributeMap())
384 return attributeMap;
385
386 rareData->setAttributeMap(NamedNodeMap::create(const_cast<Element*>(this)));
387 return rareData->attributeMap();
388}
389
Ben Murdoch83750172013-07-24 10:36:59 +0100390ActiveAnimations* Element::activeAnimations() const
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100391{
Ben Murdoch83750172013-07-24 10:36:59 +0100392 if (hasActiveAnimations())
393 return elementRareData()->activeAnimations();
394 return 0;
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100395}
396
Ben Murdoch83750172013-07-24 10:36:59 +0100397ActiveAnimations* Element::ensureActiveAnimations()
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100398{
Ben Murdoch83750172013-07-24 10:36:59 +0100399 ElementRareData* rareData = ensureElementRareData();
400 if (!elementRareData()->activeAnimations())
401 rareData->setActiveAnimations(adoptPtr(new ActiveAnimations()));
402 return rareData->activeAnimations();
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100403}
404
405bool Element::hasActiveAnimations() const
406{
Ben Murdoch83750172013-07-24 10:36:59 +0100407 if (!RuntimeEnabledFeatures::webAnimationsEnabled())
408 return false;
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100409
Ben Murdoch83750172013-07-24 10:36:59 +0100410 if (!hasRareData())
411 return false;
412
413 ActiveAnimations* activeAnimations = elementRareData()->activeAnimations();
414 return activeAnimations && !activeAnimations->isEmpty();
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100415}
416
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100417Node::NodeType Element::nodeType() const
418{
419 return ELEMENT_NODE;
420}
421
422bool Element::hasAttribute(const QualifiedName& name) const
423{
424 return hasAttributeNS(name.namespaceURI(), name.localName());
425}
426
427void Element::synchronizeAllAttributes() const
428{
429 if (!elementData())
430 return;
431 if (elementData()->m_styleAttributeIsDirty) {
432 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100433 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100434 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100435 if (elementData()->m_animatedSVGAttributesAreDirty) {
436 ASSERT(isSVGElement());
437 toSVGElement(this)->synchronizeAnimatedSVGAttribute(anyQName());
438 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100439}
440
441inline void Element::synchronizeAttribute(const QualifiedName& name) const
442{
443 if (!elementData())
444 return;
445 if (UNLIKELY(name == styleAttr && elementData()->m_styleAttributeIsDirty)) {
446 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100447 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100448 return;
449 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100450 if (UNLIKELY(elementData()->m_animatedSVGAttributesAreDirty)) {
451 ASSERT(isSVGElement());
452 toSVGElement(this)->synchronizeAnimatedSVGAttribute(name);
453 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100454}
455
456inline void Element::synchronizeAttribute(const AtomicString& localName) const
457{
458 // This version of synchronizeAttribute() is streamlined for the case where you don't have a full QualifiedName,
459 // e.g when called from DOM API.
460 if (!elementData())
461 return;
462 if (elementData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(localName, styleAttr.localName(), shouldIgnoreAttributeCase(this))) {
463 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100464 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100465 return;
466 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100467 if (elementData()->m_animatedSVGAttributesAreDirty) {
468 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
469 ASSERT(isSVGElement());
470 static_cast<const SVGElement*>(this)->synchronizeAnimatedSVGAttribute(QualifiedName(nullAtom, localName, nullAtom));
471 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100472}
473
474const AtomicString& Element::getAttribute(const QualifiedName& name) const
475{
476 if (!elementData())
477 return nullAtom;
478 synchronizeAttribute(name);
479 if (const Attribute* attribute = getAttributeItem(name))
480 return attribute->value();
481 return nullAtom;
482}
483
Ben Murdoch591b9582013-07-10 11:41:44 +0100484void Element::scrollIntoView(bool alignToTop)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100485{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100486 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100487
488 if (!renderer())
489 return;
490
491 LayoutRect bounds = boundingBox();
492 // Align to the top / bottom and to the closest edge.
493 if (alignToTop)
494 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
495 else
496 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
497}
498
499void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
500{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100501 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100502
503 if (!renderer())
504 return;
505
506 LayoutRect bounds = boundingBox();
507 if (centerIfNeeded)
508 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
509 else
510 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
511}
512
513void Element::scrollByUnits(int units, ScrollGranularity granularity)
514{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100515 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100516
517 if (!renderer())
518 return;
519
520 if (!renderer()->hasOverflowClip())
521 return;
522
523 ScrollDirection direction = ScrollDown;
524 if (units < 0) {
525 direction = ScrollUp;
526 units = -units;
527 }
528 Node* stopNode = this;
529 toRenderBox(renderer())->scroll(direction, granularity, units, &stopNode);
530}
531
532void Element::scrollByLines(int lines)
533{
534 scrollByUnits(lines, ScrollByLine);
535}
536
537void Element::scrollByPages(int pages)
538{
539 scrollByUnits(pages, ScrollByPage);
540}
541
542static float localZoomForRenderer(RenderObject* renderer)
543{
544 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
545 // other out, but the alternative is that we'd have to crawl up the whole render tree every
546 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
547 float zoomFactor = 1;
548 if (renderer->style()->effectiveZoom() != 1) {
549 // Need to find the nearest enclosing RenderObject that set up
550 // a differing zoom, and then we divide our result by it to eliminate the zoom.
551 RenderObject* prev = renderer;
552 for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) {
553 if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) {
554 zoomFactor = prev->style()->zoom();
555 break;
556 }
557 prev = curr;
558 }
559 if (prev->isRenderView())
560 zoomFactor = prev->style()->zoom();
561 }
562 return zoomFactor;
563}
564
565static int adjustForLocalZoom(LayoutUnit value, RenderObject* renderer)
566{
567 float zoomFactor = localZoomForRenderer(renderer);
568 if (zoomFactor == 1)
569 return value;
570 return lroundf(value / zoomFactor);
571}
572
573int Element::offsetLeft()
574{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100575 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100576 if (RenderBoxModelObject* renderer = renderBoxModelObject())
577 return adjustForLocalZoom(renderer->pixelSnappedOffsetLeft(), renderer);
578 return 0;
579}
580
581int Element::offsetTop()
582{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100583 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100584 if (RenderBoxModelObject* renderer = renderBoxModelObject())
585 return adjustForLocalZoom(renderer->pixelSnappedOffsetTop(), renderer);
586 return 0;
587}
588
589int Element::offsetWidth()
590{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100591 document().updateStyleForNodeIfNeeded(this);
Ben Murdoch591b9582013-07-10 11:41:44 +0100592
593 if (RenderBox* renderer = renderBox()) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100594 if (renderer->canDetermineWidthWithoutLayout())
Ben Murdoch591b9582013-07-10 11:41:44 +0100595 return adjustLayoutUnitForAbsoluteZoom(renderer->fixedOffsetWidth(), renderer).round();
596 }
597
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100598 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100599 if (RenderBoxModelObject* renderer = renderBoxModelObject())
600 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetWidth(), renderer).round();
601 return 0;
602}
603
604int Element::offsetHeight()
605{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100606 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100607 if (RenderBoxModelObject* renderer = renderBoxModelObject())
608 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetHeight(), renderer).round();
609 return 0;
610}
611
612Element* Element::bindingsOffsetParent()
613{
614 Element* element = offsetParent();
615 if (!element || !element->isInShadowTree())
616 return element;
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100617 return element->containingShadowRoot()->shouldExposeToBindings() ? element : 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100618}
619
620Element* Element::offsetParent()
621{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100622 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100623 if (RenderObject* renderer = this->renderer())
624 return renderer->offsetParent();
625 return 0;
626}
627
628int Element::clientLeft()
629{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100630 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100631
632 if (RenderBox* renderer = renderBox())
633 return adjustForAbsoluteZoom(roundToInt(renderer->clientLeft()), renderer);
634 return 0;
635}
636
637int Element::clientTop()
638{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100639 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100640
641 if (RenderBox* renderer = renderBox())
642 return adjustForAbsoluteZoom(roundToInt(renderer->clientTop()), renderer);
643 return 0;
644}
645
646int Element::clientWidth()
647{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100648 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100649
650 // When in strict mode, clientWidth for the document element should return the width of the containing frame.
651 // 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 +0100652 bool inQuirksMode = document().inQuirksMode();
653 if ((!inQuirksMode && document().documentElement() == this)
654 || (inQuirksMode && isHTMLElement() && document().body() == this)) {
655 if (FrameView* view = document().view()) {
656 if (RenderView* renderView = document().renderView())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100657 return adjustForAbsoluteZoom(view->layoutWidth(), renderView);
658 }
659 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100660
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100661 if (RenderBox* renderer = renderBox())
662 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientWidth(), renderer).round();
663 return 0;
664}
665
666int Element::clientHeight()
667{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100668 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100669
670 // When in strict mode, clientHeight for the document element should return the height of the containing frame.
671 // 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 +0100672 bool inQuirksMode = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100673
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100674 if ((!inQuirksMode && document().documentElement() == this)
675 || (inQuirksMode && isHTMLElement() && document().body() == this)) {
676 if (FrameView* view = document().view()) {
677 if (RenderView* renderView = document().renderView())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100678 return adjustForAbsoluteZoom(view->layoutHeight(), renderView);
679 }
680 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100681
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100682 if (RenderBox* renderer = renderBox())
683 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientHeight(), renderer).round();
684 return 0;
685}
686
687int Element::scrollLeft()
688{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100689 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100690
691 if (document().documentElement() == this) {
692 if (document().inQuirksMode())
693 return 0;
694
695 if (FrameView* view = document().view()) {
696 if (RenderView* renderView = document().renderView())
697 return adjustForAbsoluteZoom(view->scrollX(), renderView);
698 }
699 }
700
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100701 if (RenderBox* rend = renderBox())
702 return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
703 return 0;
704}
705
706int Element::scrollTop()
707{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100708 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100709
710 if (document().documentElement() == this) {
711 if (document().inQuirksMode())
712 return 0;
713
714 if (FrameView* view = document().view()) {
715 if (RenderView* renderView = document().renderView())
716 return adjustForAbsoluteZoom(view->scrollY(), renderView);
717 }
718 }
719
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100720 if (RenderBox* rend = renderBox())
721 return adjustForAbsoluteZoom(rend->scrollTop(), rend);
722 return 0;
723}
724
725void Element::setScrollLeft(int newLeft)
726{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100727 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100728
729 if (document().documentElement() == this) {
730 if (document().inQuirksMode())
731 return;
732
733 Frame* frame = document().frame();
734 if (!frame)
735 return;
736 FrameView* view = frame->view();
737 if (!view)
738 return;
739
740 // WHATWG spec says [1]: "If the element is the root element invoke scroll()
741 // with x as first argument and zero as second". Blink intentionally matches
742 // other engine's behaviors here, instead, where the 'y' scroll position is
743 // preversed. See [2].
744 // [1] http://dev.w3.org/csswg/cssom-view/#dom-element-scrollleft
745 // [2] https://www.w3.org/Bugs/Public/show_bug.cgi?id=23448
746 view->setScrollPosition(IntPoint(static_cast<int>(newLeft * frame->pageZoomFactor()), view->scrollY()));
747 }
748
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100749 if (RenderBox* rend = renderBox())
750 rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
751}
752
753void Element::setScrollTop(int newTop)
754{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100755 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100756
757 if (document().documentElement() == this) {
758 if (document().inQuirksMode())
759 return;
760
761 Frame* frame = document().frame();
762 if (!frame)
763 return;
764 FrameView* view = frame->view();
765 if (!view)
766 return;
767
768 // WHATWG spec says [1]: "If the element is the root element invoke scroll()
769 // with zero as first argument and y as second". Blink intentionally
770 // matches other engine's behaviors here, instead, where the 'x' scroll
771 // position is preversed. See [2].
772 // [1] http://dev.w3.org/csswg/cssom-view/#dom-element-scrolltop
773 // [2] https://www.w3.org/Bugs/Public/show_bug.cgi?id=23448
774 view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(newTop * frame->pageZoomFactor())));
775 }
776
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100777 if (RenderBox* rend = renderBox())
778 rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
779}
780
781int Element::scrollWidth()
782{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100783 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100784 if (RenderBox* rend = renderBox())
785 return adjustForAbsoluteZoom(rend->scrollWidth(), rend);
786 return 0;
787}
788
789int Element::scrollHeight()
790{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100791 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100792 if (RenderBox* rend = renderBox())
793 return adjustForAbsoluteZoom(rend->scrollHeight(), rend);
794 return 0;
795}
796
797IntRect Element::boundsInRootViewSpace()
798{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100799 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100800
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100801 FrameView* view = document().view();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100802 if (!view)
803 return IntRect();
804
805 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100806 if (isSVGElement() && renderer()) {
807 // Get the bounding rectangle from the SVG model.
808 SVGElement* svgElement = toSVGElement(this);
809 FloatRect localRect;
810 if (svgElement->getBoundingBox(localRect))
811 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100812 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100813 // Get the bounding rectangle from the box model.
814 if (renderBoxModelObject())
815 renderBoxModelObject()->absoluteQuads(quads);
816 }
817
818 if (quads.isEmpty())
819 return IntRect();
820
821 IntRect result = quads[0].enclosingBoundingBox();
822 for (size_t i = 1; i < quads.size(); ++i)
823 result.unite(quads[i].enclosingBoundingBox());
824
825 result = view->contentsToRootView(result);
826 return result;
827}
828
829PassRefPtr<ClientRectList> Element::getClientRects()
830{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100831 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100832
833 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject();
834 if (!renderBoxModelObject)
835 return ClientRectList::create();
836
837 // FIXME: Handle SVG elements.
838 // FIXME: Handle table/inline-table with a caption.
839
840 Vector<FloatQuad> quads;
841 renderBoxModelObject->absoluteQuads(quads);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100842 document().adjustFloatQuadsForScrollAndAbsoluteZoom(quads, renderBoxModelObject);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100843 return ClientRectList::create(quads);
844}
845
846PassRefPtr<ClientRect> Element::getBoundingClientRect()
847{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100848 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100849
850 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100851 if (isSVGElement() && renderer() && !renderer()->isSVGRoot()) {
852 // Get the bounding rectangle from the SVG model.
853 SVGElement* svgElement = toSVGElement(this);
854 FloatRect localRect;
855 if (svgElement->getBoundingBox(localRect))
856 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100857 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100858 // Get the bounding rectangle from the box model.
859 if (renderBoxModelObject())
860 renderBoxModelObject()->absoluteQuads(quads);
861 }
862
863 if (quads.isEmpty())
864 return ClientRect::create();
865
866 FloatRect result = quads[0].boundingBox();
867 for (size_t i = 1; i < quads.size(); ++i)
868 result.unite(quads[i].boundingBox());
869
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100870 document().adjustFloatRectForScrollAndAbsoluteZoom(result, renderer());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100871 return ClientRect::create(result);
872}
Ben Murdoch591b9582013-07-10 11:41:44 +0100873
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100874IntRect Element::screenRect() const
875{
876 if (!renderer())
877 return IntRect();
878 // FIXME: this should probably respect transforms
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100879 return document().view()->contentsToScreen(renderer()->absoluteBoundingBoxRectIgnoringTransforms());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100880}
881
882const AtomicString& Element::getAttribute(const AtomicString& localName) const
883{
884 if (!elementData())
885 return nullAtom;
886 synchronizeAttribute(localName);
887 if (const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase(this)))
888 return attribute->value();
889 return nullAtom;
890}
891
892const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
893{
894 return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
895}
896
Ben Murdochdf957042013-08-06 11:01:27 +0100897void Element::setAttribute(const AtomicString& localName, const AtomicString& value, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100898{
899 if (!Document::isValidName(localName)) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100900 es.throwUninformativeAndGenericDOMException(InvalidCharacterError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100901 return;
902 }
903
904 synchronizeAttribute(localName);
905 const AtomicString& caseAdjustedLocalName = shouldIgnoreAttributeCase(this) ? localName.lower() : localName;
906
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100907 size_t index = elementData() ? elementData()->getAttributeItemIndex(caseAdjustedLocalName, false) : kNotFound;
908 const QualifiedName& qName = index != kNotFound ? attributeItem(index)->name() : QualifiedName(nullAtom, caseAdjustedLocalName, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100909 setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute);
910}
911
912void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
913{
914 synchronizeAttribute(name);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100915 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : kNotFound;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100916 setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute);
917}
918
919void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value)
920{
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100921 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : kNotFound;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100922 setAttributeInternal(index, name, value, InSynchronizationOfLazyAttribute);
923}
924
925inline void Element::setAttributeInternal(size_t index, const QualifiedName& name, const AtomicString& newValue, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
926{
927 if (newValue.isNull()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100928 if (index != kNotFound)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100929 removeAttributeInternal(index, inSynchronizationOfLazyAttribute);
930 return;
931 }
932
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100933 if (index == kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100934 addAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute);
935 return;
936 }
937
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100938 QualifiedName existingAttributeName = attributeItem(index)->name();
939
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100940 if (!inSynchronizationOfLazyAttribute)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100941 willModifyAttribute(existingAttributeName, attributeItem(index)->value(), newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100942
943 if (newValue != attributeItem(index)->value()) {
944 // If there is an Attr node hooked to this attribute, the Attr::setValue() call below
945 // will write into the ElementData.
946 // FIXME: Refactor this so it makes some sense.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100947 if (RefPtr<Attr> attrNode = inSynchronizationOfLazyAttribute ? 0 : attrIfExists(existingAttributeName))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100948 attrNode->setValue(newValue);
949 else
950 ensureUniqueElementData()->attributeItem(index)->setValue(newValue);
951 }
952
953 if (!inSynchronizationOfLazyAttribute)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100954 didModifyAttribute(existingAttributeName, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100955}
956
957static inline AtomicString makeIdForStyleResolution(const AtomicString& value, bool inQuirksMode)
958{
959 if (inQuirksMode)
960 return value.lower();
961 return value;
962}
963
Ben Murdoch7757ec22013-07-23 11:17:36 +0100964static bool checkNeedsStyleInvalidationForIdChange(const AtomicString& oldId, const AtomicString& newId, const RuleFeatureSet& features)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100965{
966 ASSERT(newId != oldId);
Ben Murdoch7757ec22013-07-23 11:17:36 +0100967 if (!oldId.isEmpty() && features.hasSelectorForId(oldId))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100968 return true;
Ben Murdoch7757ec22013-07-23 11:17:36 +0100969 if (!newId.isEmpty() && features.hasSelectorForId(newId))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100970 return true;
971 return false;
972}
973
Ben Murdoch591b9582013-07-10 11:41:44 +0100974void Element::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100975{
976 if (ElementShadow* parentElementShadow = shadowOfParentForDistribution(this)) {
977 if (shouldInvalidateDistributionWhenAttributeChanged(parentElementShadow, name, newValue))
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100978 parentElementShadow->setNeedsDistributionRecalc();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100979 }
980
981 parseAttribute(name, newValue);
982
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100983 document().incDOMTreeVersion();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100984
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100985 StyleResolver* styleResolver = document().styleResolverIfExists();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100986 bool testShouldInvalidateStyle = confusingAndOftenMisusedAttached() && styleResolver && styleChangeType() < SubtreeStyleChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100987 bool shouldInvalidateStyle = false;
988
Ben Murdoch591b9582013-07-10 11:41:44 +0100989 if (isStyledElement() && name == styleAttr) {
990 styleAttributeChanged(newValue, reason);
991 } else if (isStyledElement() && isPresentationAttribute(name)) {
992 elementData()->m_presentationAttributeStyleIsDirty = true;
Ben Murdoche69819b2013-07-17 14:56:49 +0100993 setNeedsStyleRecalc(LocalStyleChange);
Ben Murdoch591b9582013-07-10 11:41:44 +0100994 }
995
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100996 if (isIdAttributeName(name)) {
997 AtomicString oldId = elementData()->idForStyleResolution();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100998 AtomicString newId = makeIdForStyleResolution(newValue, document().inQuirksMode());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100999 if (newId != oldId) {
1000 elementData()->setIdForStyleResolution(newId);
Ben Murdoch7757ec22013-07-23 11:17:36 +01001001 shouldInvalidateStyle = testShouldInvalidateStyle && checkNeedsStyleInvalidationForIdChange(oldId, newId, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001002 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001003 } else if (name == classAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001004 classAttributeChanged(newValue);
Ben Murdoch591b9582013-07-10 11:41:44 +01001005 } else if (name == HTMLNames::nameAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001006 setHasName(!newValue.isNull());
Ben Murdoch591b9582013-07-10 11:41:44 +01001007 } else if (name == HTMLNames::pseudoAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001008 shouldInvalidateStyle |= testShouldInvalidateStyle && isInShadowTree();
Ben Murdoch591b9582013-07-10 11:41:44 +01001009 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001010
1011 invalidateNodeListCachesInAncestors(&name, this);
1012
1013 // If there is currently no StyleResolver, we can't be sure that this attribute change won't affect style.
1014 shouldInvalidateStyle |= !styleResolver;
1015
1016 if (shouldInvalidateStyle)
1017 setNeedsStyleRecalc();
1018
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001019 if (AXObjectCache* cache = document().existingAXObjectCache())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001020 cache->handleAttributeChanged(name, this);
1021}
1022
1023inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
1024{
Ben Murdoche69819b2013-07-17 14:56:49 +01001025 if (name == isAttr)
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001026 CustomElementRegistrationContext::setTypeExtension(this, newValue, reason == ModifiedDirectly ? CustomElementRegistrationContext::CreatedByParser : CustomElementRegistrationContext::NotCreatedByParser);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001027 attributeChanged(name, newValue, reason);
1028}
1029
1030template <typename CharacterType>
1031static inline bool classStringHasClassName(const CharacterType* characters, unsigned length)
1032{
1033 ASSERT(length > 0);
1034
1035 unsigned i = 0;
1036 do {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001037 if (isNotHTMLSpace<CharacterType>(characters[i]))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001038 break;
1039 ++i;
1040 } while (i < length);
1041
1042 return i < length;
1043}
1044
1045static inline bool classStringHasClassName(const AtomicString& newClassString)
1046{
1047 unsigned length = newClassString.length();
1048
1049 if (!length)
1050 return false;
1051
1052 if (newClassString.is8Bit())
1053 return classStringHasClassName(newClassString.characters8(), length);
1054 return classStringHasClassName(newClassString.characters16(), length);
1055}
1056
1057template<typename Checker>
1058static bool checkSelectorForClassChange(const SpaceSplitString& changedClasses, const Checker& checker)
1059{
1060 unsigned changedSize = changedClasses.size();
1061 for (unsigned i = 0; i < changedSize; ++i) {
1062 if (checker.hasSelectorForClass(changedClasses[i]))
1063 return true;
1064 }
1065 return false;
1066}
1067
1068template<typename Checker>
1069static bool checkSelectorForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, const Checker& checker)
1070{
1071 unsigned oldSize = oldClasses.size();
1072 if (!oldSize)
1073 return checkSelectorForClassChange(newClasses, checker);
1074 BitVector remainingClassBits;
1075 remainingClassBits.ensureSize(oldSize);
1076 // Class vectors tend to be very short. This is faster than using a hash table.
1077 unsigned newSize = newClasses.size();
1078 for (unsigned i = 0; i < newSize; ++i) {
1079 for (unsigned j = 0; j < oldSize; ++j) {
1080 if (newClasses[i] == oldClasses[j]) {
1081 remainingClassBits.quickSet(j);
1082 continue;
1083 }
1084 }
1085 if (checker.hasSelectorForClass(newClasses[i]))
1086 return true;
1087 }
1088 for (unsigned i = 0; i < oldSize; ++i) {
1089 // If the bit is not set the the corresponding class has been removed.
1090 if (remainingClassBits.quickGet(i))
1091 continue;
1092 if (checker.hasSelectorForClass(oldClasses[i]))
1093 return true;
1094 }
1095 return false;
1096}
1097
1098void Element::classAttributeChanged(const AtomicString& newClassString)
1099{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001100 StyleResolver* styleResolver = document().styleResolverIfExists();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001101 bool testShouldInvalidateStyle = confusingAndOftenMisusedAttached() && styleResolver && styleChangeType() < SubtreeStyleChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001102 bool shouldInvalidateStyle = false;
1103
1104 if (classStringHasClassName(newClassString)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001105 const bool shouldFoldCase = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001106 const SpaceSplitString oldClasses = elementData()->classNames();
1107 elementData()->setClass(newClassString, shouldFoldCase);
1108 const SpaceSplitString& newClasses = elementData()->classNames();
Ben Murdoch7757ec22013-07-23 11:17:36 +01001109 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, newClasses, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001110 } else {
1111 const SpaceSplitString& oldClasses = elementData()->classNames();
Ben Murdoch7757ec22013-07-23 11:17:36 +01001112 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001113 elementData()->clearClass();
1114 }
1115
1116 if (hasRareData())
1117 elementRareData()->clearClassListValueForQuirksMode();
1118
1119 if (shouldInvalidateStyle)
1120 setNeedsStyleRecalc();
1121}
1122
1123bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
1124{
1125 ASSERT(elementShadow);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001126 const SelectRuleFeatureSet& featureSet = elementShadow->ensureSelectFeatureSet();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001127
1128 if (isIdAttributeName(name)) {
1129 AtomicString oldId = elementData()->idForStyleResolution();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001130 AtomicString newId = makeIdForStyleResolution(newValue, document().inQuirksMode());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001131 if (newId != oldId) {
1132 if (!oldId.isEmpty() && featureSet.hasSelectorForId(oldId))
1133 return true;
1134 if (!newId.isEmpty() && featureSet.hasSelectorForId(newId))
1135 return true;
1136 }
1137 }
1138
1139 if (name == HTMLNames::classAttr) {
1140 const AtomicString& newClassString = newValue;
1141 if (classStringHasClassName(newClassString)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001142 const bool shouldFoldCase = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001143 const SpaceSplitString& oldClasses = elementData()->classNames();
1144 const SpaceSplitString newClasses(newClassString, shouldFoldCase);
1145 if (checkSelectorForClassChange(oldClasses, newClasses, featureSet))
1146 return true;
1147 } else {
1148 const SpaceSplitString& oldClasses = elementData()->classNames();
1149 if (checkSelectorForClassChange(oldClasses, featureSet))
1150 return true;
1151 }
1152 }
1153
1154 return featureSet.hasSelectorForAttribute(name.localName());
1155}
1156
1157// Returns true is the given attribute is an event handler.
1158// We consider an event handler any attribute that begins with "on".
1159// It is a simple solution that has the advantage of not requiring any
1160// code or configuration change if a new event handler is defined.
1161
1162static inline bool isEventHandlerAttribute(const Attribute& attribute)
1163{
1164 return attribute.name().namespaceURI().isNull() && attribute.name().localName().startsWith("on");
1165}
1166
1167bool Element::isJavaScriptURLAttribute(const Attribute& attribute) const
1168{
1169 return isURLAttribute(attribute) && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(attribute.value()));
1170}
1171
1172void Element::stripScriptingAttributes(Vector<Attribute>& attributeVector) const
1173{
1174 size_t destination = 0;
1175 for (size_t source = 0; source < attributeVector.size(); ++source) {
1176 if (isEventHandlerAttribute(attributeVector[source])
1177 || isJavaScriptURLAttribute(attributeVector[source])
1178 || isHTMLContentAttribute(attributeVector[source]))
1179 continue;
1180
1181 if (source != destination)
1182 attributeVector[destination] = attributeVector[source];
1183
1184 ++destination;
1185 }
1186 attributeVector.shrink(destination);
1187}
1188
1189void Element::parserSetAttributes(const Vector<Attribute>& attributeVector)
1190{
1191 ASSERT(!inDocument());
1192 ASSERT(!parentNode());
1193 ASSERT(!m_elementData);
1194
1195 if (attributeVector.isEmpty())
1196 return;
1197
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001198 if (document().sharedObjectPool())
1199 m_elementData = document().sharedObjectPool()->cachedShareableElementDataWithAttributes(attributeVector);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001200 else
1201 m_elementData = ShareableElementData::createWithAttributes(attributeVector);
1202
1203 // Use attributeVector instead of m_elementData because attributeChanged might modify m_elementData.
1204 for (unsigned i = 0; i < attributeVector.size(); ++i)
1205 attributeChangedFromParserOrByCloning(attributeVector[i].name(), attributeVector[i].value(), ModifiedDirectly);
1206}
1207
1208bool Element::hasAttributes() const
1209{
1210 synchronizeAllAttributes();
1211 return elementData() && elementData()->length();
1212}
1213
1214bool Element::hasEquivalentAttributes(const Element* other) const
1215{
1216 synchronizeAllAttributes();
1217 other->synchronizeAllAttributes();
1218 if (elementData() == other->elementData())
1219 return true;
1220 if (elementData())
1221 return elementData()->isEquivalent(other->elementData());
1222 if (other->elementData())
1223 return other->elementData()->isEquivalent(elementData());
1224 return true;
1225}
1226
1227String Element::nodeName() const
1228{
1229 return m_tagName.toString();
1230}
1231
1232String Element::nodeNamePreservingCase() const
1233{
1234 return m_tagName.toString();
1235}
1236
Ben Murdochdf957042013-08-06 11:01:27 +01001237void Element::setPrefix(const AtomicString& prefix, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001238{
Ben Murdochdf957042013-08-06 11:01:27 +01001239 checkSetPrefix(prefix, es);
1240 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001241 return;
1242
1243 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
1244}
1245
1246KURL Element::baseURI() const
1247{
1248 const AtomicString& baseAttribute = getAttribute(baseAttr);
1249 KURL base(KURL(), baseAttribute);
1250 if (!base.protocol().isEmpty())
1251 return base;
1252
1253 ContainerNode* parent = parentNode();
1254 if (!parent)
1255 return base;
1256
1257 const KURL& parentBase = parent->baseURI();
1258 if (parentBase.isNull())
1259 return base;
1260
1261 return KURL(parentBase, baseAttribute);
1262}
1263
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001264const AtomicString Element::imageSourceURL() const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001265{
1266 return getAttribute(srcAttr);
1267}
1268
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001269bool Element::rendererIsNeeded(const RenderStyle& style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001270{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001271 return style.display() != NONE;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001272}
1273
Ben Murdoch591b9582013-07-10 11:41:44 +01001274RenderObject* Element::createRenderer(RenderStyle* style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001275{
1276 return RenderObject::createObject(this, style);
1277}
1278
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001279Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertionPoint)
1280{
1281 // need to do superclass processing first so inDocument() is true
1282 // by the time we reach updateId
1283 ContainerNode::insertedInto(insertionPoint);
1284
1285 if (containsFullScreenElement() && parentElement() && !parentElement()->containsFullScreenElement())
1286 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
1287
1288 if (Element* before = pseudoElement(BEFORE))
1289 before->insertedInto(insertionPoint);
1290
1291 if (Element* after = pseudoElement(AFTER))
1292 after->insertedInto(insertionPoint);
1293
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001294 if (Element* backdrop = pseudoElement(BACKDROP))
1295 backdrop->insertedInto(insertionPoint);
1296
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001297 if (!insertionPoint->isInTreeScope())
1298 return InsertionDone;
1299
1300 if (hasRareData())
1301 elementRareData()->clearClassListValueForQuirksMode();
1302
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001303 if (isUpgradedCustomElement() && inDocument())
1304 CustomElement::didEnterDocument(this, document());
1305
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001306 TreeScope& scope = insertionPoint->treeScope();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001307 if (scope != treeScope())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001308 return InsertionDone;
1309
1310 const AtomicString& idValue = getIdAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001311 if (!idValue.isNull())
1312 updateId(scope, nullAtom, idValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001313
1314 const AtomicString& nameValue = getNameAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001315 if (!nameValue.isNull())
1316 updateName(nullAtom, nameValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001317
1318 if (hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001319 if (scope.shouldCacheLabelsByForAttribute())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001320 updateLabel(scope, nullAtom, fastGetAttribute(forAttr));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001321 }
1322
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001323 if (parentElement() && parentElement()->isInCanvasSubtree())
1324 setIsInCanvasSubtree(true);
1325
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001326 return InsertionDone;
1327}
1328
1329void Element::removedFrom(ContainerNode* insertionPoint)
1330{
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001331 bool wasInDocument = insertionPoint->inDocument();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001332
1333 if (Element* before = pseudoElement(BEFORE))
1334 before->removedFrom(insertionPoint);
1335
1336 if (Element* after = pseudoElement(AFTER))
1337 after->removedFrom(insertionPoint);
1338
Ben Murdoche69819b2013-07-17 14:56:49 +01001339 if (Element* backdrop = pseudoElement(BACKDROP))
1340 backdrop->removedFrom(insertionPoint);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001341 document().removeFromTopLayer(this);
Ben Murdoche69819b2013-07-17 14:56:49 +01001342
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001343 if (containsFullScreenElement())
1344 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
1345
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001346 if (document().page())
1347 document().page()->pointerLockController().elementRemoved(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001348
1349 setSavedLayerScrollOffset(IntSize());
1350
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001351 if (insertionPoint->isInTreeScope() && treeScope() == document()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001352 const AtomicString& idValue = getIdAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001353 if (!idValue.isNull())
1354 updateId(insertionPoint->treeScope(), idValue, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001355
1356 const AtomicString& nameValue = getNameAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001357 if (!nameValue.isNull())
1358 updateName(nameValue, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001359
1360 if (hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001361 TreeScope& treeScope = insertionPoint->treeScope();
1362 if (treeScope.shouldCacheLabelsByForAttribute())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001363 updateLabel(treeScope, fastGetAttribute(forAttr), nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001364 }
1365 }
1366
1367 ContainerNode::removedFrom(insertionPoint);
Ben Murdoche69819b2013-07-17 14:56:49 +01001368 if (wasInDocument) {
1369 if (hasPendingResources())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001370 document().accessSVGExtensions()->removeElementFromPendingResources(this);
Ben Murdoche69819b2013-07-17 14:56:49 +01001371
Ben Murdoch83750172013-07-24 10:36:59 +01001372 if (isUpgradedCustomElement())
Ben Murdochfff88842013-07-30 15:20:09 +01001373 CustomElement::didLeaveDocument(this, insertionPoint->document());
Ben Murdoche69819b2013-07-17 14:56:49 +01001374 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001375
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001376 if (hasRareData())
1377 elementRareData()->setIsInCanvasSubtree(false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001378}
1379
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001380void Element::attach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001381{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001382 ASSERT(document().inStyleRecalc());
1383
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001384 StyleResolverParentPusher parentPusher(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001385
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001386 // We've already been through detach when doing a lazyAttach, but we might
1387 // need to clear any state that's been added since then.
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001388 if (hasRareData() && styleChangeType() == NeedsReattachStyleChange) {
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001389 ElementRareData* data = elementRareData();
1390 data->clearComputedStyle();
1391 data->resetDynamicRestyleObservations();
1392 if (!context.resolvedStyle)
1393 data->resetStyleState();
1394 }
1395
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001396 NodeRenderingContext(this, context.resolvedStyle).createRendererForElementIfNeeded();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001397
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001398 if (RenderStyle* style = renderStyle())
1399 updateCallbackSelectors(0, style);
1400
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001401 createPseudoElementIfNeeded(BEFORE);
1402
1403 // When a shadow root exists, it does the work of attaching the children.
1404 if (ElementShadow* shadow = this->shadow()) {
1405 parentPusher.push();
Ben Murdoch591b9582013-07-10 11:41:44 +01001406 shadow->attach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001407 } else if (firstChild())
1408 parentPusher.push();
1409
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001410 ContainerNode::attach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001411
1412 createPseudoElementIfNeeded(AFTER);
Ben Murdoche69819b2013-07-17 14:56:49 +01001413 createPseudoElementIfNeeded(BACKDROP);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001414
Ben Murdoch591b9582013-07-10 11:41:44 +01001415 if (hasRareData()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001416 ElementRareData* data = elementRareData();
1417 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001418 if (isFocusable() && document().focusedElement() == this)
1419 document().updateFocusAppearanceSoon(false /* don't restore selection */);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001420 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1421 }
1422 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001423
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001424 InspectorInstrumentation::didRecalculateStyleForElement(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001425}
1426
1427void Element::unregisterNamedFlowContentNode()
1428{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001429 if (RuntimeEnabledFeatures::cssRegionsEnabled() && inNamedFlow() && document().renderView())
1430 document().renderView()->flowThreadController()->unregisterNamedFlowContentNode(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001431}
1432
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001433void Element::detach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001434{
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001435 RenderWidget::UpdateSuspendScope suspendWidgetHierarchyUpdates;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001436 unregisterNamedFlowContentNode();
1437 cancelFocusAppearanceUpdate();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001438 if (RenderStyle* style = renderStyle()) {
1439 if (!style->callbackSelectors().isEmpty())
1440 updateCallbackSelectors(style, 0);
1441 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001442 if (hasRareData()) {
1443 ElementRareData* data = elementRareData();
1444 data->setPseudoElement(BEFORE, 0);
1445 data->setPseudoElement(AFTER, 0);
Ben Murdoche69819b2013-07-17 14:56:49 +01001446 data->setPseudoElement(BACKDROP, 0);
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001447 data->clearComputedStyle();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001448 data->resetDynamicRestyleObservations();
Ben Murdoch591b9582013-07-10 11:41:44 +01001449 data->setIsInsideRegion(false);
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001450
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001451 // Only clear the style state if we're not going to reuse the style from recalcStyle.
1452 if (!context.resolvedStyle)
1453 data->resetStyleState();
1454
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001455 if (RuntimeEnabledFeatures::webAnimationsCSSEnabled() && !context.performingReattach) {
1456 if (ActiveAnimations* activeAnimations = data->activeAnimations())
1457 activeAnimations->cssAnimations()->cancel();
1458 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001459 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001460 if (ElementShadow* shadow = this->shadow())
1461 shadow->detach(context);
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001462 ContainerNode::detach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001463}
1464
1465bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle)
1466{
1467 ASSERT(currentStyle == renderStyle());
1468 ASSERT(renderer());
1469
1470 if (!currentStyle)
1471 return false;
1472
1473 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles();
1474 if (!pseudoStyleCache)
1475 return false;
1476
1477 size_t cacheSize = pseudoStyleCache->size();
1478 for (size_t i = 0; i < cacheSize; ++i) {
1479 RefPtr<RenderStyle> newPseudoStyle;
1480 PseudoId pseudoId = pseudoStyleCache->at(i)->styleType();
1481 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
1482 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle);
1483 else
1484 newPseudoStyle = renderer()->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
1485 if (!newPseudoStyle)
1486 return true;
1487 if (*newPseudoStyle != *pseudoStyleCache->at(i)) {
1488 if (pseudoId < FIRST_INTERNAL_PSEUDOID)
1489 newStyle->setHasPseudoStyle(pseudoId);
1490 newStyle->addCachedPseudoStyle(newPseudoStyle);
1491 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
1492 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
1493 // is needed, but for now just assume a layout will be required. The diff code
1494 // in RenderObject::setStyle would need to be factored out so that it could be reused.
1495 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
1496 }
1497 return true;
1498 }
1499 }
1500 return false;
1501}
1502
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001503PassRefPtr<RenderStyle> Element::styleForRenderer()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001504{
1505 if (hasCustomStyleCallbacks()) {
1506 if (RefPtr<RenderStyle> style = customStyleForRenderer())
1507 return style.release();
1508 }
1509
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001510 return originalStyleForRenderer();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001511}
1512
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001513PassRefPtr<RenderStyle> Element::originalStyleForRenderer()
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001514{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001515 return document().styleResolver()->styleForElement(this);
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001516}
1517
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001518bool Element::recalcStyle(StyleRecalcChange change)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001519{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001520 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001521
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)1e202182013-10-18 15:46:42 +01001528 if ((change >= Inherit || needsStyleRecalc()) && parentRenderStyle()) {
1529 if (hasCustomStyleCallbacks())
1530 willRecalcStyle(change);
1531 // Active InsertionPoints have no renderers so they never need to go through a recalc.
1532 if (!isActiveInsertionPoint(this))
1533 change = recalcOwnStyle(change);
1534 if (hasCustomStyleCallbacks())
1535 didRecalcStyle(change);
1536 }
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001537
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001538 // If we reattached we don't need to recalc the style of our descendants anymore.
1539 if (change < Reattach)
1540 recalcChildStyle(change);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001541
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001542 clearNeedsStyleRecalc();
1543 clearChildNeedsStyleRecalc();
Ben Murdoch591b9582013-07-10 11:41:44 +01001544
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001545 return change == Reattach;
1546}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001547
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001548static bool callbackSelectorsDiffer(RenderStyle* style1, RenderStyle* style2)
1549{
1550 const Vector<String> emptyVector;
1551 const Vector<String>& callbackSelectors1 = style1 ? style1->callbackSelectors() : emptyVector;
1552 const Vector<String>& callbackSelectors2 = style2 ? style2->callbackSelectors() : emptyVector;
1553 if (callbackSelectors1.isEmpty() && callbackSelectors2.isEmpty()) {
1554 // Help the inliner with this common case.
1555 return false;
1556 }
1557 return callbackSelectors1 != callbackSelectors2;
1558}
1559
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001560StyleRecalcChange Element::recalcOwnStyle(StyleRecalcChange change)
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001561{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001562 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001563
1564 CSSAnimationUpdateScope cssAnimationUpdateScope(this);
1565 RefPtr<RenderStyle> oldStyle = renderStyle();
1566 RefPtr<RenderStyle> newStyle = styleForRenderer();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001567 StyleRecalcChange localChange = RenderStyle::compare(oldStyle.get(), newStyle.get());
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001568
1569 if (localChange == Reattach) {
1570 AttachContext reattachContext;
1571 reattachContext.resolvedStyle = newStyle.get();
1572 reattach(reattachContext);
1573 return Reattach;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001574 }
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001575
1576 InspectorInstrumentation::didRecalculateStyleForElement(this);
1577
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001578 if (localChange != NoChange && callbackSelectorsDiffer(oldStyle.get(), newStyle.get()))
1579 updateCallbackSelectors(oldStyle.get(), newStyle.get());
1580
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001581 if (RenderObject* renderer = this->renderer()) {
1582 if (localChange != NoChange || pseudoStyleCacheIsInvalid(oldStyle.get(), newStyle.get()) || (change == Force && renderer->requiresForcedStyleRecalcPropagation()) || shouldNotifyRendererWithIdenticalStyles()) {
1583 renderer->setAnimatableStyle(newStyle.get());
1584 } else if (needsStyleRecalc()) {
1585 // Although no change occurred, we use the new style so that the cousin style sharing code won't get
1586 // fooled into believing this style is the same.
1587 renderer->setStyleInternal(newStyle.get());
1588 }
1589 }
1590
1591 // 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
1592 // 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 +01001593 if (document().styleEngine()->usesRemUnits() && document().documentElement() == this && oldStyle && newStyle && oldStyle->fontSize() != newStyle->fontSize()) {
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001594 // Cached RenderStyles may depend on the re units.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001595 document().styleResolver()->invalidateMatchedPropertiesCache();
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001596 return Force;
1597 }
1598
1599 if (styleChangeType() >= SubtreeStyleChange)
1600 return Force;
1601
1602 return max(localChange, change);
1603}
1604
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001605void Element::recalcChildStyle(StyleRecalcChange change)
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001606{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001607 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001608
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001609 StyleResolverParentPusher parentPusher(this);
1610
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001611 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
1612 if (shouldRecalcStyle(change, root)) {
1613 parentPusher.push();
1614 root->recalcStyle(change);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001615 }
1616 }
1617
1618 if (shouldRecalcStyle(change, this))
1619 updatePseudoElement(BEFORE, change);
1620
1621 // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
1622 // For now we will just worry about the common case, since it's a lot trickier to get the second case right
1623 // without doing way too much re-resolution.
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001624 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
1625 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001626 bool forceCheckOfNextElementSibling = false;
1627 bool forceCheckOfAnyElementSibling = false;
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001628 if (hasDirectAdjacentRules || hasIndirectAdjacentRules) {
1629 for (Node* child = firstChild(); child; child = child->nextSibling()) {
1630 if (!child->isElementNode())
1631 continue;
Ben Murdoche69819b2013-07-17 14:56:49 +01001632 Element* element = toElement(child);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001633 bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() >= SubtreeStyleChange;
Ben Murdoche69819b2013-07-17 14:56:49 +01001634 if (forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling)
1635 element->setNeedsStyleRecalc();
Ben Murdoche69819b2013-07-17 14:56:49 +01001636 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
1637 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001638 }
1639 }
1640 // This loop is deliberately backwards because we use insertBefore in the rendering tree, and want to avoid
1641 // a potentially n^2 loop to find the insertion point while resolving style. Having us start from the last
1642 // child and work our way back means in the common case, we'll find the insertion point in O(1) time.
1643 // Reversing this loop can lead to non-deterministic results in our code to optimize out empty whitespace
1644 // RenderTexts. We try to put off recalcing their style until the end to avoid this issue.
1645 // See crbug.com/288225
1646 WhitespaceChildList whitespaceChildList(change);
1647 for (Node* child = lastChild(); child; child = child->previousSibling()) {
1648 if (child->isTextNode()) {
1649 Text* textChild = toText(child);
1650 // FIXME: This check is expensive and may negate the performance gained by the optimization of
1651 // avoiding whitespace renderers.
1652 if (textChild->containsOnlyWhitespace())
1653 whitespaceChildList.append(textChild);
1654 else
1655 textChild->recalcTextStyle(change);
1656 } else if (child->isElementNode()) {
1657 Element* element = toElement(child);
Ben Murdoche69819b2013-07-17 14:56:49 +01001658 if (shouldRecalcStyle(change, element)) {
1659 parentPusher.push();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001660 element->recalcStyle(change);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001661 } else if (document().styleResolver()->supportsStyleSharing(element)) {
1662 document().styleResolver()->addToStyleSharingList(element);
Ben Murdoche69819b2013-07-17 14:56:49 +01001663 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001664 }
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001665 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001666
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001667 whitespaceChildList.recalcStyle();
1668
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001669 if (shouldRecalcStyle(change, this)) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001670 updatePseudoElement(AFTER, change);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001671 updatePseudoElement(BACKDROP, change);
1672 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001673}
1674
1675ElementShadow* Element::shadow() const
1676{
1677 return hasRareData() ? elementRareData()->shadow() : 0;
1678}
1679
1680ElementShadow* Element::ensureShadow()
1681{
1682 return ensureElementRareData()->ensureShadow();
1683}
1684
1685void Element::didAffectSelector(AffectedSelectorMask mask)
1686{
1687 setNeedsStyleRecalc();
1688 if (ElementShadow* elementShadow = shadowOfParentForDistribution(this))
1689 elementShadow->didAffectSelector(mask);
1690}
1691
Ben Murdochdf957042013-08-06 11:01:27 +01001692PassRefPtr<ShadowRoot> Element::createShadowRoot(ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001693{
1694 if (alwaysCreateUserAgentShadowRoot())
1695 ensureUserAgentShadowRoot();
1696
1697 if (RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled())
1698 return ensureShadow()->addShadowRoot(this, ShadowRoot::AuthorShadowRoot);
1699
1700 // Since some elements recreates shadow root dynamically, multiple shadow
1701 // subtrees won't work well in that element. Until they are fixed, we disable
1702 // adding author shadow root for them.
1703 if (!areAuthorShadowsAllowed()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001704 es.throwUninformativeAndGenericDOMException(HierarchyRequestError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001705 return 0;
1706 }
1707 return ensureShadow()->addShadowRoot(this, ShadowRoot::AuthorShadowRoot);
1708}
1709
1710ShadowRoot* Element::shadowRoot() const
1711{
1712 ElementShadow* elementShadow = shadow();
1713 if (!elementShadow)
1714 return 0;
1715 ShadowRoot* shadowRoot = elementShadow->youngestShadowRoot();
1716 if (shadowRoot->type() == ShadowRoot::AuthorShadowRoot)
1717 return shadowRoot;
1718 return 0;
1719}
1720
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001721void Element::didAddShadowRoot(ShadowRoot&)
1722{
1723}
1724
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001725ShadowRoot* Element::userAgentShadowRoot() const
1726{
1727 if (ElementShadow* elementShadow = shadow()) {
1728 if (ShadowRoot* shadowRoot = elementShadow->oldestShadowRoot()) {
1729 ASSERT(shadowRoot->type() == ShadowRoot::UserAgentShadowRoot);
1730 return shadowRoot;
1731 }
1732 }
1733
1734 return 0;
1735}
1736
1737ShadowRoot* Element::ensureUserAgentShadowRoot()
1738{
1739 if (ShadowRoot* shadowRoot = userAgentShadowRoot())
1740 return shadowRoot;
1741 ShadowRoot* shadowRoot = ensureShadow()->addShadowRoot(this, ShadowRoot::UserAgentShadowRoot);
1742 didAddUserAgentShadowRoot(shadowRoot);
1743 return shadowRoot;
1744}
1745
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001746bool Element::childTypeAllowed(NodeType type) const
1747{
1748 switch (type) {
1749 case ELEMENT_NODE:
1750 case TEXT_NODE:
1751 case COMMENT_NODE:
1752 case PROCESSING_INSTRUCTION_NODE:
1753 case CDATA_SECTION_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001754 return true;
1755 default:
1756 break;
1757 }
1758 return false;
1759}
1760
Ben Murdoch83750172013-07-24 10:36:59 +01001761static void inline checkForEmptyStyleChange(Element* element, RenderStyle* style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001762{
1763 if (!style && !element->styleAffectedByEmpty())
1764 return;
1765
1766 if (!style || (element->styleAffectedByEmpty() && (!style->emptyState() || element->hasChildNodes())))
1767 element->setNeedsStyleRecalc();
1768}
1769
1770static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
1771 Node* beforeChange, Node* afterChange, int childCountDelta)
1772{
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001773 if (!e->confusingAndOftenMisusedAttached() || e->document().hasPendingForcedStyleRecalc() || e->styleChangeType() >= SubtreeStyleChange)
Ben Murdoch83750172013-07-24 10:36:59 +01001774 return;
1775
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001776 // :empty selector.
1777 checkForEmptyStyleChange(e, style);
Ben Murdoch591b9582013-07-10 11:41:44 +01001778
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001779 if (!style || (e->needsStyleRecalc() && e->childrenAffectedByPositionalRules()))
1780 return;
1781
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001782 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
1783 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1784 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
1785 // backward case.
1786 // |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.
1787 // 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 +01001788 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
1789 if ((e->childrenAffectedByForwardPositionalRules() && afterChange) || (e->childrenAffectedByBackwardPositionalRules() && beforeChange)) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001790 e->setNeedsStyleRecalc();
Ben Murdoch83750172013-07-24 10:36:59 +01001791 return;
1792 }
1793
1794 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1795 // In the DOM case, we only need to do something if |afterChange| is not 0.
1796 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
1797 if (e->childrenAffectedByFirstChildRules() && afterChange) {
1798 // Find our new first child.
1799 Node* newFirstChild = e->firstElementChild();
1800 RenderStyle* newFirstChildStyle = newFirstChild ? newFirstChild->renderStyle() : 0;
1801
1802 // Find the first element node following |afterChange|
1803 Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling();
1804 RenderStyle* firstElementAfterInsertionStyle = firstElementAfterInsertion ? firstElementAfterInsertion->renderStyle() : 0;
1805
1806 // This is the insert/append case.
1807 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertionStyle && firstElementAfterInsertionStyle->firstChildState())
1808 firstElementAfterInsertion->setNeedsStyleRecalc();
1809
1810 // We also have to handle node removal.
1811 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChildStyle || !newFirstChildStyle->firstChildState()))
1812 newFirstChild->setNeedsStyleRecalc();
1813 }
1814
1815 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1816 // In the DOM case, we only need to do something if |afterChange| is not 0.
1817 if (e->childrenAffectedByLastChildRules() && beforeChange) {
1818 // Find our new last child.
1819 Node* newLastChild = e->lastElementChild();
1820 RenderStyle* newLastChildStyle = newLastChild ? newLastChild->renderStyle() : 0;
1821
1822 // Find the last element node going backwards from |beforeChange|
1823 Node* lastElementBeforeInsertion = beforeChange->isElementNode() ? beforeChange : beforeChange->previousElementSibling();
1824 RenderStyle* lastElementBeforeInsertionStyle = lastElementBeforeInsertion ? lastElementBeforeInsertion->renderStyle() : 0;
1825
1826 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertionStyle && lastElementBeforeInsertionStyle->lastChildState())
1827 lastElementBeforeInsertion->setNeedsStyleRecalc();
1828
1829 // 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
1830 // to match now.
1831 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChildStyle || !newLastChildStyle->lastChildState()))
1832 newLastChild->setNeedsStyleRecalc();
1833 }
1834
1835 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
1836 // that could be affected by this DOM change.
1837 if (e->childrenAffectedByDirectAdjacentRules() && afterChange) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001838 if (Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling())
Ben Murdoch83750172013-07-24 10:36:59 +01001839 firstElementAfterInsertion->setNeedsStyleRecalc();
1840 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001841}
1842
1843void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
1844{
1845 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
1846 if (changedByParser)
1847 checkForEmptyStyleChange(this, renderStyle());
1848 else
1849 checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
1850
Ben Murdoch83750172013-07-24 10:36:59 +01001851 if (ElementShadow* shadow = this->shadow())
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001852 shadow->setNeedsDistributionRecalc();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001853}
1854
1855void Element::removeAllEventListeners()
1856{
1857 ContainerNode::removeAllEventListeners();
1858 if (ElementShadow* shadow = this->shadow())
1859 shadow->removeAllEventListeners();
1860}
1861
1862void Element::beginParsingChildren()
1863{
1864 clearIsParsingChildrenFinished();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001865}
1866
1867void Element::finishParsingChildren()
1868{
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001869 setIsParsingChildrenFinished();
1870 checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001871 if (isCustomElement())
1872 CustomElement::didFinishParsingChildren(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001873}
1874
1875#ifndef NDEBUG
1876void Element::formatForDebugger(char* buffer, unsigned length) const
1877{
1878 StringBuilder result;
1879 String s;
1880
1881 result.append(nodeName());
1882
1883 s = getIdAttribute();
1884 if (s.length() > 0) {
1885 if (result.length() > 0)
1886 result.appendLiteral("; ");
1887 result.appendLiteral("id=");
1888 result.append(s);
1889 }
1890
1891 s = getAttribute(classAttr);
1892 if (s.length() > 0) {
1893 if (result.length() > 0)
1894 result.appendLiteral("; ");
1895 result.appendLiteral("class=");
1896 result.append(s);
1897 }
1898
1899 strncpy(buffer, result.toString().utf8().data(), length - 1);
1900}
1901#endif
1902
1903const Vector<RefPtr<Attr> >& Element::attrNodeList()
1904{
1905 ASSERT(hasSyntheticAttrChildNodes());
1906 return *attrNodeListForElement(this);
1907}
1908
Ben Murdochdf957042013-08-06 11:01:27 +01001909PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001910{
1911 if (!attrNode) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001912 es.throwUninformativeAndGenericDOMException(TypeMismatchError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001913 return 0;
1914 }
1915
1916 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName());
1917 if (oldAttrNode.get() == attrNode)
1918 return attrNode; // This Attr is already attached to the element.
1919
Ben Murdoche69819b2013-07-17 14:56:49 +01001920 // 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 +01001921 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
1922 if (attrNode->ownerElement()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001923 es.throwUninformativeAndGenericDOMException(InUseAttributeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001924 return 0;
1925 }
1926
1927 synchronizeAllAttributes();
1928 UniqueElementData* elementData = ensureUniqueElementData();
1929
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001930 size_t index = elementData->getAttributeItemIndex(attrNode->qualifiedName(), shouldIgnoreAttributeCase(this));
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001931 if (index != kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001932 if (oldAttrNode)
1933 detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData->attributeItem(index)->value());
1934 else
1935 oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), elementData->attributeItem(index)->value());
1936 }
1937
1938 setAttributeInternal(index, attrNode->qualifiedName(), attrNode->value(), NotInSynchronizationOfLazyAttribute);
1939
1940 attrNode->attachToElement(this);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001941 treeScope().adoptIfNeeded(attrNode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001942 ensureAttrNodeListForElement(this)->append(attrNode);
1943
1944 return oldAttrNode.release();
1945}
1946
Ben Murdochdf957042013-08-06 11:01:27 +01001947PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001948{
Ben Murdochdf957042013-08-06 11:01:27 +01001949 return setAttributeNode(attr, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001950}
1951
Ben Murdochdf957042013-08-06 11:01:27 +01001952PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001953{
1954 if (!attr) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001955 es.throwUninformativeAndGenericDOMException(TypeMismatchError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001956 return 0;
1957 }
1958 if (attr->ownerElement() != this) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001959 es.throwUninformativeAndGenericDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001960 return 0;
1961 }
1962
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001963 ASSERT(document() == attr->document());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001964
1965 synchronizeAttribute(attr->qualifiedName());
1966
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001967 size_t index = elementData()->getAttrIndex(attr);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001968 if (index == kNotFound) {
1969 es.throwUninformativeAndGenericDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001970 return 0;
1971 }
1972
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001973 RefPtr<Attr> guard(attr);
1974 detachAttrNodeAtIndex(attr, index);
1975 return guard.release();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001976}
1977
Ben Murdochdf957042013-08-06 11:01:27 +01001978bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001979{
1980 String prefix, localName;
Ben Murdochdf957042013-08-06 11:01:27 +01001981 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, es))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001982 return false;
Ben Murdochdf957042013-08-06 11:01:27 +01001983 ASSERT(!es.hadException());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001984
1985 QualifiedName qName(prefix, localName, namespaceURI);
1986
1987 if (!Document::hasValidNamespaceForAttributes(qName)) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001988 es.throwUninformativeAndGenericDOMException(NamespaceError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001989 return false;
1990 }
1991
1992 out = qName;
1993 return true;
1994}
1995
Ben Murdochdf957042013-08-06 11:01:27 +01001996void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001997{
1998 QualifiedName parsedName = anyName;
Ben Murdochdf957042013-08-06 11:01:27 +01001999 if (!parseAttributeName(parsedName, namespaceURI, qualifiedName, es))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002000 return;
2001 setAttribute(parsedName, value);
2002}
2003
2004void Element::removeAttributeInternal(size_t index, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
2005{
2006 ASSERT_WITH_SECURITY_IMPLICATION(index < attributeCount());
2007
2008 UniqueElementData* elementData = ensureUniqueElementData();
2009
2010 QualifiedName name = elementData->attributeItem(index)->name();
2011 AtomicString valueBeingRemoved = elementData->attributeItem(index)->value();
2012
2013 if (!inSynchronizationOfLazyAttribute) {
2014 if (!valueBeingRemoved.isNull())
2015 willModifyAttribute(name, valueBeingRemoved, nullAtom);
2016 }
2017
2018 if (RefPtr<Attr> attrNode = attrIfExists(name))
2019 detachAttrNodeFromElementWithValue(attrNode.get(), elementData->attributeItem(index)->value());
2020
2021 elementData->removeAttribute(index);
2022
2023 if (!inSynchronizationOfLazyAttribute)
2024 didRemoveAttribute(name);
2025}
2026
2027void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
2028{
2029 if (!inSynchronizationOfLazyAttribute)
2030 willModifyAttribute(name, nullAtom, value);
2031 ensureUniqueElementData()->addAttribute(name, value);
2032 if (!inSynchronizationOfLazyAttribute)
2033 didAddAttribute(name, value);
2034}
2035
2036void Element::removeAttribute(const AtomicString& name)
2037{
2038 if (!elementData())
2039 return;
2040
2041 AtomicString localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
2042 size_t index = elementData()->getAttributeItemIndex(localName, false);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01002043 if (index == kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002044 if (UNLIKELY(localName == styleAttr) && elementData()->m_styleAttributeIsDirty && isStyledElement())
Ben Murdoch591b9582013-07-10 11:41:44 +01002045 removeAllInlineStyleProperties();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002046 return;
2047 }
2048
2049 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
2050}
2051
2052void Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName)
2053{
2054 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI));
2055}
2056
2057PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& localName)
2058{
2059 if (!elementData())
2060 return 0;
2061 synchronizeAttribute(localName);
2062 const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase(this));
2063 if (!attribute)
2064 return 0;
2065 return ensureAttr(attribute->name());
2066}
2067
2068PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
2069{
2070 if (!elementData())
2071 return 0;
2072 QualifiedName qName(nullAtom, localName, namespaceURI);
2073 synchronizeAttribute(qName);
2074 const Attribute* attribute = elementData()->getAttributeItem(qName);
2075 if (!attribute)
2076 return 0;
2077 return ensureAttr(attribute->name());
2078}
2079
2080bool Element::hasAttribute(const AtomicString& localName) const
2081{
2082 if (!elementData())
2083 return false;
2084 synchronizeAttribute(localName);
2085 return elementData()->getAttributeItem(shouldIgnoreAttributeCase(this) ? localName.lower() : localName, false);
2086}
2087
2088bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
2089{
2090 if (!elementData())
2091 return false;
2092 QualifiedName qName(nullAtom, localName, namespaceURI);
2093 synchronizeAttribute(qName);
2094 return elementData()->getAttributeItem(qName);
2095}
2096
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002097void Element::focus(bool restorePreviousSelection, FocusDirection direction)
2098{
2099 if (!inDocument())
2100 return;
2101
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002102 Document& doc = document();
2103 if (doc.focusedElement() == this)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002104 return;
2105
2106 // If the stylesheets have already been loaded we can reliably check isFocusable.
2107 // If not, we continue and set the focused node on the focus controller below so
Ben Murdoch591b9582013-07-10 11:41:44 +01002108 // that it can be updated soon after attach.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002109 if (doc.haveStylesheetsLoaded()) {
2110 doc.updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002111 if (!isFocusable())
2112 return;
2113 }
2114
2115 if (!supportsFocus())
2116 return;
2117
2118 RefPtr<Node> protect;
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002119 if (Page* page = doc.page()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002120 // Focus and change event handlers can cause us to lose our last ref.
2121 // If a focus event handler changes the focus to a different node it
2122 // does not make sense to continue and update appearence.
2123 protect = this;
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002124 if (!page->focusController().setFocusedElement(this, doc.frame(), direction))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002125 return;
2126 }
2127
2128 // Setting the focused node above might have invalidated the layout due to scripts.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002129 doc.updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002130
2131 if (!isFocusable()) {
2132 ensureElementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
2133 return;
2134 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002135
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002136 cancelFocusAppearanceUpdate();
2137 updateFocusAppearance(restorePreviousSelection);
2138}
2139
2140void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
2141{
2142 if (isRootEditableElement()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002143 Frame* frame = document().frame();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002144 if (!frame)
2145 return;
Ben Murdoch591b9582013-07-10 11:41:44 +01002146
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002147 // 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 +01002148 if (this == frame->selection().rootEditableElement())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002149 return;
2150
2151 // FIXME: We should restore the previous selection if there is one.
2152 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002153 frame->selection().setSelection(newSelection);
2154 frame->selection().revealSelection();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002155 } else if (renderer() && !renderer()->isWidget())
2156 renderer()->scrollRectToVisible(boundingBox());
2157}
2158
2159void Element::blur()
2160{
2161 cancelFocusAppearanceUpdate();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002162 if (treeScope().adjustedFocusedElement() == this) {
2163 Document& doc = document();
2164 if (doc.page())
2165 doc.page()->focusController().setFocusedElement(0, doc.frame());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002166 else
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002167 doc.setFocusedElement(0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002168 }
2169}
2170
Ben Murdochdf957042013-08-06 11:01:27 +01002171bool Element::isFocusable() const
2172{
2173 return inDocument() && supportsFocus() && !isInert() && rendererIsFocusable();
2174}
2175
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002176bool Element::isKeyboardFocusable() const
2177{
2178 return isFocusable() && tabIndex() >= 0;
2179}
2180
2181bool Element::isMouseFocusable() const
2182{
2183 return isFocusable();
2184}
2185
Ben Murdoch02772c62013-07-26 10:21:05 +01002186void Element::dispatchFocusEvent(Element* oldFocusedElement, FocusDirection)
2187{
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002188 RefPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::focus, false, false, document().defaultView(), 0, oldFocusedElement);
Ben Murdoch02772c62013-07-26 10:21:05 +01002189 EventDispatcher::dispatchEvent(this, FocusEventDispatchMediator::create(event.release()));
2190}
2191
2192void Element::dispatchBlurEvent(Element* newFocusedElement)
2193{
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002194 RefPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::blur, false, false, document().defaultView(), 0, newFocusedElement);
Ben Murdoch02772c62013-07-26 10:21:05 +01002195 EventDispatcher::dispatchEvent(this, BlurEventDispatchMediator::create(event.release()));
2196}
2197
2198void Element::dispatchFocusInEvent(const AtomicString& eventType, Element* oldFocusedElement)
2199{
2200 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002201 ASSERT(eventType == EventTypeNames::focusin || eventType == EventTypeNames::DOMFocusIn);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002202 dispatchScopedEventDispatchMediator(FocusInEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document().defaultView(), 0, oldFocusedElement)));
Ben Murdoch02772c62013-07-26 10:21:05 +01002203}
2204
2205void Element::dispatchFocusOutEvent(const AtomicString& eventType, Element* newFocusedElement)
2206{
2207 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002208 ASSERT(eventType == EventTypeNames::focusout || eventType == EventTypeNames::DOMFocusOut);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002209 dispatchScopedEventDispatchMediator(FocusOutEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document().defaultView(), 0, newFocusedElement)));
Ben Murdoch02772c62013-07-26 10:21:05 +01002210}
2211
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002212String Element::innerText()
2213{
2214 // We need to update layout, since plainText uses line boxes in the render tree.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002215 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002216
2217 if (!renderer())
2218 return textContent(true);
2219
2220 return plainText(rangeOfContents(const_cast<Element*>(this)).get());
2221}
2222
2223String Element::outerText()
2224{
2225 // Getting outerText is the same as getting innerText, only
2226 // setting is different. You would think this should get the plain
2227 // text for the outer range, but this is wrong, <br> for instance
2228 // would return different values for inner and outer text by such
2229 // a rule, but it doesn't in WinIE, and we want to match that.
2230 return innerText();
2231}
2232
Ben Murdoch591b9582013-07-10 11:41:44 +01002233String Element::textFromChildren()
2234{
2235 Text* firstTextNode = 0;
2236 bool foundMultipleTextNodes = false;
2237 unsigned totalLength = 0;
2238
2239 for (Node* child = firstChild(); child; child = child->nextSibling()) {
2240 if (!child->isTextNode())
2241 continue;
2242 Text* text = toText(child);
2243 if (!firstTextNode)
2244 firstTextNode = text;
2245 else
2246 foundMultipleTextNodes = true;
2247 unsigned length = text->data().length();
2248 if (length > std::numeric_limits<unsigned>::max() - totalLength)
2249 return emptyString();
2250 totalLength += length;
2251 }
2252
2253 if (!firstTextNode)
2254 return emptyString();
2255
2256 if (firstTextNode && !foundMultipleTextNodes) {
2257 firstTextNode->atomize();
2258 return firstTextNode->data();
2259 }
2260
2261 StringBuilder content;
2262 content.reserveCapacity(totalLength);
2263 for (Node* child = firstTextNode; child; child = child->nextSibling()) {
2264 if (!child->isTextNode())
2265 continue;
2266 content.append(toText(child)->data());
2267 }
2268
2269 ASSERT(content.length() == totalLength);
2270 return content.toString();
2271}
2272
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01002273// pseudo is used via shadowPseudoId.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002274const AtomicString& Element::pseudo() const
2275{
2276 return getAttribute(pseudoAttr);
2277}
2278
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002279const AtomicString& Element::part() const
2280{
2281 return getAttribute(partAttr);
2282}
2283
2284void Element::setPart(const AtomicString& value)
2285{
2286 setAttribute(partAttr, value);
2287}
2288
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002289LayoutSize Element::minimumSizeForResizing() const
2290{
2291 return hasRareData() ? elementRareData()->minimumSizeForResizing() : defaultMinimumSizeForResizing();
2292}
2293
2294void Element::setMinimumSizeForResizing(const LayoutSize& size)
2295{
2296 if (!hasRareData() && size == defaultMinimumSizeForResizing())
2297 return;
2298 ensureElementRareData()->setMinimumSizeForResizing(size);
2299}
2300
2301RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
2302{
2303 if (PseudoElement* element = pseudoElement(pseudoElementSpecifier))
2304 return element->computedStyle();
2305
2306 // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
2307 // properties, which are only known by the renderer because it did the layout, will be correct and so that the
2308 // values returned for the ":selection" pseudo-element will be correct.
2309 if (RenderStyle* usedStyle = renderStyle()) {
2310 if (pseudoElementSpecifier) {
2311 RenderStyle* cachedPseudoStyle = usedStyle->getCachedPseudoStyle(pseudoElementSpecifier);
2312 return cachedPseudoStyle ? cachedPseudoStyle : usedStyle;
2313 } else
2314 return usedStyle;
2315 }
2316
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002317 if (!confusingAndOftenMisusedAttached())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002318 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
2319 // document tree and figure out when to destroy the computed style for such elements.
2320 return 0;
2321
2322 ElementRareData* data = ensureElementRareData();
2323 if (!data->computedStyle())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002324 data->setComputedStyle(document().styleForElementIgnoringPendingStylesheets(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002325 return pseudoElementSpecifier ? data->computedStyle()->getCachedPseudoStyle(pseudoElementSpecifier) : data->computedStyle();
2326}
2327
2328void Element::setStyleAffectedByEmpty()
2329{
2330 ensureElementRareData()->setStyleAffectedByEmpty(true);
2331}
2332
2333void Element::setChildrenAffectedByHover(bool value)
2334{
2335 if (value || hasRareData())
2336 ensureElementRareData()->setChildrenAffectedByHover(value);
2337}
2338
2339void Element::setChildrenAffectedByActive(bool value)
2340{
2341 if (value || hasRareData())
2342 ensureElementRareData()->setChildrenAffectedByActive(value);
2343}
2344
2345void Element::setChildrenAffectedByDrag(bool value)
2346{
2347 if (value || hasRareData())
2348 ensureElementRareData()->setChildrenAffectedByDrag(value);
2349}
2350
2351void Element::setChildrenAffectedByFirstChildRules()
2352{
2353 ensureElementRareData()->setChildrenAffectedByFirstChildRules(true);
2354}
2355
2356void Element::setChildrenAffectedByLastChildRules()
2357{
2358 ensureElementRareData()->setChildrenAffectedByLastChildRules(true);
2359}
2360
2361void Element::setChildrenAffectedByDirectAdjacentRules()
2362{
2363 ensureElementRareData()->setChildrenAffectedByDirectAdjacentRules(true);
2364}
2365
2366void Element::setChildrenAffectedByForwardPositionalRules()
2367{
2368 ensureElementRareData()->setChildrenAffectedByForwardPositionalRules(true);
2369}
2370
2371void Element::setChildrenAffectedByBackwardPositionalRules()
2372{
2373 ensureElementRareData()->setChildrenAffectedByBackwardPositionalRules(true);
2374}
2375
2376void Element::setChildIndex(unsigned index)
2377{
2378 ElementRareData* rareData = ensureElementRareData();
2379 if (RenderStyle* style = renderStyle())
2380 style->setUnique();
2381 rareData->setChildIndex(index);
2382}
2383
2384bool Element::hasFlagsSetDuringStylingOfChildren() const
2385{
2386 if (!hasRareData())
2387 return false;
2388 return rareDataChildrenAffectedByHover()
2389 || rareDataChildrenAffectedByActive()
2390 || rareDataChildrenAffectedByDrag()
2391 || rareDataChildrenAffectedByFirstChildRules()
2392 || rareDataChildrenAffectedByLastChildRules()
2393 || rareDataChildrenAffectedByDirectAdjacentRules()
2394 || rareDataChildrenAffectedByForwardPositionalRules()
2395 || rareDataChildrenAffectedByBackwardPositionalRules();
2396}
2397
2398bool Element::rareDataStyleAffectedByEmpty() const
2399{
2400 ASSERT(hasRareData());
2401 return elementRareData()->styleAffectedByEmpty();
2402}
2403
2404bool Element::rareDataChildrenAffectedByHover() const
2405{
2406 ASSERT(hasRareData());
2407 return elementRareData()->childrenAffectedByHover();
2408}
2409
2410bool Element::rareDataChildrenAffectedByActive() const
2411{
2412 ASSERT(hasRareData());
2413 return elementRareData()->childrenAffectedByActive();
2414}
2415
2416bool Element::rareDataChildrenAffectedByDrag() const
2417{
2418 ASSERT(hasRareData());
2419 return elementRareData()->childrenAffectedByDrag();
2420}
2421
2422bool Element::rareDataChildrenAffectedByFirstChildRules() const
2423{
2424 ASSERT(hasRareData());
2425 return elementRareData()->childrenAffectedByFirstChildRules();
2426}
2427
2428bool Element::rareDataChildrenAffectedByLastChildRules() const
2429{
2430 ASSERT(hasRareData());
2431 return elementRareData()->childrenAffectedByLastChildRules();
2432}
2433
2434bool Element::rareDataChildrenAffectedByDirectAdjacentRules() const
2435{
2436 ASSERT(hasRareData());
2437 return elementRareData()->childrenAffectedByDirectAdjacentRules();
2438}
2439
2440bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
2441{
2442 ASSERT(hasRareData());
2443 return elementRareData()->childrenAffectedByForwardPositionalRules();
2444}
2445
2446bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
2447{
2448 ASSERT(hasRareData());
2449 return elementRareData()->childrenAffectedByBackwardPositionalRules();
2450}
2451
2452unsigned Element::rareDataChildIndex() const
2453{
2454 ASSERT(hasRareData());
2455 return elementRareData()->childIndex();
2456}
2457
2458void Element::setIsInCanvasSubtree(bool isInCanvasSubtree)
2459{
2460 ensureElementRareData()->setIsInCanvasSubtree(isInCanvasSubtree);
2461}
2462
2463bool Element::isInCanvasSubtree() const
2464{
2465 return hasRareData() && elementRareData()->isInCanvasSubtree();
2466}
2467
Ben Murdoch591b9582013-07-10 11:41:44 +01002468void Element::setIsInsideRegion(bool value)
2469{
2470 if (value == isInsideRegion())
2471 return;
2472
2473 ensureElementRareData()->setIsInsideRegion(value);
2474}
2475
2476bool Element::isInsideRegion() const
2477{
2478 return hasRareData() ? elementRareData()->isInsideRegion() : false;
2479}
2480
2481void Element::setRegionOversetState(RegionOversetState state)
2482{
2483 ensureElementRareData()->setRegionOversetState(state);
2484}
2485
2486RegionOversetState Element::regionOversetState() const
2487{
2488 return hasRareData() ? elementRareData()->regionOversetState() : RegionUndefined;
2489}
2490
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002491AtomicString Element::computeInheritedLanguage() const
2492{
2493 const Node* n = this;
2494 AtomicString value;
2495 // The language property is inherited, so we iterate over the parents to find the first language.
2496 do {
2497 if (n->isElementNode()) {
2498 if (const ElementData* elementData = toElement(n)->elementData()) {
2499 // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7
2500 if (const Attribute* attribute = elementData->getAttributeItem(XMLNames::langAttr))
2501 value = attribute->value();
2502 else if (const Attribute* attribute = elementData->getAttributeItem(HTMLNames::langAttr))
2503 value = attribute->value();
2504 }
2505 } else if (n->isDocumentNode()) {
2506 // checking the MIME content-language
2507 value = toDocument(n)->contentLanguage();
2508 }
2509
2510 n = n->parentNode();
2511 } while (n && value.isNull());
2512
2513 return value;
2514}
2515
2516Locale& Element::locale() const
2517{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002518 return document().getCachedLocale(computeInheritedLanguage());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002519}
2520
2521void Element::cancelFocusAppearanceUpdate()
2522{
2523 if (hasRareData())
2524 elementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002525 if (document().focusedElement() == this)
2526 document().cancelFocusAppearanceUpdate();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002527}
2528
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002529void Element::updateCallbackSelectors(RenderStyle* oldStyle, RenderStyle* newStyle)
2530{
2531 const Vector<String> emptyVector;
2532 const Vector<String>& oldCallbackSelectors = oldStyle ? oldStyle->callbackSelectors() : emptyVector;
2533 const Vector<String>& newCallbackSelectors = newStyle ? newStyle->callbackSelectors() : emptyVector;
2534
2535 CSSSelectorWatch::from(document()).updateSelectorMatches(oldCallbackSelectors, newCallbackSelectors);
2536}
2537
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002538void Element::normalizeAttributes()
2539{
2540 if (!hasAttributes())
2541 return;
2542 for (unsigned i = 0; i < attributeCount(); ++i) {
2543 if (RefPtr<Attr> attr = attrIfExists(attributeItem(i)->name()))
2544 attr->normalize();
2545 }
2546}
2547
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002548void Element::updatePseudoElement(PseudoId pseudoId, StyleRecalcChange change)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002549{
2550 PseudoElement* element = pseudoElement(pseudoId);
2551 if (element && (needsStyleRecalc() || shouldRecalcStyle(change, element))) {
2552 // PseudoElement styles hang off their parent element's style so if we needed
2553 // a style recalc we should Force one on the pseudo.
2554 element->recalcStyle(needsStyleRecalc() ? Force : change);
2555
2556 // Wait until our parent is not displayed or pseudoElementRendererIsNeeded
2557 // is false, otherwise we could continously create and destroy PseudoElements
2558 // when RenderObject::isChildAllowed on our parent returns false for the
2559 // PseudoElement's renderer for each style recalc.
2560 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01002561 elementRareData()->setPseudoElement(pseudoId, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002562 } else if (change >= Inherit || needsStyleRecalc())
2563 createPseudoElementIfNeeded(pseudoId);
2564}
2565
2566void Element::createPseudoElementIfNeeded(PseudoId pseudoId)
2567{
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002568 if (needsPseudoElement(pseudoId))
2569 createPseudoElement(pseudoId);
2570}
2571
2572bool Element::needsPseudoElement(PseudoId pseudoId) const
2573{
Ben Murdoche69819b2013-07-17 14:56:49 +01002574 if (pseudoId == BACKDROP && !isInTopLayer())
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002575 return false;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002576 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002577 return false;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002578 if (!renderer()->canHaveGeneratedChildren())
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002579 return false;
2580 return true;
2581}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002582
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002583void Element::createPseudoElement(PseudoId pseudoId)
2584{
2585 ASSERT(needsPseudoElement(pseudoId));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002586 ASSERT(!isPseudoElement());
2587 RefPtr<PseudoElement> element = PseudoElement::create(this, pseudoId);
Ben Murdoche69819b2013-07-17 14:56:49 +01002588 if (pseudoId == BACKDROP)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002589 document().addToTopLayer(element.get(), this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002590 element->attach();
Ben Murdoche69819b2013-07-17 14:56:49 +01002591
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01002592 ensureElementRareData()->setPseudoElement(pseudoId, element.release());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002593}
2594
2595PseudoElement* Element::pseudoElement(PseudoId pseudoId) const
2596{
2597 return hasRareData() ? elementRareData()->pseudoElement(pseudoId) : 0;
2598}
2599
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002600RenderObject* Element::pseudoElementRenderer(PseudoId pseudoId) const
2601{
2602 if (PseudoElement* element = pseudoElement(pseudoId))
2603 return element->renderer();
2604 return 0;
2605}
2606
Ben Murdochdf957042013-08-06 11:01:27 +01002607bool Element::webkitMatchesSelector(const String& selector, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002608{
2609 if (selector.isEmpty()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01002610 es.throwUninformativeAndGenericDOMException(SyntaxError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002611 return false;
2612 }
2613
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002614 SelectorQuery* selectorQuery = document().selectorQueryCache()->add(selector, document(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002615 if (!selectorQuery)
2616 return false;
2617 return selectorQuery->matches(this);
2618}
2619
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002620DOMTokenList* Element::classList()
2621{
2622 ElementRareData* data = ensureElementRareData();
2623 if (!data->classList())
2624 data->setClassList(ClassList::create(this));
2625 return data->classList();
2626}
2627
2628DOMStringMap* Element::dataset()
2629{
2630 ElementRareData* data = ensureElementRareData();
2631 if (!data->dataset())
2632 data->setDataset(DatasetDOMStringMap::create(this));
2633 return data->dataset();
2634}
2635
2636KURL Element::getURLAttribute(const QualifiedName& name) const
2637{
2638#if !ASSERT_DISABLED
2639 if (elementData()) {
2640 if (const Attribute* attribute = getAttributeItem(name))
2641 ASSERT(isURLAttribute(*attribute));
2642 }
2643#endif
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002644 return document().completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002645}
2646
2647KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
2648{
2649#if !ASSERT_DISABLED
2650 if (elementData()) {
2651 if (const Attribute* attribute = getAttributeItem(name))
2652 ASSERT(isURLAttribute(*attribute));
2653 }
2654#endif
2655 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
2656 if (value.isEmpty())
2657 return KURL();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002658 return document().completeURL(value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002659}
2660
2661int Element::getIntegralAttribute(const QualifiedName& attributeName) const
2662{
2663 return getAttribute(attributeName).string().toInt();
2664}
2665
2666void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
2667{
2668 // FIXME: Need an AtomicString version of String::number.
2669 setAttribute(attributeName, String::number(value));
2670}
2671
2672unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
2673{
2674 return getAttribute(attributeName).string().toUInt();
2675}
2676
2677void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
2678{
2679 // FIXME: Need an AtomicString version of String::number.
2680 setAttribute(attributeName, String::number(value));
2681}
2682
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002683bool Element::childShouldCreateRenderer(const Node& child) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002684{
2685 // 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 +01002686 if (child.isSVGElement())
2687 return child.hasTagName(SVGNames::svgTag) || isSVGElement();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002688
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002689 return ContainerNode::childShouldCreateRenderer(child);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002690}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002691
2692void Element::webkitRequestFullscreen()
2693{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002694 FullscreenElementStack::from(&document())->requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002695}
2696
2697void Element::webkitRequestFullScreen(unsigned short flags)
2698{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002699 FullscreenElementStack::from(&document())->requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002700}
2701
2702bool Element::containsFullScreenElement() const
2703{
2704 return hasRareData() && elementRareData()->containsFullScreenElement();
2705}
2706
2707void Element::setContainsFullScreenElement(bool flag)
2708{
2709 ensureElementRareData()->setContainsFullScreenElement(flag);
Ben Murdoche69819b2013-07-17 14:56:49 +01002710 setNeedsStyleRecalc(SubtreeStyleChange);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002711}
2712
2713static Element* parentCrossingFrameBoundaries(Element* element)
2714{
2715 ASSERT(element);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002716 return element->parentElement() ? element->parentElement() : element->document().ownerElement();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002717}
2718
2719void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool flag)
2720{
2721 Element* element = this;
2722 while ((element = parentCrossingFrameBoundaries(element)))
2723 element->setContainsFullScreenElement(flag);
2724}
2725
2726bool Element::isInTopLayer() const
2727{
2728 return hasRareData() && elementRareData()->isInTopLayer();
2729}
2730
2731void Element::setIsInTopLayer(bool inTopLayer)
2732{
2733 if (isInTopLayer() == inTopLayer)
2734 return;
2735 ensureElementRareData()->setIsInTopLayer(inTopLayer);
2736
2737 // We must ensure a reattach occurs so the renderer is inserted in the correct sibling order under RenderView according to its
2738 // top layer position, or in its usual place if not in the top layer.
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002739 lazyReattachIfAttached();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002740}
2741
2742void Element::webkitRequestPointerLock()
2743{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002744 if (document().page())
2745 document().page()->pointerLockController().requestPointerLock(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002746}
2747
2748SpellcheckAttributeState Element::spellcheckAttributeState() const
2749{
2750 const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
2751 if (value == nullAtom)
2752 return SpellcheckAttributeDefault;
2753 if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
2754 return SpellcheckAttributeTrue;
2755 if (equalIgnoringCase(value, "false"))
2756 return SpellcheckAttributeFalse;
2757
2758 return SpellcheckAttributeDefault;
2759}
2760
2761bool Element::isSpellCheckingEnabled() const
2762{
2763 for (const Element* element = this; element; element = element->parentOrShadowHostElement()) {
2764 switch (element->spellcheckAttributeState()) {
2765 case SpellcheckAttributeTrue:
2766 return true;
2767 case SpellcheckAttributeFalse:
2768 return false;
2769 case SpellcheckAttributeDefault:
2770 break;
2771 }
2772 }
2773
2774 return true;
2775}
2776
2777RenderRegion* Element::renderRegion() const
2778{
2779 if (renderer() && renderer()->isRenderRegion())
2780 return toRenderRegion(renderer());
2781
2782 return 0;
2783}
2784
Ben Murdoch591b9582013-07-10 11:41:44 +01002785bool Element::shouldMoveToFlowThread(RenderStyle* styleToUse) const
2786{
2787 ASSERT(styleToUse);
2788
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002789 if (FullscreenElementStack::isActiveFullScreenElement(this))
Ben Murdoch591b9582013-07-10 11:41:44 +01002790 return false;
2791
2792 if (isInShadowTree())
2793 return false;
2794
2795 if (styleToUse->flowThread().isEmpty())
2796 return false;
2797
2798 return !isRegisteredWithNamedFlow();
2799}
2800
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002801const AtomicString& Element::webkitRegionOverset() const
2802{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002803 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002804
2805 DEFINE_STATIC_LOCAL(AtomicString, undefinedState, ("undefined", AtomicString::ConstructFromLiteral));
2806 if (!RuntimeEnabledFeatures::cssRegionsEnabled() || !renderRegion())
2807 return undefinedState;
2808
Ben Murdoch591b9582013-07-10 11:41:44 +01002809 switch (renderRegion()->regionOversetState()) {
2810 case RegionFit: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002811 DEFINE_STATIC_LOCAL(AtomicString, fitState, ("fit", AtomicString::ConstructFromLiteral));
2812 return fitState;
2813 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002814 case RegionEmpty: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002815 DEFINE_STATIC_LOCAL(AtomicString, emptyState, ("empty", AtomicString::ConstructFromLiteral));
2816 return emptyState;
2817 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002818 case RegionOverset: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002819 DEFINE_STATIC_LOCAL(AtomicString, overflowState, ("overset", AtomicString::ConstructFromLiteral));
2820 return overflowState;
2821 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002822 case RegionUndefined:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002823 return undefinedState;
2824 }
2825
2826 ASSERT_NOT_REACHED();
2827 return undefinedState;
2828}
2829
2830Vector<RefPtr<Range> > Element::webkitGetRegionFlowRanges() const
2831{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002832 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002833
2834 Vector<RefPtr<Range> > rangeObjects;
2835 if (RuntimeEnabledFeatures::cssRegionsEnabled() && renderer() && renderer()->isRenderRegion()) {
2836 RenderRegion* region = toRenderRegion(renderer());
2837 if (region->isValid())
2838 region->getRanges(rangeObjects);
2839 }
2840
2841 return rangeObjects;
2842}
2843
2844#ifndef NDEBUG
2845bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
2846{
2847 if (name == HTMLNames::styleAttr)
2848 return false;
2849
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002850 if (isSVGElement())
2851 return !static_cast<const SVGElement*>(this)->isAnimatableAttribute(name);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002852
2853 return true;
2854}
2855#endif
2856
2857#ifdef DUMP_NODE_STATISTICS
2858bool Element::hasNamedNodeMap() const
2859{
2860 return hasRareData() && elementRareData()->attributeMap();
2861}
2862#endif
2863
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002864inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002865{
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002866 if (!inDocument() || isInShadowTree())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002867 return;
2868
2869 if (oldName == newName)
2870 return;
2871
Ben Murdochdf957042013-08-06 11:01:27 +01002872 if (shouldRegisterAsNamedItem())
2873 updateNamedItemRegistration(oldName, newName);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002874}
2875
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002876inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002877{
2878 if (!isInTreeScope())
2879 return;
2880
2881 if (oldId == newId)
2882 return;
2883
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002884 updateId(treeScope(), oldId, newId);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002885}
2886
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002887inline void Element::updateId(TreeScope& scope, const AtomicString& oldId, const AtomicString& newId)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002888{
2889 ASSERT(isInTreeScope());
2890 ASSERT(oldId != newId);
2891
2892 if (!oldId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002893 scope.removeElementById(oldId, this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002894 if (!newId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002895 scope.addElementById(newId, this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002896
Ben Murdochdf957042013-08-06 11:01:27 +01002897 if (shouldRegisterAsExtraNamedItem())
2898 updateExtraNamedItemRegistration(oldId, newId);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002899}
2900
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002901void Element::updateLabel(TreeScope& scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002902{
2903 ASSERT(hasTagName(labelTag));
2904
2905 if (!inDocument())
2906 return;
2907
2908 if (oldForAttributeValue == newForAttributeValue)
2909 return;
2910
2911 if (!oldForAttributeValue.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002912 scope.removeLabel(oldForAttributeValue, toHTMLLabelElement(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002913 if (!newForAttributeValue.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002914 scope.addLabel(newForAttributeValue, toHTMLLabelElement(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002915}
2916
Ben Murdoch7757ec22013-07-23 11:17:36 +01002917static bool hasSelectorForAttribute(Document* document, const AtomicString& localName)
2918{
2919 return document->styleResolver() && document->styleResolver()->ruleFeatureSet().hasSelectorForAttribute(localName);
2920}
2921
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002922void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
2923{
2924 if (isIdAttributeName(name))
2925 updateId(oldValue, newValue);
2926 else if (name == HTMLNames::nameAttr)
2927 updateName(oldValue, newValue);
2928 else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002929 TreeScope& scope = treeScope();
2930 if (scope.shouldCacheLabelsByForAttribute())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002931 updateLabel(scope, oldValue, newValue);
2932 }
2933
2934 if (oldValue != newValue) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002935 if (confusingAndOftenMisusedAttached() && hasSelectorForAttribute(&document(), name.localName()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002936 setNeedsStyleRecalc();
Ben Murdoche69819b2013-07-17 14:56:49 +01002937
2938 if (isUpgradedCustomElement())
Ben Murdoch83750172013-07-24 10:36:59 +01002939 CustomElement::attributeDidChange(this, name.localName(), oldValue, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002940 }
2941
2942 if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(this, name))
2943 recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue));
2944
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002945 InspectorInstrumentation::willModifyDOMAttr(&document(), this, oldValue, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002946}
2947
2948void Element::didAddAttribute(const QualifiedName& name, const AtomicString& value)
2949{
2950 attributeChanged(name, value);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002951 InspectorInstrumentation::didModifyDOMAttr(&document(), this, name.localName(), value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002952 dispatchSubtreeModifiedEvent();
2953}
2954
2955void Element::didModifyAttribute(const QualifiedName& name, const AtomicString& value)
2956{
2957 attributeChanged(name, value);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002958 InspectorInstrumentation::didModifyDOMAttr(&document(), this, name.localName(), value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002959 // Do not dispatch a DOMSubtreeModified event here; see bug 81141.
2960}
2961
2962void Element::didRemoveAttribute(const QualifiedName& name)
2963{
2964 attributeChanged(name, nullAtom);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002965 InspectorInstrumentation::didRemoveDOMAttr(&document(), this, name.localName());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002966 dispatchSubtreeModifiedEvent();
2967}
2968
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002969void Element::didMoveToNewDocument(Document& oldDocument)
Ben Murdoche69819b2013-07-17 14:56:49 +01002970{
2971 Node::didMoveToNewDocument(oldDocument);
2972
2973 // If the documents differ by quirks mode then they differ by case sensitivity
2974 // for class and id names so we need to go through the attribute change logic
2975 // to pick up the new casing in the ElementData.
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002976 if (oldDocument.inQuirksMode() != document().inQuirksMode()) {
Ben Murdoche69819b2013-07-17 14:56:49 +01002977 if (hasID())
2978 setIdAttribute(getIdAttribute());
2979 if (hasClass())
2980 setAttribute(HTMLNames::classAttr, getClassAttribute());
2981 }
2982}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002983
Ben Murdochdf957042013-08-06 11:01:27 +01002984void Element::updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName)
2985{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002986 if (!document().isHTMLDocument())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002987 return;
Ben Murdochdf957042013-08-06 11:01:27 +01002988
2989 if (!oldName.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002990 toHTMLDocument(document()).removeNamedItem(oldName);
Ben Murdochdf957042013-08-06 11:01:27 +01002991
2992 if (!newName.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002993 toHTMLDocument(document()).addNamedItem(newName);
Ben Murdochdf957042013-08-06 11:01:27 +01002994}
2995
2996void Element::updateExtraNamedItemRegistration(const AtomicString& oldId, const AtomicString& newId)
2997{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002998 if (!document().isHTMLDocument())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002999 return;
Ben Murdochdf957042013-08-06 11:01:27 +01003000
3001 if (!oldId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003002 toHTMLDocument(document()).removeExtraNamedItem(oldId);
Ben Murdochdf957042013-08-06 11:01:27 +01003003
3004 if (!newId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003005 toHTMLDocument(document()).addExtraNamedItem(newId);
Ben Murdochdf957042013-08-06 11:01:27 +01003006}
3007
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003008PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
3009{
3010 if (HTMLCollection* collection = cachedHTMLCollection(type))
3011 return collection;
3012
3013 RefPtr<HTMLCollection> collection;
3014 if (type == TableRows) {
3015 ASSERT(hasTagName(tableTag));
3016 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
3017 } else if (type == SelectOptions) {
3018 ASSERT(hasTagName(selectTag));
3019 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
3020 } else if (type == FormControls) {
3021 ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
3022 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
3023 }
3024 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLCollection>(this, type);
3025}
3026
Ben Murdoch591b9582013-07-10 11:41:44 +01003027static void scheduleLayerUpdateCallback(Node* node)
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003028{
Ben Murdoche69819b2013-07-17 14:56:49 +01003029 // Notify the renderer even is the styles are identical since it may need to
3030 // create or destroy a RenderLayer.
3031 node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003032}
3033
Ben Murdoch591b9582013-07-10 11:41:44 +01003034void Element::scheduleLayerUpdate()
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003035{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003036 if (document().inStyleRecalc())
3037 PostAttachCallbacks::queueCallback(scheduleLayerUpdateCallback, this);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003038 else
Ben Murdoche69819b2013-07-17 14:56:49 +01003039 scheduleLayerUpdateCallback(this);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003040}
3041
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003042HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
3043{
3044 return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0;
3045}
3046
3047IntSize Element::savedLayerScrollOffset() const
3048{
3049 return hasRareData() ? elementRareData()->savedLayerScrollOffset() : IntSize();
3050}
3051
3052void Element::setSavedLayerScrollOffset(const IntSize& size)
3053{
3054 if (size.isZero() && !hasRareData())
3055 return;
3056 ensureElementRareData()->setSavedLayerScrollOffset(size);
3057}
3058
3059PassRefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
3060{
3061 if (AttrNodeList* attrNodeList = attrNodeListForElement(this))
3062 return findAttrNodeInList(attrNodeList, name);
3063 return 0;
3064}
3065
3066PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name)
3067{
3068 AttrNodeList* attrNodeList = ensureAttrNodeListForElement(this);
3069 RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
3070 if (!attrNode) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003071 attrNode = Attr::create(*this, name);
3072 treeScope().adoptIfNeeded(attrNode.get());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003073 attrNodeList->append(attrNode);
3074 }
3075 return attrNode.release();
3076}
3077
3078void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value)
3079{
3080 ASSERT(hasSyntheticAttrChildNodes());
3081 attrNode->detachFromElementWithValue(value);
3082
3083 AttrNodeList* attrNodeList = attrNodeListForElement(this);
3084 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
3085 if (attrNodeList->at(i)->qualifiedName() == attrNode->qualifiedName()) {
3086 attrNodeList->remove(i);
3087 if (attrNodeList->isEmpty())
3088 removeAttrNodeListForElement(this);
3089 return;
3090 }
3091 }
3092 ASSERT_NOT_REACHED();
3093}
3094
3095void Element::detachAllAttrNodesFromElement()
3096{
3097 AttrNodeList* attrNodeList = attrNodeListForElement(this);
3098 ASSERT(attrNodeList);
3099
3100 for (unsigned i = 0; i < attributeCount(); ++i) {
3101 const Attribute* attribute = attributeItem(i);
3102 if (RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, attribute->name()))
3103 attrNode->detachFromElementWithValue(attribute->value());
3104 }
3105
3106 removeAttrNodeListForElement(this);
3107}
3108
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003109void Element::willRecalcStyle(StyleRecalcChange)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003110{
3111 ASSERT(hasCustomStyleCallbacks());
3112}
3113
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003114void Element::didRecalcStyle(StyleRecalcChange)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003115{
3116 ASSERT(hasCustomStyleCallbacks());
3117}
3118
3119
3120PassRefPtr<RenderStyle> Element::customStyleForRenderer()
3121{
3122 ASSERT(hasCustomStyleCallbacks());
3123 return 0;
3124}
3125
3126void Element::cloneAttributesFromElement(const Element& other)
3127{
3128 if (hasSyntheticAttrChildNodes())
3129 detachAllAttrNodesFromElement();
3130
3131 other.synchronizeAllAttributes();
3132 if (!other.m_elementData) {
3133 m_elementData.clear();
3134 return;
3135 }
3136
3137 const AtomicString& oldID = getIdAttribute();
3138 const AtomicString& newID = other.getIdAttribute();
3139
3140 if (!oldID.isNull() || !newID.isNull())
3141 updateId(oldID, newID);
3142
3143 const AtomicString& oldName = getNameAttribute();
3144 const AtomicString& newName = other.getNameAttribute();
3145
3146 if (!oldName.isNull() || !newName.isNull())
3147 updateName(oldName, newName);
3148
Ben Murdoche69819b2013-07-17 14:56:49 +01003149 // Quirks mode makes class and id not case sensitive. We can't share the ElementData
3150 // if the idForStyleResolution and the className need different casing.
3151 bool ownerDocumentsHaveDifferentCaseSensitivity = false;
3152 if (other.hasClass() || other.hasID())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003153 ownerDocumentsHaveDifferentCaseSensitivity = other.document().inQuirksMode() != document().inQuirksMode();
Ben Murdoche69819b2013-07-17 14:56:49 +01003154
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003155 // 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 +01003156 // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes,
3157 // and sharing the data won't result in different case sensitivity of class or id.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003158 if (other.m_elementData->isUnique()
Ben Murdoche69819b2013-07-17 14:56:49 +01003159 && !ownerDocumentsHaveDifferentCaseSensitivity
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003160 && !other.m_elementData->presentationAttributeStyle()
3161 && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper()))
3162 const_cast<Element&>(other).m_elementData = static_cast<const UniqueElementData*>(other.m_elementData.get())->makeShareableCopy();
3163
Ben Murdoche69819b2013-07-17 14:56:49 +01003164 if (!other.m_elementData->isUnique() && !ownerDocumentsHaveDifferentCaseSensitivity)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003165 m_elementData = other.m_elementData;
3166 else
3167 m_elementData = other.m_elementData->makeUniqueCopy();
3168
3169 for (unsigned i = 0; i < m_elementData->length(); ++i) {
3170 const Attribute* attribute = const_cast<const ElementData*>(m_elementData.get())->attributeItem(i);
3171 attributeChangedFromParserOrByCloning(attribute->name(), attribute->value(), ModifiedByCloning);
3172 }
3173}
3174
3175void Element::cloneDataFromElement(const Element& other)
3176{
3177 cloneAttributesFromElement(other);
3178 copyNonAttributePropertiesFromElement(other);
3179}
3180
3181void Element::createUniqueElementData()
3182{
3183 if (!m_elementData)
3184 m_elementData = UniqueElementData::create();
3185 else {
3186 ASSERT(!m_elementData->isUnique());
3187 m_elementData = static_cast<ShareableElementData*>(m_elementData.get())->makeUniqueCopy();
3188 }
3189}
3190
Ben Murdoch1fad5ca2013-08-07 11:05:11 +01003191InputMethodContext* Element::inputMethodContext()
Torne (Richard Coles)81a51572013-05-13 16:52:28 +01003192{
3193 return ensureElementRareData()->ensureInputMethodContext(toHTMLElement(this));
3194}
3195
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003196bool Element::hasPendingResources() const
3197{
3198 return hasRareData() && elementRareData()->hasPendingResources();
3199}
3200
3201void Element::setHasPendingResources()
3202{
3203 ensureElementRareData()->setHasPendingResources(true);
3204}
3205
3206void Element::clearHasPendingResources()
3207{
3208 ensureElementRareData()->setHasPendingResources(false);
3209}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003210
Ben Murdoch591b9582013-07-10 11:41:44 +01003211struct PresentationAttributeCacheKey {
3212 PresentationAttributeCacheKey() : tagName(0) { }
Ben Murdoch83750172013-07-24 10:36:59 +01003213 StringImpl* tagName;
Ben Murdoch591b9582013-07-10 11:41:44 +01003214 // Only the values need refcounting.
Ben Murdoch83750172013-07-24 10:36:59 +01003215 Vector<pair<StringImpl*, AtomicString>, 3> attributesAndValues;
Ben Murdoch591b9582013-07-10 11:41:44 +01003216};
3217
3218struct PresentationAttributeCacheEntry {
3219 WTF_MAKE_FAST_ALLOCATED;
3220public:
3221 PresentationAttributeCacheKey key;
3222 RefPtr<StylePropertySet> value;
3223};
3224
3225typedef HashMap<unsigned, OwnPtr<PresentationAttributeCacheEntry>, AlreadyHashed> PresentationAttributeCache;
3226
3227static bool operator!=(const PresentationAttributeCacheKey& a, const PresentationAttributeCacheKey& b)
3228{
3229 if (a.tagName != b.tagName)
3230 return true;
3231 return a.attributesAndValues != b.attributesAndValues;
3232}
3233
3234static PresentationAttributeCache& presentationAttributeCache()
3235{
3236 DEFINE_STATIC_LOCAL(PresentationAttributeCache, cache, ());
3237 return cache;
3238}
3239
3240class PresentationAttributeCacheCleaner {
3241 WTF_MAKE_NONCOPYABLE(PresentationAttributeCacheCleaner); WTF_MAKE_FAST_ALLOCATED;
3242public:
3243 PresentationAttributeCacheCleaner()
3244 : m_hitCount(0)
3245 , m_cleanTimer(this, &PresentationAttributeCacheCleaner::cleanCache)
3246 {
3247 }
3248
3249 void didHitPresentationAttributeCache()
3250 {
3251 if (presentationAttributeCache().size() < minimumPresentationAttributeCacheSizeForCleaning)
3252 return;
3253
3254 m_hitCount++;
3255
3256 if (!m_cleanTimer.isActive())
3257 m_cleanTimer.startOneShot(presentationAttributeCacheCleanTimeInSeconds);
3258 }
3259
3260private:
3261 static const unsigned presentationAttributeCacheCleanTimeInSeconds = 60;
3262 static const int minimumPresentationAttributeCacheSizeForCleaning = 100;
3263 static const unsigned minimumPresentationAttributeCacheHitCountPerMinute = (100 * presentationAttributeCacheCleanTimeInSeconds) / 60;
3264
3265 void cleanCache(Timer<PresentationAttributeCacheCleaner>* timer)
3266 {
3267 ASSERT_UNUSED(timer, timer == &m_cleanTimer);
3268 unsigned hitCount = m_hitCount;
3269 m_hitCount = 0;
3270 if (hitCount > minimumPresentationAttributeCacheHitCountPerMinute)
3271 return;
3272 presentationAttributeCache().clear();
3273 }
3274
3275 unsigned m_hitCount;
3276 Timer<PresentationAttributeCacheCleaner> m_cleanTimer;
3277};
3278
3279static PresentationAttributeCacheCleaner& presentationAttributeCacheCleaner()
3280{
3281 DEFINE_STATIC_LOCAL(PresentationAttributeCacheCleaner, cleaner, ());
3282 return cleaner;
3283}
3284
3285void Element::synchronizeStyleAttributeInternal() const
3286{
3287 ASSERT(isStyledElement());
3288 ASSERT(elementData());
3289 ASSERT(elementData()->m_styleAttributeIsDirty);
3290 elementData()->m_styleAttributeIsDirty = false;
3291 if (const StylePropertySet* inlineStyle = this->inlineStyle())
3292 const_cast<Element*>(this)->setSynchronizedLazyAttribute(styleAttr, inlineStyle->asText());
3293}
3294
3295CSSStyleDeclaration* Element::style()
3296{
3297 if (!isStyledElement())
3298 return 0;
3299 return ensureMutableInlineStyle()->ensureInlineCSSStyleDeclaration(this);
3300}
3301
3302MutableStylePropertySet* Element::ensureMutableInlineStyle()
3303{
3304 ASSERT(isStyledElement());
3305 RefPtr<StylePropertySet>& inlineStyle = ensureUniqueElementData()->m_inlineStyle;
3306 if (!inlineStyle)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003307 inlineStyle = MutableStylePropertySet::create(strictToCSSParserMode(isHTMLElement() && !document().inQuirksMode()));
Ben Murdoch591b9582013-07-10 11:41:44 +01003308 else if (!inlineStyle->isMutable())
3309 inlineStyle = inlineStyle->mutableCopy();
3310 ASSERT(inlineStyle->isMutable());
3311 return static_cast<MutableStylePropertySet*>(inlineStyle.get());
3312}
3313
3314PropertySetCSSStyleDeclaration* Element::inlineStyleCSSOMWrapper()
3315{
3316 if (!inlineStyle() || !inlineStyle()->hasCSSOMWrapper())
3317 return 0;
3318 PropertySetCSSStyleDeclaration* cssomWrapper = ensureMutableInlineStyle()->cssStyleDeclaration();
3319 ASSERT(cssomWrapper && cssomWrapper->parentElement() == this);
3320 return cssomWrapper;
3321}
3322
3323inline void Element::setInlineStyleFromString(const AtomicString& newStyleString)
3324{
3325 ASSERT(isStyledElement());
3326 RefPtr<StylePropertySet>& inlineStyle = elementData()->m_inlineStyle;
3327
3328 // Avoid redundant work if we're using shared attribute data with already parsed inline style.
3329 if (inlineStyle && !elementData()->isUnique())
3330 return;
3331
3332 // We reconstruct the property set instead of mutating if there is no CSSOM wrapper.
3333 // This makes wrapperless property sets immutable and so cacheable.
3334 if (inlineStyle && !inlineStyle->isMutable())
3335 inlineStyle.clear();
3336
3337 if (!inlineStyle) {
3338 inlineStyle = CSSParser::parseInlineStyleDeclaration(newStyleString, this);
3339 } else {
3340 ASSERT(inlineStyle->isMutable());
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003341 static_pointer_cast<MutableStylePropertySet>(inlineStyle)->parseDeclaration(newStyleString, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003342 }
3343}
3344
3345void Element::styleAttributeChanged(const AtomicString& newStyleString, AttributeModificationReason modificationReason)
3346{
3347 ASSERT(isStyledElement());
3348 WTF::OrdinalNumber startLineNumber = WTF::OrdinalNumber::beforeFirst();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003349 if (document().scriptableDocumentParser() && !document().isInDocumentWrite())
3350 startLineNumber = document().scriptableDocumentParser()->lineNumber();
Ben Murdoch591b9582013-07-10 11:41:44 +01003351
3352 if (newStyleString.isNull()) {
3353 if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
3354 cssomWrapper->clearParentElement();
3355 ensureUniqueElementData()->m_inlineStyle.clear();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003356 } else if (modificationReason == ModifiedByCloning || document().contentSecurityPolicy()->allowInlineStyle(document().url(), startLineNumber)) {
Ben Murdoch591b9582013-07-10 11:41:44 +01003357 setInlineStyleFromString(newStyleString);
3358 }
3359
3360 elementData()->m_styleAttributeIsDirty = false;
3361
Ben Murdoche69819b2013-07-17 14:56:49 +01003362 setNeedsStyleRecalc(LocalStyleChange);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003363 InspectorInstrumentation::didInvalidateStyleAttr(&document(), this);
Ben Murdoch591b9582013-07-10 11:41:44 +01003364}
3365
3366void Element::inlineStyleChanged()
3367{
3368 ASSERT(isStyledElement());
Ben Murdoche69819b2013-07-17 14:56:49 +01003369 setNeedsStyleRecalc(LocalStyleChange);
Ben Murdoch591b9582013-07-10 11:41:44 +01003370 ASSERT(elementData());
3371 elementData()->m_styleAttributeIsDirty = true;
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003372 InspectorInstrumentation::didInvalidateStyleAttr(&document(), this);
Ben Murdoch591b9582013-07-10 11:41:44 +01003373}
3374
3375bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
3376{
3377 ASSERT(isStyledElement());
3378 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
3379 inlineStyleChanged();
3380 return true;
3381}
3382
3383bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
3384{
3385 ASSERT(isStyledElement());
3386 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
3387 inlineStyleChanged();
3388 return true;
3389}
3390
3391bool Element::setInlineStyleProperty(CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit, bool important)
3392{
3393 ASSERT(isStyledElement());
3394 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createValue(value, unit), important);
3395 inlineStyleChanged();
3396 return true;
3397}
3398
3399bool Element::setInlineStyleProperty(CSSPropertyID propertyID, const String& value, bool important)
3400{
3401 ASSERT(isStyledElement());
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003402 bool changes = ensureMutableInlineStyle()->setProperty(propertyID, value, important, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003403 if (changes)
3404 inlineStyleChanged();
3405 return changes;
3406}
3407
3408bool Element::removeInlineStyleProperty(CSSPropertyID propertyID)
3409{
3410 ASSERT(isStyledElement());
3411 if (!inlineStyle())
3412 return false;
3413 bool changes = ensureMutableInlineStyle()->removeProperty(propertyID);
3414 if (changes)
3415 inlineStyleChanged();
3416 return changes;
3417}
3418
3419void Element::removeAllInlineStyleProperties()
3420{
3421 ASSERT(isStyledElement());
3422 if (!inlineStyle() || inlineStyle()->isEmpty())
3423 return;
3424 ensureMutableInlineStyle()->clear();
3425 inlineStyleChanged();
3426}
3427
3428void Element::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
3429{
3430 ASSERT(isStyledElement());
3431 if (const StylePropertySet* inlineStyle = elementData() ? elementData()->inlineStyle() : 0)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003432 inlineStyle->addSubresourceStyleURLs(urls, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003433}
3434
Ben Murdoch83750172013-07-24 10:36:59 +01003435static inline bool attributeNameSort(const pair<StringImpl*, AtomicString>& p1, const pair<StringImpl*, AtomicString>& p2)
Ben Murdoch591b9582013-07-10 11:41:44 +01003436{
3437 // Sort based on the attribute name pointers. It doesn't matter what the order is as long as it is always the same.
3438 return p1.first < p2.first;
3439}
3440
3441void Element::makePresentationAttributeCacheKey(PresentationAttributeCacheKey& result) const
3442{
3443 ASSERT(isStyledElement());
3444 // FIXME: Enable for SVG.
3445 if (namespaceURI() != xhtmlNamespaceURI)
3446 return;
3447 // Interpretation of the size attributes on <input> depends on the type attribute.
3448 if (hasTagName(inputTag))
3449 return;
3450 unsigned size = attributeCount();
3451 for (unsigned i = 0; i < size; ++i) {
3452 const Attribute* attribute = attributeItem(i);
3453 if (!isPresentationAttribute(attribute->name()))
3454 continue;
3455 if (!attribute->namespaceURI().isNull())
3456 return;
3457 // FIXME: Background URL may depend on the base URL and can't be shared. Disallow caching.
3458 if (attribute->name() == backgroundAttr)
3459 return;
3460 result.attributesAndValues.append(std::make_pair(attribute->localName().impl(), attribute->value()));
3461 }
3462 if (result.attributesAndValues.isEmpty())
3463 return;
3464 // Attribute order doesn't matter. Sort for easy equality comparison.
3465 std::sort(result.attributesAndValues.begin(), result.attributesAndValues.end(), attributeNameSort);
3466 // The cache key is non-null when the tagName is set.
3467 result.tagName = localName().impl();
3468}
3469
3470static unsigned computePresentationAttributeCacheHash(const PresentationAttributeCacheKey& key)
3471{
3472 if (!key.tagName)
3473 return 0;
3474 ASSERT(key.attributesAndValues.size());
3475 unsigned attributeHash = StringHasher::hashMemory(key.attributesAndValues.data(), key.attributesAndValues.size() * sizeof(key.attributesAndValues[0]));
3476 return WTF::pairIntHash(key.tagName->existingHash(), attributeHash);
3477}
3478
3479void Element::rebuildPresentationAttributeStyle()
3480{
3481 ASSERT(isStyledElement());
3482 PresentationAttributeCacheKey cacheKey;
3483 makePresentationAttributeCacheKey(cacheKey);
3484
3485 unsigned cacheHash = computePresentationAttributeCacheHash(cacheKey);
3486
3487 PresentationAttributeCache::iterator cacheIterator;
3488 if (cacheHash) {
3489 cacheIterator = presentationAttributeCache().add(cacheHash, nullptr).iterator;
3490 if (cacheIterator->value && cacheIterator->value->key != cacheKey)
3491 cacheHash = 0;
3492 } else {
3493 cacheIterator = presentationAttributeCache().end();
3494 }
3495
3496 RefPtr<StylePropertySet> style;
3497 if (cacheHash && cacheIterator->value) {
3498 style = cacheIterator->value->value;
3499 presentationAttributeCacheCleaner().didHitPresentationAttributeCache();
3500 } else {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01003501 style = MutableStylePropertySet::create(isSVGElement() ? SVGAttributeMode : CSSAttributeMode);
Ben Murdoch591b9582013-07-10 11:41:44 +01003502 unsigned size = attributeCount();
3503 for (unsigned i = 0; i < size; ++i) {
3504 const Attribute* attribute = attributeItem(i);
3505 collectStyleForPresentationAttribute(attribute->name(), attribute->value(), static_cast<MutableStylePropertySet*>(style.get()));
3506 }
3507 }
3508
3509 // ShareableElementData doesn't store presentation attribute style, so make sure we have a UniqueElementData.
3510 UniqueElementData* elementData = ensureUniqueElementData();
3511
3512 elementData->m_presentationAttributeStyleIsDirty = false;
3513 elementData->m_presentationAttributeStyle = style->isEmpty() ? 0 : style;
3514
3515 if (!cacheHash || cacheIterator->value)
3516 return;
3517
3518 OwnPtr<PresentationAttributeCacheEntry> newEntry = adoptPtr(new PresentationAttributeCacheEntry);
3519 newEntry->key = cacheKey;
3520 newEntry->value = style.release();
3521
3522 static const int presentationAttributeCacheMaximumSize = 4096;
3523 if (presentationAttributeCache().size() > presentationAttributeCacheMaximumSize) {
3524 // Start building from scratch if the cache ever gets big.
3525 presentationAttributeCache().clear();
3526 presentationAttributeCache().set(cacheHash, newEntry.release());
3527 } else {
3528 cacheIterator->value = newEntry.release();
3529 }
3530}
3531
3532void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, CSSValueID identifier)
3533{
3534 ASSERT(isStyledElement());
3535 style->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier));
3536}
3537
3538void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit)
3539{
3540 ASSERT(isStyledElement());
3541 style->setProperty(propertyID, cssValuePool().createValue(value, unit));
3542}
3543
3544void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, const String& value)
3545{
3546 ASSERT(isStyledElement());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01003547 style->setProperty(propertyID, value, false);
Ben Murdoch591b9582013-07-10 11:41:44 +01003548}
3549
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003550void ElementData::deref()
3551{
3552 if (!derefBase())
3553 return;
3554
3555 if (m_isUnique)
3556 delete static_cast<UniqueElementData*>(this);
3557 else
3558 delete static_cast<ShareableElementData*>(this);
3559}
3560
3561ElementData::ElementData()
3562 : m_isUnique(true)
3563 , m_arraySize(0)
3564 , m_presentationAttributeStyleIsDirty(false)
3565 , m_styleAttributeIsDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003566 , m_animatedSVGAttributesAreDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003567{
3568}
3569
3570ElementData::ElementData(unsigned arraySize)
3571 : m_isUnique(false)
3572 , m_arraySize(arraySize)
3573 , m_presentationAttributeStyleIsDirty(false)
3574 , m_styleAttributeIsDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003575 , m_animatedSVGAttributesAreDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003576{
3577}
3578
3579struct SameSizeAsElementData : public RefCounted<SameSizeAsElementData> {
3580 unsigned bitfield;
3581 void* refPtrs[3];
3582};
3583
3584COMPILE_ASSERT(sizeof(ElementData) == sizeof(SameSizeAsElementData), element_attribute_data_should_stay_small);
3585
3586static size_t sizeForShareableElementDataWithAttributeCount(unsigned count)
3587{
3588 return sizeof(ShareableElementData) + sizeof(Attribute) * count;
3589}
3590
3591PassRefPtr<ShareableElementData> ShareableElementData::createWithAttributes(const Vector<Attribute>& attributes)
3592{
3593 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(attributes.size()));
3594 return adoptRef(new (slot) ShareableElementData(attributes));
3595}
3596
3597PassRefPtr<UniqueElementData> UniqueElementData::create()
3598{
3599 return adoptRef(new UniqueElementData);
3600}
3601
3602ShareableElementData::ShareableElementData(const Vector<Attribute>& attributes)
3603 : ElementData(attributes.size())
3604{
3605 for (unsigned i = 0; i < m_arraySize; ++i)
3606 new (&m_attributeArray[i]) Attribute(attributes[i]);
3607}
3608
3609ShareableElementData::~ShareableElementData()
3610{
3611 for (unsigned i = 0; i < m_arraySize; ++i)
3612 m_attributeArray[i].~Attribute();
3613}
3614
3615ShareableElementData::ShareableElementData(const UniqueElementData& other)
3616 : ElementData(other, false)
3617{
3618 ASSERT(!other.m_presentationAttributeStyle);
3619
3620 if (other.m_inlineStyle) {
3621 ASSERT(!other.m_inlineStyle->hasCSSOMWrapper());
3622 m_inlineStyle = other.m_inlineStyle->immutableCopyIfNeeded();
3623 }
3624
3625 for (unsigned i = 0; i < m_arraySize; ++i)
3626 new (&m_attributeArray[i]) Attribute(other.m_attributeVector.at(i));
3627}
3628
3629ElementData::ElementData(const ElementData& other, bool isUnique)
3630 : m_isUnique(isUnique)
3631 , m_arraySize(isUnique ? 0 : other.length())
3632 , m_presentationAttributeStyleIsDirty(other.m_presentationAttributeStyleIsDirty)
3633 , m_styleAttributeIsDirty(other.m_styleAttributeIsDirty)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003634 , m_animatedSVGAttributesAreDirty(other.m_animatedSVGAttributesAreDirty)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003635 , m_classNames(other.m_classNames)
3636 , m_idForStyleResolution(other.m_idForStyleResolution)
3637{
3638 // NOTE: The inline style is copied by the subclass copy constructor since we don't know what to do with it here.
3639}
3640
3641UniqueElementData::UniqueElementData()
3642{
3643}
3644
3645UniqueElementData::UniqueElementData(const UniqueElementData& other)
3646 : ElementData(other, true)
3647 , m_presentationAttributeStyle(other.m_presentationAttributeStyle)
3648 , m_attributeVector(other.m_attributeVector)
3649{
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003650 m_inlineStyle = other.m_inlineStyle ? other.m_inlineStyle->mutableCopy() : 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003651}
3652
3653UniqueElementData::UniqueElementData(const ShareableElementData& other)
3654 : ElementData(other, true)
3655{
3656 // An ShareableElementData should never have a mutable inline StylePropertySet attached.
3657 ASSERT(!other.m_inlineStyle || !other.m_inlineStyle->isMutable());
3658 m_inlineStyle = other.m_inlineStyle;
3659
3660 m_attributeVector.reserveCapacity(other.length());
3661 for (unsigned i = 0; i < other.length(); ++i)
3662 m_attributeVector.uncheckedAppend(other.m_attributeArray[i]);
3663}
3664
3665PassRefPtr<UniqueElementData> ElementData::makeUniqueCopy() const
3666{
3667 if (isUnique())
3668 return adoptRef(new UniqueElementData(static_cast<const UniqueElementData&>(*this)));
3669 return adoptRef(new UniqueElementData(static_cast<const ShareableElementData&>(*this)));
3670}
3671
3672PassRefPtr<ShareableElementData> UniqueElementData::makeShareableCopy() const
3673{
3674 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(m_attributeVector.size()));
3675 return adoptRef(new (slot) ShareableElementData(*this));
3676}
3677
3678void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value)
3679{
3680 m_attributeVector.append(Attribute(attributeName, value));
3681}
3682
3683void UniqueElementData::removeAttribute(size_t index)
3684{
3685 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
3686 m_attributeVector.remove(index);
3687}
3688
3689bool ElementData::isEquivalent(const ElementData* other) const
3690{
3691 if (!other)
3692 return isEmpty();
3693
3694 unsigned len = length();
3695 if (len != other->length())
3696 return false;
3697
3698 for (unsigned i = 0; i < len; i++) {
3699 const Attribute* attribute = attributeItem(i);
3700 const Attribute* otherAttr = other->getAttributeItem(attribute->name());
3701 if (!otherAttr || attribute->value() != otherAttr->value())
3702 return false;
3703 }
3704
3705 return true;
3706}
3707
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01003708size_t ElementData::getAttrIndex(Attr* attr) const
3709{
3710 // This relies on the fact that Attr's QualifiedName == the Attribute's name.
3711 for (unsigned i = 0; i < length(); ++i) {
3712 if (attributeItem(i)->name() == attr->qualifiedName())
3713 return i;
3714 }
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01003715 return kNotFound;
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01003716}
3717
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003718size_t ElementData::getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const
3719{
3720 // Continue to checking case-insensitively and/or full namespaced names if necessary:
3721 for (unsigned i = 0; i < length(); ++i) {
3722 const Attribute* attribute = attributeItem(i);
3723 if (!attribute->name().hasPrefix()) {
3724 if (shouldIgnoreAttributeCase && equalIgnoringCase(name, attribute->localName()))
3725 return i;
3726 } else {
3727 // FIXME: Would be faster to do this comparison without calling toString, which
3728 // generates a temporary string by concatenation. But this branch is only reached
3729 // if the attribute name has a prefix, which is rare in HTML.
3730 if (equalPossiblyIgnoringCase(name, attribute->name().toString(), shouldIgnoreAttributeCase))
3731 return i;
3732 }
3733 }
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01003734 return kNotFound;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003735}
3736
3737Attribute* UniqueElementData::getAttributeItem(const QualifiedName& name)
3738{
3739 for (unsigned i = 0; i < length(); ++i) {
3740 if (m_attributeVector.at(i).name().matches(name))
3741 return &m_attributeVector.at(i);
3742 }
3743 return 0;
3744}
3745
3746Attribute* UniqueElementData::attributeItem(unsigned index)
3747{
3748 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
3749 return &m_attributeVector.at(index);
3750}
3751
3752} // namespace WebCore