blob: ce5e91a04f284c071f7fabb080953e601ae0b4b1 [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)53e740f2013-05-09 18:38:43 +010047#include "core/dom/ClientRect.h"
48#include "core/dom/ClientRectList.h"
Ben Murdoch83750172013-07-24 10:36:59 +010049#include "core/dom/CustomElement.h"
Ben Murdoche69819b2013-07-17 14:56:49 +010050#include "core/dom/CustomElementRegistrationContext.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010051#include "core/dom/DatasetDOMStringMap.h"
52#include "core/dom/Document.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010053#include "core/dom/DocumentSharedObjectPool.h"
54#include "core/dom/ElementRareData.h"
Ben Murdoch02772c62013-07-26 10:21:05 +010055#include "core/dom/EventDispatcher.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010056#include "core/dom/ExceptionCode.h"
Ben Murdoch02772c62013-07-26 10:21:05 +010057#include "core/dom/FocusEvent.h"
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +010058#include "core/dom/FullscreenElementStack.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010059#include "core/dom/MutationObserverInterestGroup.h"
60#include "core/dom/MutationRecord.h"
61#include "core/dom/NamedNodeMap.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010062#include "core/dom/NodeRenderStyle.h"
63#include "core/dom/NodeRenderingContext.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010064#include "core/dom/PseudoElement.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010065#include "core/dom/ScriptableDocumentParser.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010066#include "core/dom/SelectorQuery.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010067#include "core/dom/Text.h"
Torne (Richard Coles)e5249552013-05-15 11:35:13 +010068#include "core/dom/shadow/InsertionPoint.h"
69#include "core/dom/shadow/ShadowRoot.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010070#include "core/editing/FrameSelection.h"
71#include "core/editing/TextIterator.h"
72#include "core/editing/htmlediting.h"
73#include "core/html/ClassList.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010074#include "core/html/HTMLCollection.h"
75#include "core/html/HTMLDocument.h"
76#include "core/html/HTMLElement.h"
77#include "core/html/HTMLFormControlsCollection.h"
78#include "core/html/HTMLFrameOwnerElement.h"
79#include "core/html/HTMLLabelElement.h"
80#include "core/html/HTMLOptionsCollection.h"
81#include "core/html/HTMLTableRowsCollection.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010082#include "core/html/parser/HTMLParserIdioms.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010083#include "core/page/ContentSecurityPolicy.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010084#include "core/page/FocusController.h"
85#include "core/page/Frame.h"
86#include "core/page/FrameView.h"
87#include "core/page/Page.h"
88#include "core/page/PointerLockController.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010089#include "core/rendering/FlowThreadController.h"
90#include "core/rendering/RenderRegion.h"
91#include "core/rendering/RenderView.h"
92#include "core/rendering/RenderWidget.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010093#include "core/svg/SVGDocumentExtensions.h"
94#include "core/svg/SVGElement.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010095#include "wtf/BitVector.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010096#include "wtf/HashFunctions.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010097#include "wtf/text/CString.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010098#include "wtf/text/TextPosition.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010099
100namespace WebCore {
101
102using namespace HTMLNames;
103using namespace XMLNames;
104
105static inline bool shouldIgnoreAttributeCase(const Element* e)
106{
107 return e && e->document()->isHTMLDocument() && e->isHTMLElement();
108}
Ben Murdoch591b9582013-07-10 11:41:44 +0100109
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100110class StyleResolverParentPusher {
111public:
112 StyleResolverParentPusher(Element* parent)
113 : m_parent(parent)
114 , m_pushedStyleResolver(0)
115 {
116 }
117 void push()
118 {
119 if (m_pushedStyleResolver)
120 return;
121 m_pushedStyleResolver = m_parent->document()->styleResolver();
122 m_pushedStyleResolver->pushParentElement(m_parent);
123 }
124 ~StyleResolverParentPusher()
125 {
126
127 if (!m_pushedStyleResolver)
128 return;
129
130 // This tells us that our pushed style selector is in a bad state,
131 // so we should just bail out in that scenario.
132 ASSERT(m_pushedStyleResolver == m_parent->document()->styleResolver());
133 if (m_pushedStyleResolver != m_parent->document()->styleResolver())
134 return;
135
136 m_pushedStyleResolver->popParentElement(m_parent);
137 }
138
139private:
140 Element* m_parent;
141 StyleResolver* m_pushedStyleResolver;
142};
143
144typedef Vector<RefPtr<Attr> > AttrNodeList;
145typedef HashMap<Element*, OwnPtr<AttrNodeList> > AttrNodeListMap;
146
147static AttrNodeListMap& attrNodeListMap()
148{
149 DEFINE_STATIC_LOCAL(AttrNodeListMap, map, ());
150 return map;
151}
152
153static AttrNodeList* attrNodeListForElement(Element* element)
154{
155 if (!element->hasSyntheticAttrChildNodes())
156 return 0;
157 ASSERT(attrNodeListMap().contains(element));
158 return attrNodeListMap().get(element);
159}
160
161static AttrNodeList* ensureAttrNodeListForElement(Element* element)
162{
163 if (element->hasSyntheticAttrChildNodes()) {
164 ASSERT(attrNodeListMap().contains(element));
165 return attrNodeListMap().get(element);
166 }
167 ASSERT(!attrNodeListMap().contains(element));
168 element->setHasSyntheticAttrChildNodes(true);
169 AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList));
170 return result.iterator->value.get();
171}
172
173static void removeAttrNodeListForElement(Element* element)
174{
175 ASSERT(element->hasSyntheticAttrChildNodes());
176 ASSERT(attrNodeListMap().contains(element));
177 attrNodeListMap().remove(element);
178 element->setHasSyntheticAttrChildNodes(false);
179}
180
181static Attr* findAttrNodeInList(AttrNodeList* attrNodeList, const QualifiedName& name)
182{
183 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
184 if (attrNodeList->at(i)->qualifiedName() == name)
185 return attrNodeList->at(i).get();
186 }
187 return 0;
188}
189
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100190PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document)
191{
192 return adoptRef(new Element(tagName, document, CreateElement));
193}
194
195Element::~Element()
196{
197#ifndef NDEBUG
198 if (document() && document()->renderer()) {
199 // When the document is not destroyed, an element that was part of a named flow
200 // content nodes should have been removed from the content nodes collection
201 // and the inNamedFlow flag reset.
202 ASSERT(!inNamedFlow());
203 }
204#endif
205
Ben Murdoch591b9582013-07-10 11:41:44 +0100206 if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
207 cssomWrapper->clearParentElement();
208
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100209 if (hasRareData()) {
210 ElementRareData* data = elementRareData();
211 data->setPseudoElement(BEFORE, 0);
212 data->setPseudoElement(AFTER, 0);
Ben Murdoche69819b2013-07-17 14:56:49 +0100213 data->setPseudoElement(BACKDROP, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100214 data->clearShadow();
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100215
216 if (RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
217 if (ActiveAnimations* activeAnimations = data->activeAnimations())
218 activeAnimations->cssAnimations()->cancel();
219 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100220 }
221
Ben Murdoch83750172013-07-24 10:36:59 +0100222 if (isCustomElement())
223 CustomElement::wasDestroyed(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100224
225 if (hasSyntheticAttrChildNodes())
226 detachAllAttrNodesFromElement();
227
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100228 if (hasPendingResources()) {
229 document()->accessSVGExtensions()->removeElementFromPendingResources(this);
230 ASSERT(!hasPendingResources());
231 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100232}
233
234inline ElementRareData* Element::elementRareData() const
235{
236 ASSERT(hasRareData());
237 return static_cast<ElementRareData*>(rareData());
238}
239
240inline ElementRareData* Element::ensureElementRareData()
241{
242 return static_cast<ElementRareData*>(ensureRareData());
243}
244
245void Element::clearTabIndexExplicitlyIfNeeded()
246{
247 if (hasRareData())
248 elementRareData()->clearTabIndexExplicitly();
249}
250
251void Element::setTabIndexExplicitly(short tabIndex)
252{
253 ensureElementRareData()->setTabIndexExplicitly(tabIndex);
254}
255
256bool Element::supportsFocus() const
257{
258 return hasRareData() && elementRareData()->tabIndexSetExplicitly();
259}
260
261short Element::tabIndex() const
262{
263 return hasRareData() ? elementRareData()->tabIndex() : 0;
264}
265
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100266bool Element::rendererIsFocusable() const
267{
268 // Elements in canvas fallback content are not rendered, but they are allowed to be
269 // focusable as long as their canvas is displayed and visible.
270 if (isInCanvasSubtree()) {
271 const Element* e = this;
272 while (e && !e->hasLocalName(canvasTag))
273 e = e->parentElement();
274 ASSERT(e);
275 return e->renderer() && e->renderer()->style()->visibility() == VISIBLE;
276 }
277
278 // FIXME: These asserts should be in Node::isFocusable, but there are some
Ben Murdoche69819b2013-07-17 14:56:49 +0100279 // callsites like Document::setFocusedElement that would currently fail on
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100280 // them. See crbug.com/251163
281 if (renderer()) {
282 ASSERT(!renderer()->needsLayout());
283 } else {
284 // We can't just use needsStyleRecalc() because if the node is in a
285 // display:none tree it might say it needs style recalc but the whole
286 // document is actually up to date.
287 ASSERT(!document()->childNeedsStyleRecalc());
288 }
289
290 // FIXME: Even if we are not visible, we might have a child that is visible.
291 // Hyatt wants to fix that some day with a "has visible content" flag or the like.
292 if (!renderer() || renderer()->style()->visibility() != VISIBLE)
293 return false;
294
295 return true;
296}
297
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100298DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, blur);
299DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, error);
300DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, focus);
301DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, load);
302
303PassRefPtr<Node> Element::cloneNode(bool deep)
304{
305 return deep ? cloneElementWithChildren() : cloneElementWithoutChildren();
306}
307
308PassRefPtr<Element> Element::cloneElementWithChildren()
309{
310 RefPtr<Element> clone = cloneElementWithoutChildren();
311 cloneChildNodes(clone.get());
312 return clone.release();
313}
314
315PassRefPtr<Element> Element::cloneElementWithoutChildren()
316{
317 RefPtr<Element> clone = cloneElementWithoutAttributesAndChildren();
318 // This will catch HTML elements in the wrong namespace that are not correctly copied.
319 // This is a sanity check as HTML overloads some of the DOM methods.
320 ASSERT(isHTMLElement() == clone->isHTMLElement());
321
322 clone->cloneDataFromElement(*this);
323 return clone.release();
324}
325
326PassRefPtr<Element> Element::cloneElementWithoutAttributesAndChildren()
327{
328 return document()->createElement(tagQName(), false);
329}
330
331PassRefPtr<Attr> Element::detachAttribute(size_t index)
332{
333 ASSERT(elementData());
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100334 const Attribute* attribute = elementData()->attributeItem(index);
335 RefPtr<Attr> attrNode = attrIfExists(attribute->name());
336 if (attrNode)
337 detachAttrNodeAtIndex(attrNode.get(), index);
338 else {
339 attrNode = Attr::create(document(), attribute->name(), attribute->value());
340 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
341 }
342 return attrNode.release();
343}
344
345void Element::detachAttrNodeAtIndex(Attr* attr, size_t index)
346{
347 ASSERT(attr);
348 ASSERT(elementData());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100349
350 const Attribute* attribute = elementData()->attributeItem(index);
351 ASSERT(attribute);
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100352 ASSERT(attribute->name() == attr->qualifiedName());
353 detachAttrNodeFromElementWithValue(attr, attribute->value());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100354 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100355}
356
357void Element::removeAttribute(const QualifiedName& name)
358{
359 if (!elementData())
360 return;
361
362 size_t index = elementData()->getAttributeItemIndex(name);
363 if (index == notFound)
364 return;
365
366 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
367}
368
369void Element::setBooleanAttribute(const QualifiedName& name, bool value)
370{
371 if (value)
372 setAttribute(name, emptyAtom);
373 else
374 removeAttribute(name);
375}
376
377NamedNodeMap* Element::attributes() const
378{
379 ElementRareData* rareData = const_cast<Element*>(this)->ensureElementRareData();
380 if (NamedNodeMap* attributeMap = rareData->attributeMap())
381 return attributeMap;
382
383 rareData->setAttributeMap(NamedNodeMap::create(const_cast<Element*>(this)));
384 return rareData->attributeMap();
385}
386
Ben Murdoch83750172013-07-24 10:36:59 +0100387ActiveAnimations* Element::activeAnimations() const
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100388{
Ben Murdoch83750172013-07-24 10:36:59 +0100389 if (hasActiveAnimations())
390 return elementRareData()->activeAnimations();
391 return 0;
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100392}
393
Ben Murdoch83750172013-07-24 10:36:59 +0100394ActiveAnimations* Element::ensureActiveAnimations()
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100395{
Ben Murdoch83750172013-07-24 10:36:59 +0100396 ElementRareData* rareData = ensureElementRareData();
397 if (!elementRareData()->activeAnimations())
398 rareData->setActiveAnimations(adoptPtr(new ActiveAnimations()));
399 return rareData->activeAnimations();
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100400}
401
402bool Element::hasActiveAnimations() const
403{
Ben Murdoch83750172013-07-24 10:36:59 +0100404 if (!RuntimeEnabledFeatures::webAnimationsEnabled())
405 return false;
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100406
Ben Murdoch83750172013-07-24 10:36:59 +0100407 if (!hasRareData())
408 return false;
409
410 ActiveAnimations* activeAnimations = elementRareData()->activeAnimations();
411 return activeAnimations && !activeAnimations->isEmpty();
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100412}
413
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100414Node::NodeType Element::nodeType() const
415{
416 return ELEMENT_NODE;
417}
418
419bool Element::hasAttribute(const QualifiedName& name) const
420{
421 return hasAttributeNS(name.namespaceURI(), name.localName());
422}
423
424void Element::synchronizeAllAttributes() const
425{
426 if (!elementData())
427 return;
428 if (elementData()->m_styleAttributeIsDirty) {
429 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100430 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100431 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100432 if (elementData()->m_animatedSVGAttributesAreDirty) {
433 ASSERT(isSVGElement());
434 toSVGElement(this)->synchronizeAnimatedSVGAttribute(anyQName());
435 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100436}
437
438inline void Element::synchronizeAttribute(const QualifiedName& name) const
439{
440 if (!elementData())
441 return;
442 if (UNLIKELY(name == styleAttr && elementData()->m_styleAttributeIsDirty)) {
443 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100444 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100445 return;
446 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100447 if (UNLIKELY(elementData()->m_animatedSVGAttributesAreDirty)) {
448 ASSERT(isSVGElement());
449 toSVGElement(this)->synchronizeAnimatedSVGAttribute(name);
450 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100451}
452
453inline void Element::synchronizeAttribute(const AtomicString& localName) const
454{
455 // This version of synchronizeAttribute() is streamlined for the case where you don't have a full QualifiedName,
456 // e.g when called from DOM API.
457 if (!elementData())
458 return;
459 if (elementData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(localName, styleAttr.localName(), shouldIgnoreAttributeCase(this))) {
460 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100461 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100462 return;
463 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100464 if (elementData()->m_animatedSVGAttributesAreDirty) {
465 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
466 ASSERT(isSVGElement());
467 static_cast<const SVGElement*>(this)->synchronizeAnimatedSVGAttribute(QualifiedName(nullAtom, localName, nullAtom));
468 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100469}
470
471const AtomicString& Element::getAttribute(const QualifiedName& name) const
472{
473 if (!elementData())
474 return nullAtom;
475 synchronizeAttribute(name);
476 if (const Attribute* attribute = getAttributeItem(name))
477 return attribute->value();
478 return nullAtom;
479}
480
Ben Murdoch591b9582013-07-10 11:41:44 +0100481void Element::scrollIntoView(bool alignToTop)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100482{
483 document()->updateLayoutIgnorePendingStylesheets();
484
485 if (!renderer())
486 return;
487
488 LayoutRect bounds = boundingBox();
489 // Align to the top / bottom and to the closest edge.
490 if (alignToTop)
491 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
492 else
493 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
494}
495
496void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
497{
498 document()->updateLayoutIgnorePendingStylesheets();
499
500 if (!renderer())
501 return;
502
503 LayoutRect bounds = boundingBox();
504 if (centerIfNeeded)
505 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
506 else
507 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
508}
509
510void Element::scrollByUnits(int units, ScrollGranularity granularity)
511{
512 document()->updateLayoutIgnorePendingStylesheets();
513
514 if (!renderer())
515 return;
516
517 if (!renderer()->hasOverflowClip())
518 return;
519
520 ScrollDirection direction = ScrollDown;
521 if (units < 0) {
522 direction = ScrollUp;
523 units = -units;
524 }
525 Node* stopNode = this;
526 toRenderBox(renderer())->scroll(direction, granularity, units, &stopNode);
527}
528
529void Element::scrollByLines(int lines)
530{
531 scrollByUnits(lines, ScrollByLine);
532}
533
534void Element::scrollByPages(int pages)
535{
536 scrollByUnits(pages, ScrollByPage);
537}
538
539static float localZoomForRenderer(RenderObject* renderer)
540{
541 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
542 // other out, but the alternative is that we'd have to crawl up the whole render tree every
543 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
544 float zoomFactor = 1;
545 if (renderer->style()->effectiveZoom() != 1) {
546 // Need to find the nearest enclosing RenderObject that set up
547 // a differing zoom, and then we divide our result by it to eliminate the zoom.
548 RenderObject* prev = renderer;
549 for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) {
550 if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) {
551 zoomFactor = prev->style()->zoom();
552 break;
553 }
554 prev = curr;
555 }
556 if (prev->isRenderView())
557 zoomFactor = prev->style()->zoom();
558 }
559 return zoomFactor;
560}
561
562static int adjustForLocalZoom(LayoutUnit value, RenderObject* renderer)
563{
564 float zoomFactor = localZoomForRenderer(renderer);
565 if (zoomFactor == 1)
566 return value;
567 return lroundf(value / zoomFactor);
568}
569
570int Element::offsetLeft()
571{
572 document()->updateLayoutIgnorePendingStylesheets();
573 if (RenderBoxModelObject* renderer = renderBoxModelObject())
574 return adjustForLocalZoom(renderer->pixelSnappedOffsetLeft(), renderer);
575 return 0;
576}
577
578int Element::offsetTop()
579{
580 document()->updateLayoutIgnorePendingStylesheets();
581 if (RenderBoxModelObject* renderer = renderBoxModelObject())
582 return adjustForLocalZoom(renderer->pixelSnappedOffsetTop(), renderer);
583 return 0;
584}
585
586int Element::offsetWidth()
587{
Ben Murdoch591b9582013-07-10 11:41:44 +0100588 document()->updateStyleForNodeIfNeeded(this);
589
590 if (RenderBox* renderer = renderBox()) {
591 if (!renderer->requiresLayoutToDetermineWidth())
592 return adjustLayoutUnitForAbsoluteZoom(renderer->fixedOffsetWidth(), renderer).round();
593 }
594
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100595 document()->updateLayoutIgnorePendingStylesheets();
596 if (RenderBoxModelObject* renderer = renderBoxModelObject())
597 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetWidth(), renderer).round();
598 return 0;
599}
600
601int Element::offsetHeight()
602{
603 document()->updateLayoutIgnorePendingStylesheets();
604 if (RenderBoxModelObject* renderer = renderBoxModelObject())
605 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetHeight(), renderer).round();
606 return 0;
607}
608
609Element* Element::bindingsOffsetParent()
610{
611 Element* element = offsetParent();
612 if (!element || !element->isInShadowTree())
613 return element;
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100614 return element->containingShadowRoot()->shouldExposeToBindings() ? element : 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100615}
616
617Element* Element::offsetParent()
618{
619 document()->updateLayoutIgnorePendingStylesheets();
620 if (RenderObject* renderer = this->renderer())
621 return renderer->offsetParent();
622 return 0;
623}
624
625int Element::clientLeft()
626{
627 document()->updateLayoutIgnorePendingStylesheets();
628
629 if (RenderBox* renderer = renderBox())
630 return adjustForAbsoluteZoom(roundToInt(renderer->clientLeft()), renderer);
631 return 0;
632}
633
634int Element::clientTop()
635{
636 document()->updateLayoutIgnorePendingStylesheets();
637
638 if (RenderBox* renderer = renderBox())
639 return adjustForAbsoluteZoom(roundToInt(renderer->clientTop()), renderer);
640 return 0;
641}
642
643int Element::clientWidth()
644{
645 document()->updateLayoutIgnorePendingStylesheets();
646
647 // When in strict mode, clientWidth for the document element should return the width of the containing frame.
648 // When in quirks mode, clientWidth for the body element should return the width of the containing frame.
649 bool inQuirksMode = document()->inQuirksMode();
650 if ((!inQuirksMode && document()->documentElement() == this) ||
651 (inQuirksMode && isHTMLElement() && document()->body() == this)) {
652 if (FrameView* view = document()->view()) {
653 if (RenderView* renderView = document()->renderView())
654 return adjustForAbsoluteZoom(view->layoutWidth(), renderView);
655 }
656 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100657
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100658 if (RenderBox* renderer = renderBox())
659 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientWidth(), renderer).round();
660 return 0;
661}
662
663int Element::clientHeight()
664{
665 document()->updateLayoutIgnorePendingStylesheets();
666
667 // When in strict mode, clientHeight for the document element should return the height of the containing frame.
668 // When in quirks mode, clientHeight for the body element should return the height of the containing frame.
Ben Murdoch591b9582013-07-10 11:41:44 +0100669 bool inQuirksMode = document()->inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100670
671 if ((!inQuirksMode && document()->documentElement() == this) ||
672 (inQuirksMode && isHTMLElement() && document()->body() == this)) {
673 if (FrameView* view = document()->view()) {
674 if (RenderView* renderView = document()->renderView())
675 return adjustForAbsoluteZoom(view->layoutHeight(), renderView);
676 }
677 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100678
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100679 if (RenderBox* renderer = renderBox())
680 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientHeight(), renderer).round();
681 return 0;
682}
683
684int Element::scrollLeft()
685{
686 document()->updateLayoutIgnorePendingStylesheets();
687 if (RenderBox* rend = renderBox())
688 return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
689 return 0;
690}
691
692int Element::scrollTop()
693{
694 document()->updateLayoutIgnorePendingStylesheets();
695 if (RenderBox* rend = renderBox())
696 return adjustForAbsoluteZoom(rend->scrollTop(), rend);
697 return 0;
698}
699
700void Element::setScrollLeft(int newLeft)
701{
702 document()->updateLayoutIgnorePendingStylesheets();
703 if (RenderBox* rend = renderBox())
704 rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
705}
706
707void Element::setScrollTop(int newTop)
708{
709 document()->updateLayoutIgnorePendingStylesheets();
710 if (RenderBox* rend = renderBox())
711 rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
712}
713
714int Element::scrollWidth()
715{
716 document()->updateLayoutIgnorePendingStylesheets();
717 if (RenderBox* rend = renderBox())
718 return adjustForAbsoluteZoom(rend->scrollWidth(), rend);
719 return 0;
720}
721
722int Element::scrollHeight()
723{
724 document()->updateLayoutIgnorePendingStylesheets();
725 if (RenderBox* rend = renderBox())
726 return adjustForAbsoluteZoom(rend->scrollHeight(), rend);
727 return 0;
728}
729
730IntRect Element::boundsInRootViewSpace()
731{
732 document()->updateLayoutIgnorePendingStylesheets();
733
734 FrameView* view = document()->view();
735 if (!view)
736 return IntRect();
737
738 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100739 if (isSVGElement() && renderer()) {
740 // Get the bounding rectangle from the SVG model.
741 SVGElement* svgElement = toSVGElement(this);
742 FloatRect localRect;
743 if (svgElement->getBoundingBox(localRect))
744 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100745 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100746 // Get the bounding rectangle from the box model.
747 if (renderBoxModelObject())
748 renderBoxModelObject()->absoluteQuads(quads);
749 }
750
751 if (quads.isEmpty())
752 return IntRect();
753
754 IntRect result = quads[0].enclosingBoundingBox();
755 for (size_t i = 1; i < quads.size(); ++i)
756 result.unite(quads[i].enclosingBoundingBox());
757
758 result = view->contentsToRootView(result);
759 return result;
760}
761
762PassRefPtr<ClientRectList> Element::getClientRects()
763{
764 document()->updateLayoutIgnorePendingStylesheets();
765
766 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject();
767 if (!renderBoxModelObject)
768 return ClientRectList::create();
769
770 // FIXME: Handle SVG elements.
771 // FIXME: Handle table/inline-table with a caption.
772
773 Vector<FloatQuad> quads;
774 renderBoxModelObject->absoluteQuads(quads);
775 document()->adjustFloatQuadsForScrollAndAbsoluteZoom(quads, renderBoxModelObject);
776 return ClientRectList::create(quads);
777}
778
779PassRefPtr<ClientRect> Element::getBoundingClientRect()
780{
781 document()->updateLayoutIgnorePendingStylesheets();
782
783 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100784 if (isSVGElement() && renderer() && !renderer()->isSVGRoot()) {
785 // Get the bounding rectangle from the SVG model.
786 SVGElement* svgElement = toSVGElement(this);
787 FloatRect localRect;
788 if (svgElement->getBoundingBox(localRect))
789 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100790 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100791 // Get the bounding rectangle from the box model.
792 if (renderBoxModelObject())
793 renderBoxModelObject()->absoluteQuads(quads);
794 }
795
796 if (quads.isEmpty())
797 return ClientRect::create();
798
799 FloatRect result = quads[0].boundingBox();
800 for (size_t i = 1; i < quads.size(); ++i)
801 result.unite(quads[i].boundingBox());
802
803 document()->adjustFloatRectForScrollAndAbsoluteZoom(result, renderer());
804 return ClientRect::create(result);
805}
Ben Murdoch591b9582013-07-10 11:41:44 +0100806
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100807IntRect Element::screenRect() const
808{
809 if (!renderer())
810 return IntRect();
811 // FIXME: this should probably respect transforms
812 return document()->view()->contentsToScreen(renderer()->absoluteBoundingBoxRectIgnoringTransforms());
813}
814
815const AtomicString& Element::getAttribute(const AtomicString& localName) const
816{
817 if (!elementData())
818 return nullAtom;
819 synchronizeAttribute(localName);
820 if (const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase(this)))
821 return attribute->value();
822 return nullAtom;
823}
824
825const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
826{
827 return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
828}
829
Ben Murdochdf957042013-08-06 11:01:27 +0100830void Element::setAttribute(const AtomicString& localName, const AtomicString& value, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100831{
832 if (!Document::isValidName(localName)) {
Ben Murdochdf957042013-08-06 11:01:27 +0100833 es.throwDOMException(InvalidCharacterError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100834 return;
835 }
836
837 synchronizeAttribute(localName);
838 const AtomicString& caseAdjustedLocalName = shouldIgnoreAttributeCase(this) ? localName.lower() : localName;
839
840 size_t index = elementData() ? elementData()->getAttributeItemIndex(caseAdjustedLocalName, false) : notFound;
841 const QualifiedName& qName = index != notFound ? attributeItem(index)->name() : QualifiedName(nullAtom, caseAdjustedLocalName, nullAtom);
842 setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute);
843}
844
845void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
846{
847 synchronizeAttribute(name);
848 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : notFound;
849 setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute);
850}
851
852void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value)
853{
854 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : notFound;
855 setAttributeInternal(index, name, value, InSynchronizationOfLazyAttribute);
856}
857
858inline void Element::setAttributeInternal(size_t index, const QualifiedName& name, const AtomicString& newValue, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
859{
860 if (newValue.isNull()) {
861 if (index != notFound)
862 removeAttributeInternal(index, inSynchronizationOfLazyAttribute);
863 return;
864 }
865
866 if (index == notFound) {
867 addAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute);
868 return;
869 }
870
871 if (!inSynchronizationOfLazyAttribute)
872 willModifyAttribute(name, attributeItem(index)->value(), newValue);
873
874 if (newValue != attributeItem(index)->value()) {
875 // If there is an Attr node hooked to this attribute, the Attr::setValue() call below
876 // will write into the ElementData.
877 // FIXME: Refactor this so it makes some sense.
878 if (RefPtr<Attr> attrNode = inSynchronizationOfLazyAttribute ? 0 : attrIfExists(name))
879 attrNode->setValue(newValue);
880 else
881 ensureUniqueElementData()->attributeItem(index)->setValue(newValue);
882 }
883
884 if (!inSynchronizationOfLazyAttribute)
885 didModifyAttribute(name, newValue);
886}
887
888static inline AtomicString makeIdForStyleResolution(const AtomicString& value, bool inQuirksMode)
889{
890 if (inQuirksMode)
891 return value.lower();
892 return value;
893}
894
Ben Murdoch7757ec22013-07-23 11:17:36 +0100895static bool checkNeedsStyleInvalidationForIdChange(const AtomicString& oldId, const AtomicString& newId, const RuleFeatureSet& features)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100896{
897 ASSERT(newId != oldId);
Ben Murdoch7757ec22013-07-23 11:17:36 +0100898 if (!oldId.isEmpty() && features.hasSelectorForId(oldId))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100899 return true;
Ben Murdoch7757ec22013-07-23 11:17:36 +0100900 if (!newId.isEmpty() && features.hasSelectorForId(newId))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100901 return true;
902 return false;
903}
904
Ben Murdoch591b9582013-07-10 11:41:44 +0100905void Element::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100906{
907 if (ElementShadow* parentElementShadow = shadowOfParentForDistribution(this)) {
908 if (shouldInvalidateDistributionWhenAttributeChanged(parentElementShadow, name, newValue))
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100909 parentElementShadow->setNeedsDistributionRecalc();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100910 }
911
912 parseAttribute(name, newValue);
913
914 document()->incDOMTreeVersion();
915
916 StyleResolver* styleResolver = document()->styleResolverIfExists();
Ben Murdoche69819b2013-07-17 14:56:49 +0100917 bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < SubtreeStyleChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100918 bool shouldInvalidateStyle = false;
919
Ben Murdoch591b9582013-07-10 11:41:44 +0100920 if (isStyledElement() && name == styleAttr) {
921 styleAttributeChanged(newValue, reason);
922 } else if (isStyledElement() && isPresentationAttribute(name)) {
923 elementData()->m_presentationAttributeStyleIsDirty = true;
Ben Murdoche69819b2013-07-17 14:56:49 +0100924 setNeedsStyleRecalc(LocalStyleChange);
Ben Murdoch591b9582013-07-10 11:41:44 +0100925 }
926
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100927 if (isIdAttributeName(name)) {
928 AtomicString oldId = elementData()->idForStyleResolution();
929 AtomicString newId = makeIdForStyleResolution(newValue, document()->inQuirksMode());
930 if (newId != oldId) {
931 elementData()->setIdForStyleResolution(newId);
Ben Murdoch7757ec22013-07-23 11:17:36 +0100932 shouldInvalidateStyle = testShouldInvalidateStyle && checkNeedsStyleInvalidationForIdChange(oldId, newId, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100933 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100934 } else if (name == classAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100935 classAttributeChanged(newValue);
Ben Murdoch591b9582013-07-10 11:41:44 +0100936 } else if (name == HTMLNames::nameAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100937 setHasName(!newValue.isNull());
Ben Murdoch591b9582013-07-10 11:41:44 +0100938 } else if (name == HTMLNames::pseudoAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100939 shouldInvalidateStyle |= testShouldInvalidateStyle && isInShadowTree();
Ben Murdoch591b9582013-07-10 11:41:44 +0100940 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100941
942 invalidateNodeListCachesInAncestors(&name, this);
943
944 // If there is currently no StyleResolver, we can't be sure that this attribute change won't affect style.
945 shouldInvalidateStyle |= !styleResolver;
946
947 if (shouldInvalidateStyle)
948 setNeedsStyleRecalc();
949
950 if (AXObjectCache* cache = document()->existingAXObjectCache())
951 cache->handleAttributeChanged(name, this);
952}
953
954inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
955{
Ben Murdoche69819b2013-07-17 14:56:49 +0100956 if (name == isAttr)
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +0100957 CustomElementRegistrationContext::setTypeExtension(this, newValue, reason == ModifiedDirectly ? CustomElementRegistrationContext::CreatedByParser : CustomElementRegistrationContext::NotCreatedByParser);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100958 attributeChanged(name, newValue, reason);
959}
960
961template <typename CharacterType>
962static inline bool classStringHasClassName(const CharacterType* characters, unsigned length)
963{
964 ASSERT(length > 0);
965
966 unsigned i = 0;
967 do {
968 if (isNotHTMLSpace(characters[i]))
969 break;
970 ++i;
971 } while (i < length);
972
973 return i < length;
974}
975
976static inline bool classStringHasClassName(const AtomicString& newClassString)
977{
978 unsigned length = newClassString.length();
979
980 if (!length)
981 return false;
982
983 if (newClassString.is8Bit())
984 return classStringHasClassName(newClassString.characters8(), length);
985 return classStringHasClassName(newClassString.characters16(), length);
986}
987
988template<typename Checker>
989static bool checkSelectorForClassChange(const SpaceSplitString& changedClasses, const Checker& checker)
990{
991 unsigned changedSize = changedClasses.size();
992 for (unsigned i = 0; i < changedSize; ++i) {
993 if (checker.hasSelectorForClass(changedClasses[i]))
994 return true;
995 }
996 return false;
997}
998
999template<typename Checker>
1000static bool checkSelectorForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, const Checker& checker)
1001{
1002 unsigned oldSize = oldClasses.size();
1003 if (!oldSize)
1004 return checkSelectorForClassChange(newClasses, checker);
1005 BitVector remainingClassBits;
1006 remainingClassBits.ensureSize(oldSize);
1007 // Class vectors tend to be very short. This is faster than using a hash table.
1008 unsigned newSize = newClasses.size();
1009 for (unsigned i = 0; i < newSize; ++i) {
1010 for (unsigned j = 0; j < oldSize; ++j) {
1011 if (newClasses[i] == oldClasses[j]) {
1012 remainingClassBits.quickSet(j);
1013 continue;
1014 }
1015 }
1016 if (checker.hasSelectorForClass(newClasses[i]))
1017 return true;
1018 }
1019 for (unsigned i = 0; i < oldSize; ++i) {
1020 // If the bit is not set the the corresponding class has been removed.
1021 if (remainingClassBits.quickGet(i))
1022 continue;
1023 if (checker.hasSelectorForClass(oldClasses[i]))
1024 return true;
1025 }
1026 return false;
1027}
1028
1029void Element::classAttributeChanged(const AtomicString& newClassString)
1030{
1031 StyleResolver* styleResolver = document()->styleResolverIfExists();
Ben Murdoche69819b2013-07-17 14:56:49 +01001032 bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < SubtreeStyleChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001033 bool shouldInvalidateStyle = false;
1034
1035 if (classStringHasClassName(newClassString)) {
1036 const bool shouldFoldCase = document()->inQuirksMode();
1037 const SpaceSplitString oldClasses = elementData()->classNames();
1038 elementData()->setClass(newClassString, shouldFoldCase);
1039 const SpaceSplitString& newClasses = elementData()->classNames();
Ben Murdoch7757ec22013-07-23 11:17:36 +01001040 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, newClasses, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001041 } else {
1042 const SpaceSplitString& oldClasses = elementData()->classNames();
Ben Murdoch7757ec22013-07-23 11:17:36 +01001043 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001044 elementData()->clearClass();
1045 }
1046
1047 if (hasRareData())
1048 elementRareData()->clearClassListValueForQuirksMode();
1049
1050 if (shouldInvalidateStyle)
1051 setNeedsStyleRecalc();
1052}
1053
1054bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
1055{
1056 ASSERT(elementShadow);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001057 const SelectRuleFeatureSet& featureSet = elementShadow->ensureSelectFeatureSet();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001058
1059 if (isIdAttributeName(name)) {
1060 AtomicString oldId = elementData()->idForStyleResolution();
1061 AtomicString newId = makeIdForStyleResolution(newValue, document()->inQuirksMode());
1062 if (newId != oldId) {
1063 if (!oldId.isEmpty() && featureSet.hasSelectorForId(oldId))
1064 return true;
1065 if (!newId.isEmpty() && featureSet.hasSelectorForId(newId))
1066 return true;
1067 }
1068 }
1069
1070 if (name == HTMLNames::classAttr) {
1071 const AtomicString& newClassString = newValue;
1072 if (classStringHasClassName(newClassString)) {
1073 const bool shouldFoldCase = document()->inQuirksMode();
1074 const SpaceSplitString& oldClasses = elementData()->classNames();
1075 const SpaceSplitString newClasses(newClassString, shouldFoldCase);
1076 if (checkSelectorForClassChange(oldClasses, newClasses, featureSet))
1077 return true;
1078 } else {
1079 const SpaceSplitString& oldClasses = elementData()->classNames();
1080 if (checkSelectorForClassChange(oldClasses, featureSet))
1081 return true;
1082 }
1083 }
1084
1085 return featureSet.hasSelectorForAttribute(name.localName());
1086}
1087
1088// Returns true is the given attribute is an event handler.
1089// We consider an event handler any attribute that begins with "on".
1090// It is a simple solution that has the advantage of not requiring any
1091// code or configuration change if a new event handler is defined.
1092
1093static inline bool isEventHandlerAttribute(const Attribute& attribute)
1094{
1095 return attribute.name().namespaceURI().isNull() && attribute.name().localName().startsWith("on");
1096}
1097
1098bool Element::isJavaScriptURLAttribute(const Attribute& attribute) const
1099{
1100 return isURLAttribute(attribute) && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(attribute.value()));
1101}
1102
1103void Element::stripScriptingAttributes(Vector<Attribute>& attributeVector) const
1104{
1105 size_t destination = 0;
1106 for (size_t source = 0; source < attributeVector.size(); ++source) {
1107 if (isEventHandlerAttribute(attributeVector[source])
1108 || isJavaScriptURLAttribute(attributeVector[source])
1109 || isHTMLContentAttribute(attributeVector[source]))
1110 continue;
1111
1112 if (source != destination)
1113 attributeVector[destination] = attributeVector[source];
1114
1115 ++destination;
1116 }
1117 attributeVector.shrink(destination);
1118}
1119
1120void Element::parserSetAttributes(const Vector<Attribute>& attributeVector)
1121{
1122 ASSERT(!inDocument());
1123 ASSERT(!parentNode());
1124 ASSERT(!m_elementData);
1125
1126 if (attributeVector.isEmpty())
1127 return;
1128
1129 if (document() && document()->sharedObjectPool())
1130 m_elementData = document()->sharedObjectPool()->cachedShareableElementDataWithAttributes(attributeVector);
1131 else
1132 m_elementData = ShareableElementData::createWithAttributes(attributeVector);
1133
1134 // Use attributeVector instead of m_elementData because attributeChanged might modify m_elementData.
1135 for (unsigned i = 0; i < attributeVector.size(); ++i)
1136 attributeChangedFromParserOrByCloning(attributeVector[i].name(), attributeVector[i].value(), ModifiedDirectly);
1137}
1138
1139bool Element::hasAttributes() const
1140{
1141 synchronizeAllAttributes();
1142 return elementData() && elementData()->length();
1143}
1144
1145bool Element::hasEquivalentAttributes(const Element* other) const
1146{
1147 synchronizeAllAttributes();
1148 other->synchronizeAllAttributes();
1149 if (elementData() == other->elementData())
1150 return true;
1151 if (elementData())
1152 return elementData()->isEquivalent(other->elementData());
1153 if (other->elementData())
1154 return other->elementData()->isEquivalent(elementData());
1155 return true;
1156}
1157
1158String Element::nodeName() const
1159{
1160 return m_tagName.toString();
1161}
1162
1163String Element::nodeNamePreservingCase() const
1164{
1165 return m_tagName.toString();
1166}
1167
Ben Murdochdf957042013-08-06 11:01:27 +01001168void Element::setPrefix(const AtomicString& prefix, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001169{
Ben Murdochdf957042013-08-06 11:01:27 +01001170 checkSetPrefix(prefix, es);
1171 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001172 return;
1173
1174 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
1175}
1176
1177KURL Element::baseURI() const
1178{
1179 const AtomicString& baseAttribute = getAttribute(baseAttr);
1180 KURL base(KURL(), baseAttribute);
1181 if (!base.protocol().isEmpty())
1182 return base;
1183
1184 ContainerNode* parent = parentNode();
1185 if (!parent)
1186 return base;
1187
1188 const KURL& parentBase = parent->baseURI();
1189 if (parentBase.isNull())
1190 return base;
1191
1192 return KURL(parentBase, baseAttribute);
1193}
1194
1195const AtomicString& Element::imageSourceURL() const
1196{
1197 return getAttribute(srcAttr);
1198}
1199
1200bool Element::rendererIsNeeded(const NodeRenderingContext& context)
1201{
1202 return context.style()->display() != NONE;
1203}
1204
Ben Murdoch591b9582013-07-10 11:41:44 +01001205RenderObject* Element::createRenderer(RenderStyle* style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001206{
1207 return RenderObject::createObject(this, style);
1208}
1209
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001210Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertionPoint)
1211{
1212 // need to do superclass processing first so inDocument() is true
1213 // by the time we reach updateId
1214 ContainerNode::insertedInto(insertionPoint);
1215
1216 if (containsFullScreenElement() && parentElement() && !parentElement()->containsFullScreenElement())
1217 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
1218
1219 if (Element* before = pseudoElement(BEFORE))
1220 before->insertedInto(insertionPoint);
1221
1222 if (Element* after = pseudoElement(AFTER))
1223 after->insertedInto(insertionPoint);
1224
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001225 if (Element* backdrop = pseudoElement(BACKDROP))
1226 backdrop->insertedInto(insertionPoint);
1227
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001228 if (!insertionPoint->isInTreeScope())
1229 return InsertionDone;
1230
1231 if (hasRareData())
1232 elementRareData()->clearClassListValueForQuirksMode();
1233
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001234 if (isUpgradedCustomElement() && inDocument())
1235 CustomElement::didEnterDocument(this, document());
1236
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001237 TreeScope* scope = insertionPoint->treeScope();
1238 if (scope != treeScope())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001239 return InsertionDone;
1240
1241 const AtomicString& idValue = getIdAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001242 if (!idValue.isNull())
1243 updateId(scope, nullAtom, idValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001244
1245 const AtomicString& nameValue = getNameAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001246 if (!nameValue.isNull())
1247 updateName(nullAtom, nameValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001248
1249 if (hasTagName(labelTag)) {
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001250 if (scope->shouldCacheLabelsByForAttribute())
1251 updateLabel(scope, nullAtom, fastGetAttribute(forAttr));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001252 }
1253
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001254 if (parentElement() && parentElement()->isInCanvasSubtree())
1255 setIsInCanvasSubtree(true);
1256
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001257 return InsertionDone;
1258}
1259
1260void Element::removedFrom(ContainerNode* insertionPoint)
1261{
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001262 bool wasInDocument = insertionPoint->inDocument();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001263
1264 if (Element* before = pseudoElement(BEFORE))
1265 before->removedFrom(insertionPoint);
1266
1267 if (Element* after = pseudoElement(AFTER))
1268 after->removedFrom(insertionPoint);
1269
Ben Murdoche69819b2013-07-17 14:56:49 +01001270 if (Element* backdrop = pseudoElement(BACKDROP))
1271 backdrop->removedFrom(insertionPoint);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001272 document()->removeFromTopLayer(this);
Ben Murdoche69819b2013-07-17 14:56:49 +01001273
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001274 if (containsFullScreenElement())
1275 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
1276
1277 if (document()->page())
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001278 document()->page()->pointerLockController().elementRemoved(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001279
1280 setSavedLayerScrollOffset(IntSize());
1281
1282 if (insertionPoint->isInTreeScope() && treeScope() == document()) {
1283 const AtomicString& idValue = getIdAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001284 if (!idValue.isNull())
1285 updateId(insertionPoint->treeScope(), idValue, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001286
1287 const AtomicString& nameValue = getNameAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001288 if (!nameValue.isNull())
1289 updateName(nameValue, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001290
1291 if (hasTagName(labelTag)) {
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001292 TreeScope* treeScope = insertionPoint->treeScope();
1293 if (treeScope->shouldCacheLabelsByForAttribute())
1294 updateLabel(treeScope, fastGetAttribute(forAttr), nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001295 }
1296 }
1297
1298 ContainerNode::removedFrom(insertionPoint);
Ben Murdoche69819b2013-07-17 14:56:49 +01001299 if (wasInDocument) {
1300 if (hasPendingResources())
1301 document()->accessSVGExtensions()->removeElementFromPendingResources(this);
1302
Ben Murdoch83750172013-07-24 10:36:59 +01001303 if (isUpgradedCustomElement())
Ben Murdochfff88842013-07-30 15:20:09 +01001304 CustomElement::didLeaveDocument(this, insertionPoint->document());
Ben Murdoche69819b2013-07-17 14:56:49 +01001305 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001306
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001307 if (hasRareData())
1308 elementRareData()->setIsInCanvasSubtree(false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001309}
1310
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001311void Element::attach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001312{
1313 PostAttachCallbackDisabler callbackDisabler(this);
1314 StyleResolverParentPusher parentPusher(this);
1315 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1316
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001317 // We've already been through detach when doing a lazyAttach, but we might
1318 // need to clear any state that's been added since then.
1319 if (hasRareData() && styleChangeType() == LazyAttachStyleChange) {
1320 ElementRareData* data = elementRareData();
1321 data->clearComputedStyle();
1322 data->resetDynamicRestyleObservations();
1323 if (!context.resolvedStyle)
1324 data->resetStyleState();
1325 }
1326
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001327 NodeRenderingContext(this, context.resolvedStyle).createRendererForElementIfNeeded();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001328
1329 createPseudoElementIfNeeded(BEFORE);
1330
1331 // When a shadow root exists, it does the work of attaching the children.
1332 if (ElementShadow* shadow = this->shadow()) {
1333 parentPusher.push();
Ben Murdoch591b9582013-07-10 11:41:44 +01001334 shadow->attach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001335 } else if (firstChild())
1336 parentPusher.push();
1337
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001338 ContainerNode::attach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001339
1340 createPseudoElementIfNeeded(AFTER);
Ben Murdoche69819b2013-07-17 14:56:49 +01001341 createPseudoElementIfNeeded(BACKDROP);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001342
Ben Murdoch591b9582013-07-10 11:41:44 +01001343 if (hasRareData()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001344 ElementRareData* data = elementRareData();
1345 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
Ben Murdoch7757ec22013-07-23 11:17:36 +01001346 if (isFocusable() && document()->focusedElement() == this)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001347 document()->updateFocusAppearanceSoon(false /* don't restore selection */);
1348 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1349 }
1350 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001351
1352 // FIXME: It doesn't appear safe to call didRecalculateStyleForElement when
1353 // not in a Document::recalcStyle. Since we're hopefully going to always
1354 // lazyAttach in the future that problem should go away.
1355 if (document()->inStyleRecalc())
1356 InspectorInstrumentation::didRecalculateStyleForElement(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001357}
1358
1359void Element::unregisterNamedFlowContentNode()
1360{
1361 if (RuntimeEnabledFeatures::cssRegionsEnabled() && inNamedFlow() && document()->renderView())
1362 document()->renderView()->flowThreadController()->unregisterNamedFlowContentNode(this);
1363}
1364
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001365void Element::detach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001366{
1367 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1368 unregisterNamedFlowContentNode();
1369 cancelFocusAppearanceUpdate();
1370 if (hasRareData()) {
1371 ElementRareData* data = elementRareData();
1372 data->setPseudoElement(BEFORE, 0);
1373 data->setPseudoElement(AFTER, 0);
Ben Murdoche69819b2013-07-17 14:56:49 +01001374 data->setPseudoElement(BACKDROP, 0);
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001375 data->clearComputedStyle();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001376 data->resetDynamicRestyleObservations();
Ben Murdoch591b9582013-07-10 11:41:44 +01001377 data->setIsInsideRegion(false);
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001378
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001379 // Only clear the style state if we're not going to reuse the style from recalcStyle.
1380 if (!context.resolvedStyle)
1381 data->resetStyleState();
1382
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001383 if (RuntimeEnabledFeatures::webAnimationsCSSEnabled() && !context.performingReattach) {
1384 if (ActiveAnimations* activeAnimations = data->activeAnimations())
1385 activeAnimations->cssAnimations()->cancel();
1386 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001387 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001388 if (ElementShadow* shadow = this->shadow())
1389 shadow->detach(context);
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001390 ContainerNode::detach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001391}
1392
1393bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle)
1394{
1395 ASSERT(currentStyle == renderStyle());
1396 ASSERT(renderer());
1397
1398 if (!currentStyle)
1399 return false;
1400
1401 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles();
1402 if (!pseudoStyleCache)
1403 return false;
1404
1405 size_t cacheSize = pseudoStyleCache->size();
1406 for (size_t i = 0; i < cacheSize; ++i) {
1407 RefPtr<RenderStyle> newPseudoStyle;
1408 PseudoId pseudoId = pseudoStyleCache->at(i)->styleType();
1409 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
1410 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle);
1411 else
1412 newPseudoStyle = renderer()->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
1413 if (!newPseudoStyle)
1414 return true;
1415 if (*newPseudoStyle != *pseudoStyleCache->at(i)) {
1416 if (pseudoId < FIRST_INTERNAL_PSEUDOID)
1417 newStyle->setHasPseudoStyle(pseudoId);
1418 newStyle->addCachedPseudoStyle(newPseudoStyle);
1419 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
1420 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
1421 // is needed, but for now just assume a layout will be required. The diff code
1422 // in RenderObject::setStyle would need to be factored out so that it could be reused.
1423 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
1424 }
1425 return true;
1426 }
1427 }
1428 return false;
1429}
1430
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001431PassRefPtr<RenderStyle> Element::styleForRenderer()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001432{
1433 if (hasCustomStyleCallbacks()) {
1434 if (RefPtr<RenderStyle> style = customStyleForRenderer())
1435 return style.release();
1436 }
1437
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001438 return originalStyleForRenderer();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001439}
1440
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001441PassRefPtr<RenderStyle> Element::originalStyleForRenderer()
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001442{
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001443 return document()->styleResolver()->styleForElement(this);
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001444}
1445
Ben Murdoche69819b2013-07-17 14:56:49 +01001446bool Element::recalcStyle(StyleChange change)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001447{
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001448 ASSERT(document()->inStyleRecalc());
1449
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001450 if (hasCustomStyleCallbacks())
1451 willRecalcStyle(change);
1452
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001453 if (hasRareData() && (change > NoChange || needsStyleRecalc())) {
1454 ElementRareData* data = elementRareData();
1455 data->resetStyleState();
1456 data->clearComputedStyle();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001457 }
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001458
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001459 // Active InsertionPoints have no renderers so they never need to go through a recalc.
1460 if ((change >= Inherit || needsStyleRecalc()) && parentRenderStyle() && !isActiveInsertionPoint(this))
1461 change = recalcOwnStyle(change);
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001462
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001463 // If we reattached we don't need to recalc the style of our descendants anymore.
1464 if (change < Reattach)
1465 recalcChildStyle(change);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001466
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001467 clearNeedsStyleRecalc();
1468 clearChildNeedsStyleRecalc();
Ben Murdoch591b9582013-07-10 11:41:44 +01001469
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001470 if (hasCustomStyleCallbacks())
1471 didRecalcStyle(change);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001472
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001473 return change == Reattach;
1474}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001475
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001476Node::StyleChange Element::recalcOwnStyle(StyleChange change)
1477{
1478 ASSERT(document()->inStyleRecalc());
1479
1480 CSSAnimationUpdateScope cssAnimationUpdateScope(this);
1481 RefPtr<RenderStyle> oldStyle = renderStyle();
1482 RefPtr<RenderStyle> newStyle = styleForRenderer();
1483 StyleChange localChange = oldStyle ? Node::diff(oldStyle.get(), newStyle.get(), document()) : Reattach;
1484
1485 if (localChange == Reattach) {
1486 AttachContext reattachContext;
1487 reattachContext.resolvedStyle = newStyle.get();
1488 reattach(reattachContext);
1489 return Reattach;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001490 }
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001491
1492 InspectorInstrumentation::didRecalculateStyleForElement(this);
1493
1494 if (RenderObject* renderer = this->renderer()) {
1495 if (localChange != NoChange || pseudoStyleCacheIsInvalid(oldStyle.get(), newStyle.get()) || (change == Force && renderer->requiresForcedStyleRecalcPropagation()) || shouldNotifyRendererWithIdenticalStyles()) {
1496 renderer->setAnimatableStyle(newStyle.get());
1497 } else if (needsStyleRecalc()) {
1498 // Although no change occurred, we use the new style so that the cousin style sharing code won't get
1499 // fooled into believing this style is the same.
1500 renderer->setStyleInternal(newStyle.get());
1501 }
1502 }
1503
1504 // 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
1505 // 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).
1506 if (document()->styleSheetCollections()->usesRemUnits() && document()->documentElement() == this && oldStyle && newStyle && oldStyle->fontSize() != newStyle->fontSize()) {
1507 // Cached RenderStyles may depend on the re units.
1508 document()->styleResolver()->invalidateMatchedPropertiesCache();
1509 return Force;
1510 }
1511
1512 if (styleChangeType() >= SubtreeStyleChange)
1513 return Force;
1514
1515 return max(localChange, change);
1516}
1517
1518void Element::recalcChildStyle(StyleChange change)
1519{
1520 ASSERT(document()->inStyleRecalc());
1521
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001522 StyleResolverParentPusher parentPusher(this);
1523
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001524 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
1525 if (shouldRecalcStyle(change, root)) {
1526 parentPusher.push();
1527 root->recalcStyle(change);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001528 }
1529 }
1530
1531 if (shouldRecalcStyle(change, this))
1532 updatePseudoElement(BEFORE, change);
1533
1534 // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
1535 // For now we will just worry about the common case, since it's a lot trickier to get the second case right
1536 // without doing way too much re-resolution.
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001537 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
1538 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001539 bool forceCheckOfNextElementSibling = false;
1540 bool forceCheckOfAnyElementSibling = false;
Ben Murdoche69819b2013-07-17 14:56:49 +01001541 bool forceReattachOfAnyWhitespaceSibling = false;
1542 for (Node* child = firstChild(); child; child = child->nextSibling()) {
1543 bool didReattach = false;
1544
1545 if (child->renderer())
1546 forceReattachOfAnyWhitespaceSibling = false;
1547
1548 if (child->isTextNode()) {
1549 if (forceReattachOfAnyWhitespaceSibling && toText(child)->containsOnlyWhitespace())
1550 child->reattach();
1551 else
1552 didReattach = toText(child)->recalcTextStyle(change);
1553 } else if (child->isElementNode()) {
1554 Element* element = toElement(child);
1555
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001556 bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() >= SubtreeStyleChange;
1557
Ben Murdoche69819b2013-07-17 14:56:49 +01001558 if (forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling)
1559 element->setNeedsStyleRecalc();
1560
Ben Murdoche69819b2013-07-17 14:56:49 +01001561 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
1562 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
1563
1564 if (shouldRecalcStyle(change, element)) {
1565 parentPusher.push();
1566 didReattach = element->recalcStyle(change);
1567 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001568 }
Ben Murdoche69819b2013-07-17 14:56:49 +01001569
1570 forceReattachOfAnyWhitespaceSibling = didReattach || forceReattachOfAnyWhitespaceSibling;
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001571 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001572
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001573 if (shouldRecalcStyle(change, this)) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001574 updatePseudoElement(AFTER, change);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001575 updatePseudoElement(BACKDROP, change);
1576 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001577}
1578
1579ElementShadow* Element::shadow() const
1580{
1581 return hasRareData() ? elementRareData()->shadow() : 0;
1582}
1583
1584ElementShadow* Element::ensureShadow()
1585{
1586 return ensureElementRareData()->ensureShadow();
1587}
1588
1589void Element::didAffectSelector(AffectedSelectorMask mask)
1590{
1591 setNeedsStyleRecalc();
1592 if (ElementShadow* elementShadow = shadowOfParentForDistribution(this))
1593 elementShadow->didAffectSelector(mask);
1594}
1595
Ben Murdochdf957042013-08-06 11:01:27 +01001596PassRefPtr<ShadowRoot> Element::createShadowRoot(ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001597{
1598 if (alwaysCreateUserAgentShadowRoot())
1599 ensureUserAgentShadowRoot();
1600
1601 if (RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled())
1602 return ensureShadow()->addShadowRoot(this, ShadowRoot::AuthorShadowRoot);
1603
1604 // Since some elements recreates shadow root dynamically, multiple shadow
1605 // subtrees won't work well in that element. Until they are fixed, we disable
1606 // adding author shadow root for them.
1607 if (!areAuthorShadowsAllowed()) {
Ben Murdochdf957042013-08-06 11:01:27 +01001608 es.throwDOMException(HierarchyRequestError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001609 return 0;
1610 }
1611 return ensureShadow()->addShadowRoot(this, ShadowRoot::AuthorShadowRoot);
1612}
1613
1614ShadowRoot* Element::shadowRoot() const
1615{
1616 ElementShadow* elementShadow = shadow();
1617 if (!elementShadow)
1618 return 0;
1619 ShadowRoot* shadowRoot = elementShadow->youngestShadowRoot();
1620 if (shadowRoot->type() == ShadowRoot::AuthorShadowRoot)
1621 return shadowRoot;
1622 return 0;
1623}
1624
1625ShadowRoot* Element::userAgentShadowRoot() const
1626{
1627 if (ElementShadow* elementShadow = shadow()) {
1628 if (ShadowRoot* shadowRoot = elementShadow->oldestShadowRoot()) {
1629 ASSERT(shadowRoot->type() == ShadowRoot::UserAgentShadowRoot);
1630 return shadowRoot;
1631 }
1632 }
1633
1634 return 0;
1635}
1636
1637ShadowRoot* Element::ensureUserAgentShadowRoot()
1638{
1639 if (ShadowRoot* shadowRoot = userAgentShadowRoot())
1640 return shadowRoot;
1641 ShadowRoot* shadowRoot = ensureShadow()->addShadowRoot(this, ShadowRoot::UserAgentShadowRoot);
1642 didAddUserAgentShadowRoot(shadowRoot);
1643 return shadowRoot;
1644}
1645
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001646bool Element::childTypeAllowed(NodeType type) const
1647{
1648 switch (type) {
1649 case ELEMENT_NODE:
1650 case TEXT_NODE:
1651 case COMMENT_NODE:
1652 case PROCESSING_INSTRUCTION_NODE:
1653 case CDATA_SECTION_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001654 return true;
1655 default:
1656 break;
1657 }
1658 return false;
1659}
1660
Ben Murdoch83750172013-07-24 10:36:59 +01001661static void inline checkForEmptyStyleChange(Element* element, RenderStyle* style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001662{
1663 if (!style && !element->styleAffectedByEmpty())
1664 return;
1665
1666 if (!style || (element->styleAffectedByEmpty() && (!style->emptyState() || element->hasChildNodes())))
1667 element->setNeedsStyleRecalc();
1668}
1669
1670static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
1671 Node* beforeChange, Node* afterChange, int childCountDelta)
1672{
Ben Murdochdf957042013-08-06 11:01:27 +01001673 if (!e->attached() || e->document()->hasPendingForcedStyleRecalc() || e->styleChangeType() >= SubtreeStyleChange)
Ben Murdoch83750172013-07-24 10:36:59 +01001674 return;
1675
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001676 // :empty selector.
1677 checkForEmptyStyleChange(e, style);
Ben Murdoch591b9582013-07-10 11:41:44 +01001678
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001679 if (!style || (e->needsStyleRecalc() && e->childrenAffectedByPositionalRules()))
1680 return;
1681
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001682 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
1683 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1684 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
1685 // backward case.
1686 // |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.
1687 // 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 +01001688 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
1689 if ((e->childrenAffectedByForwardPositionalRules() && afterChange) || (e->childrenAffectedByBackwardPositionalRules() && beforeChange)) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001690 e->setNeedsStyleRecalc();
Ben Murdoch83750172013-07-24 10:36:59 +01001691 return;
1692 }
1693
1694 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1695 // In the DOM case, we only need to do something if |afterChange| is not 0.
1696 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
1697 if (e->childrenAffectedByFirstChildRules() && afterChange) {
1698 // Find our new first child.
1699 Node* newFirstChild = e->firstElementChild();
1700 RenderStyle* newFirstChildStyle = newFirstChild ? newFirstChild->renderStyle() : 0;
1701
1702 // Find the first element node following |afterChange|
1703 Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling();
1704 RenderStyle* firstElementAfterInsertionStyle = firstElementAfterInsertion ? firstElementAfterInsertion->renderStyle() : 0;
1705
1706 // This is the insert/append case.
1707 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertionStyle && firstElementAfterInsertionStyle->firstChildState())
1708 firstElementAfterInsertion->setNeedsStyleRecalc();
1709
1710 // We also have to handle node removal.
1711 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChildStyle || !newFirstChildStyle->firstChildState()))
1712 newFirstChild->setNeedsStyleRecalc();
1713 }
1714
1715 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1716 // In the DOM case, we only need to do something if |afterChange| is not 0.
1717 if (e->childrenAffectedByLastChildRules() && beforeChange) {
1718 // Find our new last child.
1719 Node* newLastChild = e->lastElementChild();
1720 RenderStyle* newLastChildStyle = newLastChild ? newLastChild->renderStyle() : 0;
1721
1722 // Find the last element node going backwards from |beforeChange|
1723 Node* lastElementBeforeInsertion = beforeChange->isElementNode() ? beforeChange : beforeChange->previousElementSibling();
1724 RenderStyle* lastElementBeforeInsertionStyle = lastElementBeforeInsertion ? lastElementBeforeInsertion->renderStyle() : 0;
1725
1726 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertionStyle && lastElementBeforeInsertionStyle->lastChildState())
1727 lastElementBeforeInsertion->setNeedsStyleRecalc();
1728
1729 // 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
1730 // to match now.
1731 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChildStyle || !newLastChildStyle->lastChildState()))
1732 newLastChild->setNeedsStyleRecalc();
1733 }
1734
1735 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
1736 // that could be affected by this DOM change.
1737 if (e->childrenAffectedByDirectAdjacentRules() && afterChange) {
1738 if (Node* firstElementAfterInsertion = afterChange->nextElementSibling())
1739 firstElementAfterInsertion->setNeedsStyleRecalc();
1740 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001741}
1742
1743void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
1744{
1745 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
1746 if (changedByParser)
1747 checkForEmptyStyleChange(this, renderStyle());
1748 else
1749 checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
1750
Ben Murdoch83750172013-07-24 10:36:59 +01001751 if (ElementShadow* shadow = this->shadow())
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001752 shadow->setNeedsDistributionRecalc();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001753}
1754
1755void Element::removeAllEventListeners()
1756{
1757 ContainerNode::removeAllEventListeners();
1758 if (ElementShadow* shadow = this->shadow())
1759 shadow->removeAllEventListeners();
1760}
1761
1762void Element::beginParsingChildren()
1763{
1764 clearIsParsingChildrenFinished();
1765 StyleResolver* styleResolver = document()->styleResolverIfExists();
1766 if (styleResolver && attached())
1767 styleResolver->pushParentElement(this);
1768}
1769
1770void Element::finishParsingChildren()
1771{
1772 ContainerNode::finishParsingChildren();
1773 setIsParsingChildrenFinished();
1774 checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
1775 if (StyleResolver* styleResolver = document()->styleResolverIfExists())
1776 styleResolver->popParentElement(this);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001777 if (isCustomElement())
1778 CustomElement::didFinishParsingChildren(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001779}
1780
1781#ifndef NDEBUG
1782void Element::formatForDebugger(char* buffer, unsigned length) const
1783{
1784 StringBuilder result;
1785 String s;
1786
1787 result.append(nodeName());
1788
1789 s = getIdAttribute();
1790 if (s.length() > 0) {
1791 if (result.length() > 0)
1792 result.appendLiteral("; ");
1793 result.appendLiteral("id=");
1794 result.append(s);
1795 }
1796
1797 s = getAttribute(classAttr);
1798 if (s.length() > 0) {
1799 if (result.length() > 0)
1800 result.appendLiteral("; ");
1801 result.appendLiteral("class=");
1802 result.append(s);
1803 }
1804
1805 strncpy(buffer, result.toString().utf8().data(), length - 1);
1806}
1807#endif
1808
1809const Vector<RefPtr<Attr> >& Element::attrNodeList()
1810{
1811 ASSERT(hasSyntheticAttrChildNodes());
1812 return *attrNodeListForElement(this);
1813}
1814
Ben Murdochdf957042013-08-06 11:01:27 +01001815PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001816{
1817 if (!attrNode) {
Ben Murdochdf957042013-08-06 11:01:27 +01001818 es.throwDOMException(TypeMismatchError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001819 return 0;
1820 }
1821
1822 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName());
1823 if (oldAttrNode.get() == attrNode)
1824 return attrNode; // This Attr is already attached to the element.
1825
Ben Murdoche69819b2013-07-17 14:56:49 +01001826 // 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 +01001827 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
1828 if (attrNode->ownerElement()) {
Ben Murdochdf957042013-08-06 11:01:27 +01001829 es.throwDOMException(InUseAttributeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001830 return 0;
1831 }
1832
1833 synchronizeAllAttributes();
1834 UniqueElementData* elementData = ensureUniqueElementData();
1835
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001836 size_t index = elementData->getAttributeItemIndex(attrNode->qualifiedName(), shouldIgnoreAttributeCase(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001837 if (index != notFound) {
1838 if (oldAttrNode)
1839 detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData->attributeItem(index)->value());
1840 else
1841 oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), elementData->attributeItem(index)->value());
1842 }
1843
1844 setAttributeInternal(index, attrNode->qualifiedName(), attrNode->value(), NotInSynchronizationOfLazyAttribute);
1845
1846 attrNode->attachToElement(this);
Ben Murdoch591b9582013-07-10 11:41:44 +01001847 treeScope()->adoptIfNeeded(attrNode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001848 ensureAttrNodeListForElement(this)->append(attrNode);
1849
1850 return oldAttrNode.release();
1851}
1852
Ben Murdochdf957042013-08-06 11:01:27 +01001853PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001854{
Ben Murdochdf957042013-08-06 11:01:27 +01001855 return setAttributeNode(attr, es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001856}
1857
Ben Murdochdf957042013-08-06 11:01:27 +01001858PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001859{
1860 if (!attr) {
Ben Murdochdf957042013-08-06 11:01:27 +01001861 es.throwDOMException(TypeMismatchError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001862 return 0;
1863 }
1864 if (attr->ownerElement() != this) {
Ben Murdochdf957042013-08-06 11:01:27 +01001865 es.throwDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001866 return 0;
1867 }
1868
1869 ASSERT(document() == attr->document());
1870
1871 synchronizeAttribute(attr->qualifiedName());
1872
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001873 size_t index = elementData()->getAttrIndex(attr);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001874 if (index == notFound) {
Ben Murdochdf957042013-08-06 11:01:27 +01001875 es.throwDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001876 return 0;
1877 }
1878
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001879 RefPtr<Attr> guard(attr);
1880 detachAttrNodeAtIndex(attr, index);
1881 return guard.release();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001882}
1883
Ben Murdochdf957042013-08-06 11:01:27 +01001884bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001885{
1886 String prefix, localName;
Ben Murdochdf957042013-08-06 11:01:27 +01001887 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, es))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001888 return false;
Ben Murdochdf957042013-08-06 11:01:27 +01001889 ASSERT(!es.hadException());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001890
1891 QualifiedName qName(prefix, localName, namespaceURI);
1892
1893 if (!Document::hasValidNamespaceForAttributes(qName)) {
Ben Murdochdf957042013-08-06 11:01:27 +01001894 es.throwDOMException(NamespaceError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001895 return false;
1896 }
1897
1898 out = qName;
1899 return true;
1900}
1901
Ben Murdochdf957042013-08-06 11:01:27 +01001902void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001903{
1904 QualifiedName parsedName = anyName;
Ben Murdochdf957042013-08-06 11:01:27 +01001905 if (!parseAttributeName(parsedName, namespaceURI, qualifiedName, es))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001906 return;
1907 setAttribute(parsedName, value);
1908}
1909
1910void Element::removeAttributeInternal(size_t index, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1911{
1912 ASSERT_WITH_SECURITY_IMPLICATION(index < attributeCount());
1913
1914 UniqueElementData* elementData = ensureUniqueElementData();
1915
1916 QualifiedName name = elementData->attributeItem(index)->name();
1917 AtomicString valueBeingRemoved = elementData->attributeItem(index)->value();
1918
1919 if (!inSynchronizationOfLazyAttribute) {
1920 if (!valueBeingRemoved.isNull())
1921 willModifyAttribute(name, valueBeingRemoved, nullAtom);
1922 }
1923
1924 if (RefPtr<Attr> attrNode = attrIfExists(name))
1925 detachAttrNodeFromElementWithValue(attrNode.get(), elementData->attributeItem(index)->value());
1926
1927 elementData->removeAttribute(index);
1928
1929 if (!inSynchronizationOfLazyAttribute)
1930 didRemoveAttribute(name);
1931}
1932
1933void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1934{
1935 if (!inSynchronizationOfLazyAttribute)
1936 willModifyAttribute(name, nullAtom, value);
1937 ensureUniqueElementData()->addAttribute(name, value);
1938 if (!inSynchronizationOfLazyAttribute)
1939 didAddAttribute(name, value);
1940}
1941
1942void Element::removeAttribute(const AtomicString& name)
1943{
1944 if (!elementData())
1945 return;
1946
1947 AtomicString localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1948 size_t index = elementData()->getAttributeItemIndex(localName, false);
1949 if (index == notFound) {
1950 if (UNLIKELY(localName == styleAttr) && elementData()->m_styleAttributeIsDirty && isStyledElement())
Ben Murdoch591b9582013-07-10 11:41:44 +01001951 removeAllInlineStyleProperties();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001952 return;
1953 }
1954
1955 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
1956}
1957
1958void Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName)
1959{
1960 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI));
1961}
1962
1963PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& localName)
1964{
1965 if (!elementData())
1966 return 0;
1967 synchronizeAttribute(localName);
1968 const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase(this));
1969 if (!attribute)
1970 return 0;
1971 return ensureAttr(attribute->name());
1972}
1973
1974PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
1975{
1976 if (!elementData())
1977 return 0;
1978 QualifiedName qName(nullAtom, localName, namespaceURI);
1979 synchronizeAttribute(qName);
1980 const Attribute* attribute = elementData()->getAttributeItem(qName);
1981 if (!attribute)
1982 return 0;
1983 return ensureAttr(attribute->name());
1984}
1985
1986bool Element::hasAttribute(const AtomicString& localName) const
1987{
1988 if (!elementData())
1989 return false;
1990 synchronizeAttribute(localName);
1991 return elementData()->getAttributeItem(shouldIgnoreAttributeCase(this) ? localName.lower() : localName, false);
1992}
1993
1994bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
1995{
1996 if (!elementData())
1997 return false;
1998 QualifiedName qName(nullAtom, localName, namespaceURI);
1999 synchronizeAttribute(qName);
2000 return elementData()->getAttributeItem(qName);
2001}
2002
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002003void Element::focus(bool restorePreviousSelection, FocusDirection direction)
2004{
2005 if (!inDocument())
2006 return;
2007
2008 Document* doc = document();
Ben Murdoch7757ec22013-07-23 11:17:36 +01002009 if (doc->focusedElement() == this)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002010 return;
2011
2012 // If the stylesheets have already been loaded we can reliably check isFocusable.
2013 // If not, we continue and set the focused node on the focus controller below so
Ben Murdoch591b9582013-07-10 11:41:44 +01002014 // that it can be updated soon after attach.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002015 if (doc->haveStylesheetsLoaded()) {
2016 doc->updateLayoutIgnorePendingStylesheets();
2017 if (!isFocusable())
2018 return;
2019 }
2020
2021 if (!supportsFocus())
2022 return;
2023
2024 RefPtr<Node> protect;
2025 if (Page* page = doc->page()) {
2026 // Focus and change event handlers can cause us to lose our last ref.
2027 // If a focus event handler changes the focus to a different node it
2028 // does not make sense to continue and update appearence.
2029 protect = this;
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01002030 if (!page->focusController().setFocusedElement(this, doc->frame(), direction))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002031 return;
2032 }
2033
2034 // Setting the focused node above might have invalidated the layout due to scripts.
2035 doc->updateLayoutIgnorePendingStylesheets();
2036
2037 if (!isFocusable()) {
2038 ensureElementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
2039 return;
2040 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002041
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002042 cancelFocusAppearanceUpdate();
2043 updateFocusAppearance(restorePreviousSelection);
2044}
2045
2046void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
2047{
2048 if (isRootEditableElement()) {
2049 Frame* frame = document()->frame();
2050 if (!frame)
2051 return;
Ben Murdoch591b9582013-07-10 11:41:44 +01002052
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002053 // When focusing an editable element in an iframe, don't reset the selection if it already contains a selection.
2054 if (this == frame->selection()->rootEditableElement())
2055 return;
2056
2057 // FIXME: We should restore the previous selection if there is one.
2058 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
Ben Murdoch591b9582013-07-10 11:41:44 +01002059
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002060 if (frame->selection()->shouldChangeSelection(newSelection)) {
2061 frame->selection()->setSelection(newSelection);
2062 frame->selection()->revealSelection();
2063 }
2064 } else if (renderer() && !renderer()->isWidget())
2065 renderer()->scrollRectToVisible(boundingBox());
2066}
2067
2068void Element::blur()
2069{
2070 cancelFocusAppearanceUpdate();
Ben Murdoche69819b2013-07-17 14:56:49 +01002071 if (treeScope()->adjustedFocusedElement() == this) {
2072 Document* doc = document();
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01002073 if (doc->page())
2074 doc->page()->focusController().setFocusedElement(0, doc->frame());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002075 else
Ben Murdoche69819b2013-07-17 14:56:49 +01002076 doc->setFocusedElement(0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002077 }
2078}
2079
Ben Murdochdf957042013-08-06 11:01:27 +01002080bool Element::isFocusable() const
2081{
2082 return inDocument() && supportsFocus() && !isInert() && rendererIsFocusable();
2083}
2084
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002085bool Element::isKeyboardFocusable() const
2086{
2087 return isFocusable() && tabIndex() >= 0;
2088}
2089
2090bool Element::isMouseFocusable() const
2091{
2092 return isFocusable();
2093}
2094
Ben Murdoch02772c62013-07-26 10:21:05 +01002095void Element::dispatchFocusEvent(Element* oldFocusedElement, FocusDirection)
2096{
2097 RefPtr<FocusEvent> event = FocusEvent::create(eventNames().focusEvent, false, false, document()->defaultView(), 0, oldFocusedElement);
2098 EventDispatcher::dispatchEvent(this, FocusEventDispatchMediator::create(event.release()));
2099}
2100
2101void Element::dispatchBlurEvent(Element* newFocusedElement)
2102{
2103 RefPtr<FocusEvent> event = FocusEvent::create(eventNames().blurEvent, false, false, document()->defaultView(), 0, newFocusedElement);
2104 EventDispatcher::dispatchEvent(this, BlurEventDispatchMediator::create(event.release()));
2105}
2106
2107void Element::dispatchFocusInEvent(const AtomicString& eventType, Element* oldFocusedElement)
2108{
2109 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
2110 ASSERT(eventType == eventNames().focusinEvent || eventType == eventNames().DOMFocusInEvent);
2111 dispatchScopedEventDispatchMediator(FocusInEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document()->defaultView(), 0, oldFocusedElement)));
2112}
2113
2114void Element::dispatchFocusOutEvent(const AtomicString& eventType, Element* newFocusedElement)
2115{
2116 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
2117 ASSERT(eventType == eventNames().focusoutEvent || eventType == eventNames().DOMFocusOutEvent);
2118 dispatchScopedEventDispatchMediator(FocusOutEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document()->defaultView(), 0, newFocusedElement)));
2119}
2120
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002121String Element::innerText()
2122{
2123 // We need to update layout, since plainText uses line boxes in the render tree.
2124 document()->updateLayoutIgnorePendingStylesheets();
2125
2126 if (!renderer())
2127 return textContent(true);
2128
2129 return plainText(rangeOfContents(const_cast<Element*>(this)).get());
2130}
2131
2132String Element::outerText()
2133{
2134 // Getting outerText is the same as getting innerText, only
2135 // setting is different. You would think this should get the plain
2136 // text for the outer range, but this is wrong, <br> for instance
2137 // would return different values for inner and outer text by such
2138 // a rule, but it doesn't in WinIE, and we want to match that.
2139 return innerText();
2140}
2141
Ben Murdoch591b9582013-07-10 11:41:44 +01002142String Element::textFromChildren()
2143{
2144 Text* firstTextNode = 0;
2145 bool foundMultipleTextNodes = false;
2146 unsigned totalLength = 0;
2147
2148 for (Node* child = firstChild(); child; child = child->nextSibling()) {
2149 if (!child->isTextNode())
2150 continue;
2151 Text* text = toText(child);
2152 if (!firstTextNode)
2153 firstTextNode = text;
2154 else
2155 foundMultipleTextNodes = true;
2156 unsigned length = text->data().length();
2157 if (length > std::numeric_limits<unsigned>::max() - totalLength)
2158 return emptyString();
2159 totalLength += length;
2160 }
2161
2162 if (!firstTextNode)
2163 return emptyString();
2164
2165 if (firstTextNode && !foundMultipleTextNodes) {
2166 firstTextNode->atomize();
2167 return firstTextNode->data();
2168 }
2169
2170 StringBuilder content;
2171 content.reserveCapacity(totalLength);
2172 for (Node* child = firstTextNode; child; child = child->nextSibling()) {
2173 if (!child->isTextNode())
2174 continue;
2175 content.append(toText(child)->data());
2176 }
2177
2178 ASSERT(content.length() == totalLength);
2179 return content.toString();
2180}
2181
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01002182// pseudo is used via shadowPseudoId.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002183const AtomicString& Element::pseudo() const
2184{
2185 return getAttribute(pseudoAttr);
2186}
2187
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002188const AtomicString& Element::part() const
2189{
2190 return getAttribute(partAttr);
2191}
2192
2193void Element::setPart(const AtomicString& value)
2194{
2195 setAttribute(partAttr, value);
2196}
2197
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002198LayoutSize Element::minimumSizeForResizing() const
2199{
2200 return hasRareData() ? elementRareData()->minimumSizeForResizing() : defaultMinimumSizeForResizing();
2201}
2202
2203void Element::setMinimumSizeForResizing(const LayoutSize& size)
2204{
2205 if (!hasRareData() && size == defaultMinimumSizeForResizing())
2206 return;
2207 ensureElementRareData()->setMinimumSizeForResizing(size);
2208}
2209
2210RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
2211{
2212 if (PseudoElement* element = pseudoElement(pseudoElementSpecifier))
2213 return element->computedStyle();
2214
2215 // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
2216 // properties, which are only known by the renderer because it did the layout, will be correct and so that the
2217 // values returned for the ":selection" pseudo-element will be correct.
2218 if (RenderStyle* usedStyle = renderStyle()) {
2219 if (pseudoElementSpecifier) {
2220 RenderStyle* cachedPseudoStyle = usedStyle->getCachedPseudoStyle(pseudoElementSpecifier);
2221 return cachedPseudoStyle ? cachedPseudoStyle : usedStyle;
2222 } else
2223 return usedStyle;
2224 }
2225
2226 if (!attached())
2227 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
2228 // document tree and figure out when to destroy the computed style for such elements.
2229 return 0;
2230
2231 ElementRareData* data = ensureElementRareData();
2232 if (!data->computedStyle())
2233 data->setComputedStyle(document()->styleForElementIgnoringPendingStylesheets(this));
2234 return pseudoElementSpecifier ? data->computedStyle()->getCachedPseudoStyle(pseudoElementSpecifier) : data->computedStyle();
2235}
2236
2237void Element::setStyleAffectedByEmpty()
2238{
2239 ensureElementRareData()->setStyleAffectedByEmpty(true);
2240}
2241
2242void Element::setChildrenAffectedByHover(bool value)
2243{
2244 if (value || hasRareData())
2245 ensureElementRareData()->setChildrenAffectedByHover(value);
2246}
2247
2248void Element::setChildrenAffectedByActive(bool value)
2249{
2250 if (value || hasRareData())
2251 ensureElementRareData()->setChildrenAffectedByActive(value);
2252}
2253
2254void Element::setChildrenAffectedByDrag(bool value)
2255{
2256 if (value || hasRareData())
2257 ensureElementRareData()->setChildrenAffectedByDrag(value);
2258}
2259
2260void Element::setChildrenAffectedByFirstChildRules()
2261{
2262 ensureElementRareData()->setChildrenAffectedByFirstChildRules(true);
2263}
2264
2265void Element::setChildrenAffectedByLastChildRules()
2266{
2267 ensureElementRareData()->setChildrenAffectedByLastChildRules(true);
2268}
2269
2270void Element::setChildrenAffectedByDirectAdjacentRules()
2271{
2272 ensureElementRareData()->setChildrenAffectedByDirectAdjacentRules(true);
2273}
2274
2275void Element::setChildrenAffectedByForwardPositionalRules()
2276{
2277 ensureElementRareData()->setChildrenAffectedByForwardPositionalRules(true);
2278}
2279
2280void Element::setChildrenAffectedByBackwardPositionalRules()
2281{
2282 ensureElementRareData()->setChildrenAffectedByBackwardPositionalRules(true);
2283}
2284
2285void Element::setChildIndex(unsigned index)
2286{
2287 ElementRareData* rareData = ensureElementRareData();
2288 if (RenderStyle* style = renderStyle())
2289 style->setUnique();
2290 rareData->setChildIndex(index);
2291}
2292
2293bool Element::hasFlagsSetDuringStylingOfChildren() const
2294{
2295 if (!hasRareData())
2296 return false;
2297 return rareDataChildrenAffectedByHover()
2298 || rareDataChildrenAffectedByActive()
2299 || rareDataChildrenAffectedByDrag()
2300 || rareDataChildrenAffectedByFirstChildRules()
2301 || rareDataChildrenAffectedByLastChildRules()
2302 || rareDataChildrenAffectedByDirectAdjacentRules()
2303 || rareDataChildrenAffectedByForwardPositionalRules()
2304 || rareDataChildrenAffectedByBackwardPositionalRules();
2305}
2306
2307bool Element::rareDataStyleAffectedByEmpty() const
2308{
2309 ASSERT(hasRareData());
2310 return elementRareData()->styleAffectedByEmpty();
2311}
2312
2313bool Element::rareDataChildrenAffectedByHover() const
2314{
2315 ASSERT(hasRareData());
2316 return elementRareData()->childrenAffectedByHover();
2317}
2318
2319bool Element::rareDataChildrenAffectedByActive() const
2320{
2321 ASSERT(hasRareData());
2322 return elementRareData()->childrenAffectedByActive();
2323}
2324
2325bool Element::rareDataChildrenAffectedByDrag() const
2326{
2327 ASSERT(hasRareData());
2328 return elementRareData()->childrenAffectedByDrag();
2329}
2330
2331bool Element::rareDataChildrenAffectedByFirstChildRules() const
2332{
2333 ASSERT(hasRareData());
2334 return elementRareData()->childrenAffectedByFirstChildRules();
2335}
2336
2337bool Element::rareDataChildrenAffectedByLastChildRules() const
2338{
2339 ASSERT(hasRareData());
2340 return elementRareData()->childrenAffectedByLastChildRules();
2341}
2342
2343bool Element::rareDataChildrenAffectedByDirectAdjacentRules() const
2344{
2345 ASSERT(hasRareData());
2346 return elementRareData()->childrenAffectedByDirectAdjacentRules();
2347}
2348
2349bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
2350{
2351 ASSERT(hasRareData());
2352 return elementRareData()->childrenAffectedByForwardPositionalRules();
2353}
2354
2355bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
2356{
2357 ASSERT(hasRareData());
2358 return elementRareData()->childrenAffectedByBackwardPositionalRules();
2359}
2360
2361unsigned Element::rareDataChildIndex() const
2362{
2363 ASSERT(hasRareData());
2364 return elementRareData()->childIndex();
2365}
2366
2367void Element::setIsInCanvasSubtree(bool isInCanvasSubtree)
2368{
2369 ensureElementRareData()->setIsInCanvasSubtree(isInCanvasSubtree);
2370}
2371
2372bool Element::isInCanvasSubtree() const
2373{
2374 return hasRareData() && elementRareData()->isInCanvasSubtree();
2375}
2376
Ben Murdoch591b9582013-07-10 11:41:44 +01002377void Element::setIsInsideRegion(bool value)
2378{
2379 if (value == isInsideRegion())
2380 return;
2381
2382 ensureElementRareData()->setIsInsideRegion(value);
2383}
2384
2385bool Element::isInsideRegion() const
2386{
2387 return hasRareData() ? elementRareData()->isInsideRegion() : false;
2388}
2389
2390void Element::setRegionOversetState(RegionOversetState state)
2391{
2392 ensureElementRareData()->setRegionOversetState(state);
2393}
2394
2395RegionOversetState Element::regionOversetState() const
2396{
2397 return hasRareData() ? elementRareData()->regionOversetState() : RegionUndefined;
2398}
2399
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002400AtomicString Element::computeInheritedLanguage() const
2401{
2402 const Node* n = this;
2403 AtomicString value;
2404 // The language property is inherited, so we iterate over the parents to find the first language.
2405 do {
2406 if (n->isElementNode()) {
2407 if (const ElementData* elementData = toElement(n)->elementData()) {
2408 // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7
2409 if (const Attribute* attribute = elementData->getAttributeItem(XMLNames::langAttr))
2410 value = attribute->value();
2411 else if (const Attribute* attribute = elementData->getAttributeItem(HTMLNames::langAttr))
2412 value = attribute->value();
2413 }
2414 } else if (n->isDocumentNode()) {
2415 // checking the MIME content-language
2416 value = toDocument(n)->contentLanguage();
2417 }
2418
2419 n = n->parentNode();
2420 } while (n && value.isNull());
2421
2422 return value;
2423}
2424
2425Locale& Element::locale() const
2426{
2427 return document()->getCachedLocale(computeInheritedLanguage());
2428}
2429
2430void Element::cancelFocusAppearanceUpdate()
2431{
2432 if (hasRareData())
2433 elementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
Ben Murdoch7757ec22013-07-23 11:17:36 +01002434 if (document()->focusedElement() == this)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002435 document()->cancelFocusAppearanceUpdate();
2436}
2437
2438void Element::normalizeAttributes()
2439{
2440 if (!hasAttributes())
2441 return;
2442 for (unsigned i = 0; i < attributeCount(); ++i) {
2443 if (RefPtr<Attr> attr = attrIfExists(attributeItem(i)->name()))
2444 attr->normalize();
2445 }
2446}
2447
2448void Element::updatePseudoElement(PseudoId pseudoId, StyleChange change)
2449{
2450 PseudoElement* element = pseudoElement(pseudoId);
2451 if (element && (needsStyleRecalc() || shouldRecalcStyle(change, element))) {
2452 // PseudoElement styles hang off their parent element's style so if we needed
2453 // a style recalc we should Force one on the pseudo.
2454 element->recalcStyle(needsStyleRecalc() ? Force : change);
2455
2456 // Wait until our parent is not displayed or pseudoElementRendererIsNeeded
2457 // is false, otherwise we could continously create and destroy PseudoElements
2458 // when RenderObject::isChildAllowed on our parent returns false for the
2459 // PseudoElement's renderer for each style recalc.
2460 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01002461 elementRareData()->setPseudoElement(pseudoId, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002462 } else if (change >= Inherit || needsStyleRecalc())
2463 createPseudoElementIfNeeded(pseudoId);
2464}
2465
2466void Element::createPseudoElementIfNeeded(PseudoId pseudoId)
2467{
Ben Murdoche69819b2013-07-17 14:56:49 +01002468 if (pseudoId == BACKDROP && !isInTopLayer())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002469 return;
2470
2471 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
2472 return;
2473
2474 if (!renderer()->canHaveGeneratedChildren())
2475 return;
2476
2477 ASSERT(!isPseudoElement());
2478 RefPtr<PseudoElement> element = PseudoElement::create(this, pseudoId);
Ben Murdoche69819b2013-07-17 14:56:49 +01002479 if (pseudoId == BACKDROP)
2480 document()->addToTopLayer(element.get(), this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002481 element->attach();
Ben Murdoche69819b2013-07-17 14:56:49 +01002482
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01002483 ensureElementRareData()->setPseudoElement(pseudoId, element.release());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002484}
2485
2486PseudoElement* Element::pseudoElement(PseudoId pseudoId) const
2487{
2488 return hasRareData() ? elementRareData()->pseudoElement(pseudoId) : 0;
2489}
2490
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002491RenderObject* Element::pseudoElementRenderer(PseudoId pseudoId) const
2492{
2493 if (PseudoElement* element = pseudoElement(pseudoId))
2494 return element->renderer();
2495 return 0;
2496}
2497
Ben Murdochdf957042013-08-06 11:01:27 +01002498bool Element::webkitMatchesSelector(const String& selector, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002499{
2500 if (selector.isEmpty()) {
Ben Murdochdf957042013-08-06 11:01:27 +01002501 es.throwDOMException(SyntaxError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002502 return false;
2503 }
2504
Ben Murdochdf957042013-08-06 11:01:27 +01002505 SelectorQuery* selectorQuery = document()->selectorQueryCache()->add(selector, document(), es);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002506 if (!selectorQuery)
2507 return false;
2508 return selectorQuery->matches(this);
2509}
2510
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002511DOMTokenList* Element::classList()
2512{
2513 ElementRareData* data = ensureElementRareData();
2514 if (!data->classList())
2515 data->setClassList(ClassList::create(this));
2516 return data->classList();
2517}
2518
2519DOMStringMap* Element::dataset()
2520{
2521 ElementRareData* data = ensureElementRareData();
2522 if (!data->dataset())
2523 data->setDataset(DatasetDOMStringMap::create(this));
2524 return data->dataset();
2525}
2526
2527KURL Element::getURLAttribute(const QualifiedName& name) const
2528{
2529#if !ASSERT_DISABLED
2530 if (elementData()) {
2531 if (const Attribute* attribute = getAttributeItem(name))
2532 ASSERT(isURLAttribute(*attribute));
2533 }
2534#endif
2535 return document()->completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
2536}
2537
2538KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
2539{
2540#if !ASSERT_DISABLED
2541 if (elementData()) {
2542 if (const Attribute* attribute = getAttributeItem(name))
2543 ASSERT(isURLAttribute(*attribute));
2544 }
2545#endif
2546 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
2547 if (value.isEmpty())
2548 return KURL();
2549 return document()->completeURL(value);
2550}
2551
2552int Element::getIntegralAttribute(const QualifiedName& attributeName) const
2553{
2554 return getAttribute(attributeName).string().toInt();
2555}
2556
2557void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
2558{
2559 // FIXME: Need an AtomicString version of String::number.
2560 setAttribute(attributeName, String::number(value));
2561}
2562
2563unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
2564{
2565 return getAttribute(attributeName).string().toUInt();
2566}
2567
2568void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
2569{
2570 // FIXME: Need an AtomicString version of String::number.
2571 setAttribute(attributeName, String::number(value));
2572}
2573
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002574bool Element::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
2575{
2576 // Only create renderers for SVG elements whose parents are SVG elements, or for proper <svg xmlns="svgNS"> subdocuments.
2577 if (childContext.node()->isSVGElement())
2578 return childContext.node()->hasTagName(SVGNames::svgTag) || isSVGElement();
2579
2580 return ContainerNode::childShouldCreateRenderer(childContext);
2581}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002582
2583void Element::webkitRequestFullscreen()
2584{
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002585 FullscreenElementStack::from(document())->requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002586}
2587
2588void Element::webkitRequestFullScreen(unsigned short flags)
2589{
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002590 FullscreenElementStack::from(document())->requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002591}
2592
2593bool Element::containsFullScreenElement() const
2594{
2595 return hasRareData() && elementRareData()->containsFullScreenElement();
2596}
2597
2598void Element::setContainsFullScreenElement(bool flag)
2599{
2600 ensureElementRareData()->setContainsFullScreenElement(flag);
Ben Murdoche69819b2013-07-17 14:56:49 +01002601 setNeedsStyleRecalc(SubtreeStyleChange);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002602}
2603
2604static Element* parentCrossingFrameBoundaries(Element* element)
2605{
2606 ASSERT(element);
2607 return element->parentElement() ? element->parentElement() : element->document()->ownerElement();
2608}
2609
2610void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool flag)
2611{
2612 Element* element = this;
2613 while ((element = parentCrossingFrameBoundaries(element)))
2614 element->setContainsFullScreenElement(flag);
2615}
2616
2617bool Element::isInTopLayer() const
2618{
2619 return hasRareData() && elementRareData()->isInTopLayer();
2620}
2621
2622void Element::setIsInTopLayer(bool inTopLayer)
2623{
2624 if (isInTopLayer() == inTopLayer)
2625 return;
2626 ensureElementRareData()->setIsInTopLayer(inTopLayer);
2627
2628 // We must ensure a reattach occurs so the renderer is inserted in the correct sibling order under RenderView according to its
2629 // top layer position, or in its usual place if not in the top layer.
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002630 lazyReattachIfAttached();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002631}
2632
2633void Element::webkitRequestPointerLock()
2634{
2635 if (document()->page())
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01002636 document()->page()->pointerLockController().requestPointerLock(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002637}
2638
2639SpellcheckAttributeState Element::spellcheckAttributeState() const
2640{
2641 const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
2642 if (value == nullAtom)
2643 return SpellcheckAttributeDefault;
2644 if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
2645 return SpellcheckAttributeTrue;
2646 if (equalIgnoringCase(value, "false"))
2647 return SpellcheckAttributeFalse;
2648
2649 return SpellcheckAttributeDefault;
2650}
2651
2652bool Element::isSpellCheckingEnabled() const
2653{
2654 for (const Element* element = this; element; element = element->parentOrShadowHostElement()) {
2655 switch (element->spellcheckAttributeState()) {
2656 case SpellcheckAttributeTrue:
2657 return true;
2658 case SpellcheckAttributeFalse:
2659 return false;
2660 case SpellcheckAttributeDefault:
2661 break;
2662 }
2663 }
2664
2665 return true;
2666}
2667
2668RenderRegion* Element::renderRegion() const
2669{
2670 if (renderer() && renderer()->isRenderRegion())
2671 return toRenderRegion(renderer());
2672
2673 return 0;
2674}
2675
Ben Murdoch591b9582013-07-10 11:41:44 +01002676bool Element::shouldMoveToFlowThread(RenderStyle* styleToUse) const
2677{
2678 ASSERT(styleToUse);
2679
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002680 if (FullscreenElementStack::isActiveFullScreenElement(this))
Ben Murdoch591b9582013-07-10 11:41:44 +01002681 return false;
2682
2683 if (isInShadowTree())
2684 return false;
2685
2686 if (styleToUse->flowThread().isEmpty())
2687 return false;
2688
2689 return !isRegisteredWithNamedFlow();
2690}
2691
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002692const AtomicString& Element::webkitRegionOverset() const
2693{
2694 document()->updateLayoutIgnorePendingStylesheets();
2695
2696 DEFINE_STATIC_LOCAL(AtomicString, undefinedState, ("undefined", AtomicString::ConstructFromLiteral));
2697 if (!RuntimeEnabledFeatures::cssRegionsEnabled() || !renderRegion())
2698 return undefinedState;
2699
Ben Murdoch591b9582013-07-10 11:41:44 +01002700 switch (renderRegion()->regionOversetState()) {
2701 case RegionFit: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002702 DEFINE_STATIC_LOCAL(AtomicString, fitState, ("fit", AtomicString::ConstructFromLiteral));
2703 return fitState;
2704 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002705 case RegionEmpty: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002706 DEFINE_STATIC_LOCAL(AtomicString, emptyState, ("empty", AtomicString::ConstructFromLiteral));
2707 return emptyState;
2708 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002709 case RegionOverset: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002710 DEFINE_STATIC_LOCAL(AtomicString, overflowState, ("overset", AtomicString::ConstructFromLiteral));
2711 return overflowState;
2712 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002713 case RegionUndefined:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002714 return undefinedState;
2715 }
2716
2717 ASSERT_NOT_REACHED();
2718 return undefinedState;
2719}
2720
2721Vector<RefPtr<Range> > Element::webkitGetRegionFlowRanges() const
2722{
2723 document()->updateLayoutIgnorePendingStylesheets();
2724
2725 Vector<RefPtr<Range> > rangeObjects;
2726 if (RuntimeEnabledFeatures::cssRegionsEnabled() && renderer() && renderer()->isRenderRegion()) {
2727 RenderRegion* region = toRenderRegion(renderer());
2728 if (region->isValid())
2729 region->getRanges(rangeObjects);
2730 }
2731
2732 return rangeObjects;
2733}
2734
2735#ifndef NDEBUG
2736bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
2737{
2738 if (name == HTMLNames::styleAttr)
2739 return false;
2740
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002741 if (isSVGElement())
2742 return !static_cast<const SVGElement*>(this)->isAnimatableAttribute(name);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002743
2744 return true;
2745}
2746#endif
2747
2748#ifdef DUMP_NODE_STATISTICS
2749bool Element::hasNamedNodeMap() const
2750{
2751 return hasRareData() && elementRareData()->attributeMap();
2752}
2753#endif
2754
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002755inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002756{
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002757 if (!inDocument() || isInShadowTree())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002758 return;
2759
2760 if (oldName == newName)
2761 return;
2762
Ben Murdochdf957042013-08-06 11:01:27 +01002763 if (shouldRegisterAsNamedItem())
2764 updateNamedItemRegistration(oldName, newName);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002765}
2766
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002767inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002768{
2769 if (!isInTreeScope())
2770 return;
2771
2772 if (oldId == newId)
2773 return;
2774
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002775 updateId(treeScope(), oldId, newId);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002776}
2777
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002778inline void Element::updateId(TreeScope* scope, const AtomicString& oldId, const AtomicString& newId)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002779{
2780 ASSERT(isInTreeScope());
2781 ASSERT(oldId != newId);
2782
2783 if (!oldId.isEmpty())
2784 scope->removeElementById(oldId, this);
2785 if (!newId.isEmpty())
2786 scope->addElementById(newId, this);
2787
Ben Murdochdf957042013-08-06 11:01:27 +01002788 if (shouldRegisterAsExtraNamedItem())
2789 updateExtraNamedItemRegistration(oldId, newId);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002790}
2791
2792void Element::updateLabel(TreeScope* scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
2793{
2794 ASSERT(hasTagName(labelTag));
2795
2796 if (!inDocument())
2797 return;
2798
2799 if (oldForAttributeValue == newForAttributeValue)
2800 return;
2801
2802 if (!oldForAttributeValue.isEmpty())
Ben Murdoche69819b2013-07-17 14:56:49 +01002803 scope->removeLabel(oldForAttributeValue, toHTMLLabelElement(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002804 if (!newForAttributeValue.isEmpty())
Ben Murdoche69819b2013-07-17 14:56:49 +01002805 scope->addLabel(newForAttributeValue, toHTMLLabelElement(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002806}
2807
Ben Murdoch7757ec22013-07-23 11:17:36 +01002808static bool hasSelectorForAttribute(Document* document, const AtomicString& localName)
2809{
2810 return document->styleResolver() && document->styleResolver()->ruleFeatureSet().hasSelectorForAttribute(localName);
2811}
2812
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002813void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
2814{
2815 if (isIdAttributeName(name))
2816 updateId(oldValue, newValue);
2817 else if (name == HTMLNames::nameAttr)
2818 updateName(oldValue, newValue);
2819 else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
2820 TreeScope* scope = treeScope();
2821 if (scope->shouldCacheLabelsByForAttribute())
2822 updateLabel(scope, oldValue, newValue);
2823 }
2824
2825 if (oldValue != newValue) {
Ben Murdoch7757ec22013-07-23 11:17:36 +01002826 if (attached() && hasSelectorForAttribute(document(), name.localName()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002827 setNeedsStyleRecalc();
Ben Murdoche69819b2013-07-17 14:56:49 +01002828
2829 if (isUpgradedCustomElement())
Ben Murdoch83750172013-07-24 10:36:59 +01002830 CustomElement::attributeDidChange(this, name.localName(), oldValue, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002831 }
2832
2833 if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(this, name))
2834 recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue));
2835
2836 InspectorInstrumentation::willModifyDOMAttr(document(), this, oldValue, newValue);
2837}
2838
2839void Element::didAddAttribute(const QualifiedName& name, const AtomicString& value)
2840{
2841 attributeChanged(name, value);
2842 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value);
2843 dispatchSubtreeModifiedEvent();
2844}
2845
2846void Element::didModifyAttribute(const QualifiedName& name, const AtomicString& value)
2847{
2848 attributeChanged(name, value);
2849 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value);
2850 // Do not dispatch a DOMSubtreeModified event here; see bug 81141.
2851}
2852
2853void Element::didRemoveAttribute(const QualifiedName& name)
2854{
2855 attributeChanged(name, nullAtom);
2856 InspectorInstrumentation::didRemoveDOMAttr(document(), this, name.localName());
2857 dispatchSubtreeModifiedEvent();
2858}
2859
Ben Murdoche69819b2013-07-17 14:56:49 +01002860void Element::didMoveToNewDocument(Document* oldDocument)
2861{
2862 Node::didMoveToNewDocument(oldDocument);
2863
2864 // If the documents differ by quirks mode then they differ by case sensitivity
2865 // for class and id names so we need to go through the attribute change logic
2866 // to pick up the new casing in the ElementData.
2867 if (oldDocument->inQuirksMode() != document()->inQuirksMode()) {
2868 if (hasID())
2869 setIdAttribute(getIdAttribute());
2870 if (hasClass())
2871 setAttribute(HTMLNames::classAttr, getClassAttribute());
2872 }
2873}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002874
Ben Murdochdf957042013-08-06 11:01:27 +01002875void Element::updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName)
2876{
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002877 if (!document()->isHTMLDocument())
2878 return;
Ben Murdochdf957042013-08-06 11:01:27 +01002879
2880 if (!oldName.isEmpty())
2881 toHTMLDocument(document())->removeNamedItem(oldName);
2882
2883 if (!newName.isEmpty())
2884 toHTMLDocument(document())->addNamedItem(newName);
2885}
2886
2887void Element::updateExtraNamedItemRegistration(const AtomicString& oldId, const AtomicString& newId)
2888{
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002889 if (!document()->isHTMLDocument())
2890 return;
Ben Murdochdf957042013-08-06 11:01:27 +01002891
2892 if (!oldId.isEmpty())
2893 toHTMLDocument(document())->removeExtraNamedItem(oldId);
2894
2895 if (!newId.isEmpty())
2896 toHTMLDocument(document())->addExtraNamedItem(newId);
2897}
2898
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002899PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
2900{
2901 if (HTMLCollection* collection = cachedHTMLCollection(type))
2902 return collection;
2903
2904 RefPtr<HTMLCollection> collection;
2905 if (type == TableRows) {
2906 ASSERT(hasTagName(tableTag));
2907 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
2908 } else if (type == SelectOptions) {
2909 ASSERT(hasTagName(selectTag));
2910 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
2911 } else if (type == FormControls) {
2912 ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
2913 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
2914 }
2915 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLCollection>(this, type);
2916}
2917
Ben Murdoch591b9582013-07-10 11:41:44 +01002918static void scheduleLayerUpdateCallback(Node* node)
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002919{
Ben Murdoche69819b2013-07-17 14:56:49 +01002920 // Notify the renderer even is the styles are identical since it may need to
2921 // create or destroy a RenderLayer.
2922 node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002923}
2924
Ben Murdoch591b9582013-07-10 11:41:44 +01002925void Element::scheduleLayerUpdate()
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002926{
2927 if (postAttachCallbacksAreSuspended())
Ben Murdoch591b9582013-07-10 11:41:44 +01002928 queuePostAttachCallback(scheduleLayerUpdateCallback, this);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002929 else
Ben Murdoche69819b2013-07-17 14:56:49 +01002930 scheduleLayerUpdateCallback(this);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002931}
2932
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002933HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
2934{
2935 return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0;
2936}
2937
2938IntSize Element::savedLayerScrollOffset() const
2939{
2940 return hasRareData() ? elementRareData()->savedLayerScrollOffset() : IntSize();
2941}
2942
2943void Element::setSavedLayerScrollOffset(const IntSize& size)
2944{
2945 if (size.isZero() && !hasRareData())
2946 return;
2947 ensureElementRareData()->setSavedLayerScrollOffset(size);
2948}
2949
2950PassRefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
2951{
2952 if (AttrNodeList* attrNodeList = attrNodeListForElement(this))
2953 return findAttrNodeInList(attrNodeList, name);
2954 return 0;
2955}
2956
2957PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name)
2958{
2959 AttrNodeList* attrNodeList = ensureAttrNodeListForElement(this);
2960 RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
2961 if (!attrNode) {
2962 attrNode = Attr::create(this, name);
2963 treeScope()->adoptIfNeeded(attrNode.get());
2964 attrNodeList->append(attrNode);
2965 }
2966 return attrNode.release();
2967}
2968
2969void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value)
2970{
2971 ASSERT(hasSyntheticAttrChildNodes());
2972 attrNode->detachFromElementWithValue(value);
2973
2974 AttrNodeList* attrNodeList = attrNodeListForElement(this);
2975 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
2976 if (attrNodeList->at(i)->qualifiedName() == attrNode->qualifiedName()) {
2977 attrNodeList->remove(i);
2978 if (attrNodeList->isEmpty())
2979 removeAttrNodeListForElement(this);
2980 return;
2981 }
2982 }
2983 ASSERT_NOT_REACHED();
2984}
2985
2986void Element::detachAllAttrNodesFromElement()
2987{
2988 AttrNodeList* attrNodeList = attrNodeListForElement(this);
2989 ASSERT(attrNodeList);
2990
2991 for (unsigned i = 0; i < attributeCount(); ++i) {
2992 const Attribute* attribute = attributeItem(i);
2993 if (RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, attribute->name()))
2994 attrNode->detachFromElementWithValue(attribute->value());
2995 }
2996
2997 removeAttrNodeListForElement(this);
2998}
2999
3000void Element::willRecalcStyle(StyleChange)
3001{
3002 ASSERT(hasCustomStyleCallbacks());
3003}
3004
3005void Element::didRecalcStyle(StyleChange)
3006{
3007 ASSERT(hasCustomStyleCallbacks());
3008}
3009
3010
3011PassRefPtr<RenderStyle> Element::customStyleForRenderer()
3012{
3013 ASSERT(hasCustomStyleCallbacks());
3014 return 0;
3015}
3016
3017void Element::cloneAttributesFromElement(const Element& other)
3018{
3019 if (hasSyntheticAttrChildNodes())
3020 detachAllAttrNodesFromElement();
3021
3022 other.synchronizeAllAttributes();
3023 if (!other.m_elementData) {
3024 m_elementData.clear();
3025 return;
3026 }
3027
3028 const AtomicString& oldID = getIdAttribute();
3029 const AtomicString& newID = other.getIdAttribute();
3030
3031 if (!oldID.isNull() || !newID.isNull())
3032 updateId(oldID, newID);
3033
3034 const AtomicString& oldName = getNameAttribute();
3035 const AtomicString& newName = other.getNameAttribute();
3036
3037 if (!oldName.isNull() || !newName.isNull())
3038 updateName(oldName, newName);
3039
Ben Murdoche69819b2013-07-17 14:56:49 +01003040 // Quirks mode makes class and id not case sensitive. We can't share the ElementData
3041 // if the idForStyleResolution and the className need different casing.
3042 bool ownerDocumentsHaveDifferentCaseSensitivity = false;
3043 if (other.hasClass() || other.hasID())
3044 ownerDocumentsHaveDifferentCaseSensitivity = other.document()->inQuirksMode() != document()->inQuirksMode();
3045
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003046 // 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 +01003047 // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes,
3048 // and sharing the data won't result in different case sensitivity of class or id.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003049 if (other.m_elementData->isUnique()
Ben Murdoche69819b2013-07-17 14:56:49 +01003050 && !ownerDocumentsHaveDifferentCaseSensitivity
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003051 && !other.m_elementData->presentationAttributeStyle()
3052 && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper()))
3053 const_cast<Element&>(other).m_elementData = static_cast<const UniqueElementData*>(other.m_elementData.get())->makeShareableCopy();
3054
Ben Murdoche69819b2013-07-17 14:56:49 +01003055 if (!other.m_elementData->isUnique() && !ownerDocumentsHaveDifferentCaseSensitivity)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003056 m_elementData = other.m_elementData;
3057 else
3058 m_elementData = other.m_elementData->makeUniqueCopy();
3059
3060 for (unsigned i = 0; i < m_elementData->length(); ++i) {
3061 const Attribute* attribute = const_cast<const ElementData*>(m_elementData.get())->attributeItem(i);
3062 attributeChangedFromParserOrByCloning(attribute->name(), attribute->value(), ModifiedByCloning);
3063 }
3064}
3065
3066void Element::cloneDataFromElement(const Element& other)
3067{
3068 cloneAttributesFromElement(other);
3069 copyNonAttributePropertiesFromElement(other);
3070}
3071
3072void Element::createUniqueElementData()
3073{
3074 if (!m_elementData)
3075 m_elementData = UniqueElementData::create();
3076 else {
3077 ASSERT(!m_elementData->isUnique());
3078 m_elementData = static_cast<ShareableElementData*>(m_elementData.get())->makeUniqueCopy();
3079 }
3080}
3081
Ben Murdoch1fad5ca2013-08-07 11:05:11 +01003082InputMethodContext* Element::inputMethodContext()
Torne (Richard Coles)81a51572013-05-13 16:52:28 +01003083{
3084 return ensureElementRareData()->ensureInputMethodContext(toHTMLElement(this));
3085}
3086
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003087bool Element::hasPendingResources() const
3088{
3089 return hasRareData() && elementRareData()->hasPendingResources();
3090}
3091
3092void Element::setHasPendingResources()
3093{
3094 ensureElementRareData()->setHasPendingResources(true);
3095}
3096
3097void Element::clearHasPendingResources()
3098{
3099 ensureElementRareData()->setHasPendingResources(false);
3100}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003101
Ben Murdoch591b9582013-07-10 11:41:44 +01003102struct PresentationAttributeCacheKey {
3103 PresentationAttributeCacheKey() : tagName(0) { }
Ben Murdoch83750172013-07-24 10:36:59 +01003104 StringImpl* tagName;
Ben Murdoch591b9582013-07-10 11:41:44 +01003105 // Only the values need refcounting.
Ben Murdoch83750172013-07-24 10:36:59 +01003106 Vector<pair<StringImpl*, AtomicString>, 3> attributesAndValues;
Ben Murdoch591b9582013-07-10 11:41:44 +01003107};
3108
3109struct PresentationAttributeCacheEntry {
3110 WTF_MAKE_FAST_ALLOCATED;
3111public:
3112 PresentationAttributeCacheKey key;
3113 RefPtr<StylePropertySet> value;
3114};
3115
3116typedef HashMap<unsigned, OwnPtr<PresentationAttributeCacheEntry>, AlreadyHashed> PresentationAttributeCache;
3117
3118static bool operator!=(const PresentationAttributeCacheKey& a, const PresentationAttributeCacheKey& b)
3119{
3120 if (a.tagName != b.tagName)
3121 return true;
3122 return a.attributesAndValues != b.attributesAndValues;
3123}
3124
3125static PresentationAttributeCache& presentationAttributeCache()
3126{
3127 DEFINE_STATIC_LOCAL(PresentationAttributeCache, cache, ());
3128 return cache;
3129}
3130
3131class PresentationAttributeCacheCleaner {
3132 WTF_MAKE_NONCOPYABLE(PresentationAttributeCacheCleaner); WTF_MAKE_FAST_ALLOCATED;
3133public:
3134 PresentationAttributeCacheCleaner()
3135 : m_hitCount(0)
3136 , m_cleanTimer(this, &PresentationAttributeCacheCleaner::cleanCache)
3137 {
3138 }
3139
3140 void didHitPresentationAttributeCache()
3141 {
3142 if (presentationAttributeCache().size() < minimumPresentationAttributeCacheSizeForCleaning)
3143 return;
3144
3145 m_hitCount++;
3146
3147 if (!m_cleanTimer.isActive())
3148 m_cleanTimer.startOneShot(presentationAttributeCacheCleanTimeInSeconds);
3149 }
3150
3151private:
3152 static const unsigned presentationAttributeCacheCleanTimeInSeconds = 60;
3153 static const int minimumPresentationAttributeCacheSizeForCleaning = 100;
3154 static const unsigned minimumPresentationAttributeCacheHitCountPerMinute = (100 * presentationAttributeCacheCleanTimeInSeconds) / 60;
3155
3156 void cleanCache(Timer<PresentationAttributeCacheCleaner>* timer)
3157 {
3158 ASSERT_UNUSED(timer, timer == &m_cleanTimer);
3159 unsigned hitCount = m_hitCount;
3160 m_hitCount = 0;
3161 if (hitCount > minimumPresentationAttributeCacheHitCountPerMinute)
3162 return;
3163 presentationAttributeCache().clear();
3164 }
3165
3166 unsigned m_hitCount;
3167 Timer<PresentationAttributeCacheCleaner> m_cleanTimer;
3168};
3169
3170static PresentationAttributeCacheCleaner& presentationAttributeCacheCleaner()
3171{
3172 DEFINE_STATIC_LOCAL(PresentationAttributeCacheCleaner, cleaner, ());
3173 return cleaner;
3174}
3175
3176void Element::synchronizeStyleAttributeInternal() const
3177{
3178 ASSERT(isStyledElement());
3179 ASSERT(elementData());
3180 ASSERT(elementData()->m_styleAttributeIsDirty);
3181 elementData()->m_styleAttributeIsDirty = false;
3182 if (const StylePropertySet* inlineStyle = this->inlineStyle())
3183 const_cast<Element*>(this)->setSynchronizedLazyAttribute(styleAttr, inlineStyle->asText());
3184}
3185
3186CSSStyleDeclaration* Element::style()
3187{
3188 if (!isStyledElement())
3189 return 0;
3190 return ensureMutableInlineStyle()->ensureInlineCSSStyleDeclaration(this);
3191}
3192
3193MutableStylePropertySet* Element::ensureMutableInlineStyle()
3194{
3195 ASSERT(isStyledElement());
3196 RefPtr<StylePropertySet>& inlineStyle = ensureUniqueElementData()->m_inlineStyle;
3197 if (!inlineStyle)
3198 inlineStyle = MutableStylePropertySet::create(strictToCSSParserMode(isHTMLElement() && !document()->inQuirksMode()));
3199 else if (!inlineStyle->isMutable())
3200 inlineStyle = inlineStyle->mutableCopy();
3201 ASSERT(inlineStyle->isMutable());
3202 return static_cast<MutableStylePropertySet*>(inlineStyle.get());
3203}
3204
3205PropertySetCSSStyleDeclaration* Element::inlineStyleCSSOMWrapper()
3206{
3207 if (!inlineStyle() || !inlineStyle()->hasCSSOMWrapper())
3208 return 0;
3209 PropertySetCSSStyleDeclaration* cssomWrapper = ensureMutableInlineStyle()->cssStyleDeclaration();
3210 ASSERT(cssomWrapper && cssomWrapper->parentElement() == this);
3211 return cssomWrapper;
3212}
3213
3214inline void Element::setInlineStyleFromString(const AtomicString& newStyleString)
3215{
3216 ASSERT(isStyledElement());
3217 RefPtr<StylePropertySet>& inlineStyle = elementData()->m_inlineStyle;
3218
3219 // Avoid redundant work if we're using shared attribute data with already parsed inline style.
3220 if (inlineStyle && !elementData()->isUnique())
3221 return;
3222
3223 // We reconstruct the property set instead of mutating if there is no CSSOM wrapper.
3224 // This makes wrapperless property sets immutable and so cacheable.
3225 if (inlineStyle && !inlineStyle->isMutable())
3226 inlineStyle.clear();
3227
3228 if (!inlineStyle) {
3229 inlineStyle = CSSParser::parseInlineStyleDeclaration(newStyleString, this);
3230 } else {
3231 ASSERT(inlineStyle->isMutable());
3232 static_pointer_cast<MutableStylePropertySet>(inlineStyle)->parseDeclaration(newStyleString, document()->elementSheet()->contents());
3233 }
3234}
3235
3236void Element::styleAttributeChanged(const AtomicString& newStyleString, AttributeModificationReason modificationReason)
3237{
3238 ASSERT(isStyledElement());
3239 WTF::OrdinalNumber startLineNumber = WTF::OrdinalNumber::beforeFirst();
3240 if (document() && document()->scriptableDocumentParser() && !document()->isInDocumentWrite())
3241 startLineNumber = document()->scriptableDocumentParser()->lineNumber();
3242
3243 if (newStyleString.isNull()) {
3244 if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
3245 cssomWrapper->clearParentElement();
3246 ensureUniqueElementData()->m_inlineStyle.clear();
3247 } else if (modificationReason == ModifiedByCloning || document()->contentSecurityPolicy()->allowInlineStyle(document()->url(), startLineNumber)) {
3248 setInlineStyleFromString(newStyleString);
3249 }
3250
3251 elementData()->m_styleAttributeIsDirty = false;
3252
Ben Murdoche69819b2013-07-17 14:56:49 +01003253 setNeedsStyleRecalc(LocalStyleChange);
Ben Murdoch591b9582013-07-10 11:41:44 +01003254 InspectorInstrumentation::didInvalidateStyleAttr(document(), this);
3255}
3256
3257void Element::inlineStyleChanged()
3258{
3259 ASSERT(isStyledElement());
Ben Murdoche69819b2013-07-17 14:56:49 +01003260 setNeedsStyleRecalc(LocalStyleChange);
Ben Murdoch591b9582013-07-10 11:41:44 +01003261 ASSERT(elementData());
3262 elementData()->m_styleAttributeIsDirty = true;
3263 InspectorInstrumentation::didInvalidateStyleAttr(document(), this);
3264}
3265
3266bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
3267{
3268 ASSERT(isStyledElement());
3269 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
3270 inlineStyleChanged();
3271 return true;
3272}
3273
3274bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
3275{
3276 ASSERT(isStyledElement());
3277 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
3278 inlineStyleChanged();
3279 return true;
3280}
3281
3282bool Element::setInlineStyleProperty(CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit, bool important)
3283{
3284 ASSERT(isStyledElement());
3285 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createValue(value, unit), important);
3286 inlineStyleChanged();
3287 return true;
3288}
3289
3290bool Element::setInlineStyleProperty(CSSPropertyID propertyID, const String& value, bool important)
3291{
3292 ASSERT(isStyledElement());
3293 bool changes = ensureMutableInlineStyle()->setProperty(propertyID, value, important, document()->elementSheet()->contents());
3294 if (changes)
3295 inlineStyleChanged();
3296 return changes;
3297}
3298
3299bool Element::removeInlineStyleProperty(CSSPropertyID propertyID)
3300{
3301 ASSERT(isStyledElement());
3302 if (!inlineStyle())
3303 return false;
3304 bool changes = ensureMutableInlineStyle()->removeProperty(propertyID);
3305 if (changes)
3306 inlineStyleChanged();
3307 return changes;
3308}
3309
3310void Element::removeAllInlineStyleProperties()
3311{
3312 ASSERT(isStyledElement());
3313 if (!inlineStyle() || inlineStyle()->isEmpty())
3314 return;
3315 ensureMutableInlineStyle()->clear();
3316 inlineStyleChanged();
3317}
3318
3319void Element::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
3320{
3321 ASSERT(isStyledElement());
3322 if (const StylePropertySet* inlineStyle = elementData() ? elementData()->inlineStyle() : 0)
3323 inlineStyle->addSubresourceStyleURLs(urls, document()->elementSheet()->contents());
3324}
3325
Ben Murdoch83750172013-07-24 10:36:59 +01003326static inline bool attributeNameSort(const pair<StringImpl*, AtomicString>& p1, const pair<StringImpl*, AtomicString>& p2)
Ben Murdoch591b9582013-07-10 11:41:44 +01003327{
3328 // Sort based on the attribute name pointers. It doesn't matter what the order is as long as it is always the same.
3329 return p1.first < p2.first;
3330}
3331
3332void Element::makePresentationAttributeCacheKey(PresentationAttributeCacheKey& result) const
3333{
3334 ASSERT(isStyledElement());
3335 // FIXME: Enable for SVG.
3336 if (namespaceURI() != xhtmlNamespaceURI)
3337 return;
3338 // Interpretation of the size attributes on <input> depends on the type attribute.
3339 if (hasTagName(inputTag))
3340 return;
3341 unsigned size = attributeCount();
3342 for (unsigned i = 0; i < size; ++i) {
3343 const Attribute* attribute = attributeItem(i);
3344 if (!isPresentationAttribute(attribute->name()))
3345 continue;
3346 if (!attribute->namespaceURI().isNull())
3347 return;
3348 // FIXME: Background URL may depend on the base URL and can't be shared. Disallow caching.
3349 if (attribute->name() == backgroundAttr)
3350 return;
3351 result.attributesAndValues.append(std::make_pair(attribute->localName().impl(), attribute->value()));
3352 }
3353 if (result.attributesAndValues.isEmpty())
3354 return;
3355 // Attribute order doesn't matter. Sort for easy equality comparison.
3356 std::sort(result.attributesAndValues.begin(), result.attributesAndValues.end(), attributeNameSort);
3357 // The cache key is non-null when the tagName is set.
3358 result.tagName = localName().impl();
3359}
3360
3361static unsigned computePresentationAttributeCacheHash(const PresentationAttributeCacheKey& key)
3362{
3363 if (!key.tagName)
3364 return 0;
3365 ASSERT(key.attributesAndValues.size());
3366 unsigned attributeHash = StringHasher::hashMemory(key.attributesAndValues.data(), key.attributesAndValues.size() * sizeof(key.attributesAndValues[0]));
3367 return WTF::pairIntHash(key.tagName->existingHash(), attributeHash);
3368}
3369
3370void Element::rebuildPresentationAttributeStyle()
3371{
3372 ASSERT(isStyledElement());
3373 PresentationAttributeCacheKey cacheKey;
3374 makePresentationAttributeCacheKey(cacheKey);
3375
3376 unsigned cacheHash = computePresentationAttributeCacheHash(cacheKey);
3377
3378 PresentationAttributeCache::iterator cacheIterator;
3379 if (cacheHash) {
3380 cacheIterator = presentationAttributeCache().add(cacheHash, nullptr).iterator;
3381 if (cacheIterator->value && cacheIterator->value->key != cacheKey)
3382 cacheHash = 0;
3383 } else {
3384 cacheIterator = presentationAttributeCache().end();
3385 }
3386
3387 RefPtr<StylePropertySet> style;
3388 if (cacheHash && cacheIterator->value) {
3389 style = cacheIterator->value->value;
3390 presentationAttributeCacheCleaner().didHitPresentationAttributeCache();
3391 } else {
3392 style = MutableStylePropertySet::create(isSVGElement() ? SVGAttributeMode : CSSQuirksMode);
3393 unsigned size = attributeCount();
3394 for (unsigned i = 0; i < size; ++i) {
3395 const Attribute* attribute = attributeItem(i);
3396 collectStyleForPresentationAttribute(attribute->name(), attribute->value(), static_cast<MutableStylePropertySet*>(style.get()));
3397 }
3398 }
3399
3400 // ShareableElementData doesn't store presentation attribute style, so make sure we have a UniqueElementData.
3401 UniqueElementData* elementData = ensureUniqueElementData();
3402
3403 elementData->m_presentationAttributeStyleIsDirty = false;
3404 elementData->m_presentationAttributeStyle = style->isEmpty() ? 0 : style;
3405
3406 if (!cacheHash || cacheIterator->value)
3407 return;
3408
3409 OwnPtr<PresentationAttributeCacheEntry> newEntry = adoptPtr(new PresentationAttributeCacheEntry);
3410 newEntry->key = cacheKey;
3411 newEntry->value = style.release();
3412
3413 static const int presentationAttributeCacheMaximumSize = 4096;
3414 if (presentationAttributeCache().size() > presentationAttributeCacheMaximumSize) {
3415 // Start building from scratch if the cache ever gets big.
3416 presentationAttributeCache().clear();
3417 presentationAttributeCache().set(cacheHash, newEntry.release());
3418 } else {
3419 cacheIterator->value = newEntry.release();
3420 }
3421}
3422
3423void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, CSSValueID identifier)
3424{
3425 ASSERT(isStyledElement());
3426 style->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier));
3427}
3428
3429void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit)
3430{
3431 ASSERT(isStyledElement());
3432 style->setProperty(propertyID, cssValuePool().createValue(value, unit));
3433}
3434
3435void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, const String& value)
3436{
3437 ASSERT(isStyledElement());
3438 style->setProperty(propertyID, value, false, document()->elementSheet()->contents());
3439}
3440
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003441void ElementData::deref()
3442{
3443 if (!derefBase())
3444 return;
3445
3446 if (m_isUnique)
3447 delete static_cast<UniqueElementData*>(this);
3448 else
3449 delete static_cast<ShareableElementData*>(this);
3450}
3451
3452ElementData::ElementData()
3453 : m_isUnique(true)
3454 , m_arraySize(0)
3455 , m_presentationAttributeStyleIsDirty(false)
3456 , m_styleAttributeIsDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003457 , m_animatedSVGAttributesAreDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003458{
3459}
3460
3461ElementData::ElementData(unsigned arraySize)
3462 : m_isUnique(false)
3463 , m_arraySize(arraySize)
3464 , m_presentationAttributeStyleIsDirty(false)
3465 , m_styleAttributeIsDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003466 , m_animatedSVGAttributesAreDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003467{
3468}
3469
3470struct SameSizeAsElementData : public RefCounted<SameSizeAsElementData> {
3471 unsigned bitfield;
3472 void* refPtrs[3];
3473};
3474
3475COMPILE_ASSERT(sizeof(ElementData) == sizeof(SameSizeAsElementData), element_attribute_data_should_stay_small);
3476
3477static size_t sizeForShareableElementDataWithAttributeCount(unsigned count)
3478{
3479 return sizeof(ShareableElementData) + sizeof(Attribute) * count;
3480}
3481
3482PassRefPtr<ShareableElementData> ShareableElementData::createWithAttributes(const Vector<Attribute>& attributes)
3483{
3484 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(attributes.size()));
3485 return adoptRef(new (slot) ShareableElementData(attributes));
3486}
3487
3488PassRefPtr<UniqueElementData> UniqueElementData::create()
3489{
3490 return adoptRef(new UniqueElementData);
3491}
3492
3493ShareableElementData::ShareableElementData(const Vector<Attribute>& attributes)
3494 : ElementData(attributes.size())
3495{
3496 for (unsigned i = 0; i < m_arraySize; ++i)
3497 new (&m_attributeArray[i]) Attribute(attributes[i]);
3498}
3499
3500ShareableElementData::~ShareableElementData()
3501{
3502 for (unsigned i = 0; i < m_arraySize; ++i)
3503 m_attributeArray[i].~Attribute();
3504}
3505
3506ShareableElementData::ShareableElementData(const UniqueElementData& other)
3507 : ElementData(other, false)
3508{
3509 ASSERT(!other.m_presentationAttributeStyle);
3510
3511 if (other.m_inlineStyle) {
3512 ASSERT(!other.m_inlineStyle->hasCSSOMWrapper());
3513 m_inlineStyle = other.m_inlineStyle->immutableCopyIfNeeded();
3514 }
3515
3516 for (unsigned i = 0; i < m_arraySize; ++i)
3517 new (&m_attributeArray[i]) Attribute(other.m_attributeVector.at(i));
3518}
3519
3520ElementData::ElementData(const ElementData& other, bool isUnique)
3521 : m_isUnique(isUnique)
3522 , m_arraySize(isUnique ? 0 : other.length())
3523 , m_presentationAttributeStyleIsDirty(other.m_presentationAttributeStyleIsDirty)
3524 , m_styleAttributeIsDirty(other.m_styleAttributeIsDirty)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003525 , m_animatedSVGAttributesAreDirty(other.m_animatedSVGAttributesAreDirty)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003526 , m_classNames(other.m_classNames)
3527 , m_idForStyleResolution(other.m_idForStyleResolution)
3528{
3529 // NOTE: The inline style is copied by the subclass copy constructor since we don't know what to do with it here.
3530}
3531
3532UniqueElementData::UniqueElementData()
3533{
3534}
3535
3536UniqueElementData::UniqueElementData(const UniqueElementData& other)
3537 : ElementData(other, true)
3538 , m_presentationAttributeStyle(other.m_presentationAttributeStyle)
3539 , m_attributeVector(other.m_attributeVector)
3540{
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003541 m_inlineStyle = other.m_inlineStyle ? other.m_inlineStyle->mutableCopy() : 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003542}
3543
3544UniqueElementData::UniqueElementData(const ShareableElementData& other)
3545 : ElementData(other, true)
3546{
3547 // An ShareableElementData should never have a mutable inline StylePropertySet attached.
3548 ASSERT(!other.m_inlineStyle || !other.m_inlineStyle->isMutable());
3549 m_inlineStyle = other.m_inlineStyle;
3550
3551 m_attributeVector.reserveCapacity(other.length());
3552 for (unsigned i = 0; i < other.length(); ++i)
3553 m_attributeVector.uncheckedAppend(other.m_attributeArray[i]);
3554}
3555
3556PassRefPtr<UniqueElementData> ElementData::makeUniqueCopy() const
3557{
3558 if (isUnique())
3559 return adoptRef(new UniqueElementData(static_cast<const UniqueElementData&>(*this)));
3560 return adoptRef(new UniqueElementData(static_cast<const ShareableElementData&>(*this)));
3561}
3562
3563PassRefPtr<ShareableElementData> UniqueElementData::makeShareableCopy() const
3564{
3565 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(m_attributeVector.size()));
3566 return adoptRef(new (slot) ShareableElementData(*this));
3567}
3568
3569void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value)
3570{
3571 m_attributeVector.append(Attribute(attributeName, value));
3572}
3573
3574void UniqueElementData::removeAttribute(size_t index)
3575{
3576 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
3577 m_attributeVector.remove(index);
3578}
3579
3580bool ElementData::isEquivalent(const ElementData* other) const
3581{
3582 if (!other)
3583 return isEmpty();
3584
3585 unsigned len = length();
3586 if (len != other->length())
3587 return false;
3588
3589 for (unsigned i = 0; i < len; i++) {
3590 const Attribute* attribute = attributeItem(i);
3591 const Attribute* otherAttr = other->getAttributeItem(attribute->name());
3592 if (!otherAttr || attribute->value() != otherAttr->value())
3593 return false;
3594 }
3595
3596 return true;
3597}
3598
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01003599size_t ElementData::getAttrIndex(Attr* attr) const
3600{
3601 // This relies on the fact that Attr's QualifiedName == the Attribute's name.
3602 for (unsigned i = 0; i < length(); ++i) {
3603 if (attributeItem(i)->name() == attr->qualifiedName())
3604 return i;
3605 }
3606 return notFound;
3607}
3608
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003609size_t ElementData::getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const
3610{
3611 // Continue to checking case-insensitively and/or full namespaced names if necessary:
3612 for (unsigned i = 0; i < length(); ++i) {
3613 const Attribute* attribute = attributeItem(i);
3614 if (!attribute->name().hasPrefix()) {
3615 if (shouldIgnoreAttributeCase && equalIgnoringCase(name, attribute->localName()))
3616 return i;
3617 } else {
3618 // FIXME: Would be faster to do this comparison without calling toString, which
3619 // generates a temporary string by concatenation. But this branch is only reached
3620 // if the attribute name has a prefix, which is rare in HTML.
3621 if (equalPossiblyIgnoringCase(name, attribute->name().toString(), shouldIgnoreAttributeCase))
3622 return i;
3623 }
3624 }
3625 return notFound;
3626}
3627
3628Attribute* UniqueElementData::getAttributeItem(const QualifiedName& name)
3629{
3630 for (unsigned i = 0; i < length(); ++i) {
3631 if (m_attributeVector.at(i).name().matches(name))
3632 return &m_attributeVector.at(i);
3633 }
3634 return 0;
3635}
3636
3637Attribute* UniqueElementData::attributeItem(unsigned index)
3638{
3639 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
3640 return &m_attributeVector.at(index);
3641}
3642
3643} // namespace WebCore