blob: dc64b8dc1d2e217a4168fc07b4138c0bec2fc556 [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"
35#include "core/accessibility/AXObjectCache.h"
Ben Murdoch83750172013-07-24 10:36:59 +010036#include "core/animation/DocumentTimeline.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010037#include "core/css/CSSParser.h"
38#include "core/css/CSSStyleSheet.h"
39#include "core/css/CSSValuePool.h"
40#include "core/css/PropertySetCSSStyleDeclaration.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010041#include "core/css/StylePropertySet.h"
Torne (Richard Coles)81a51572013-05-13 16:52:28 +010042#include "core/css/resolver/StyleResolver.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010043#include "core/dom/Attr.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010044#include "core/dom/Attribute.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010045#include "core/dom/ClientRect.h"
46#include "core/dom/ClientRectList.h"
Ben Murdoch83750172013-07-24 10:36:59 +010047#include "core/dom/CustomElement.h"
Ben Murdoche69819b2013-07-17 14:56:49 +010048#include "core/dom/CustomElementRegistrationContext.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010049#include "core/dom/DatasetDOMStringMap.h"
50#include "core/dom/Document.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010051#include "core/dom/DocumentSharedObjectPool.h"
52#include "core/dom/ElementRareData.h"
53#include "core/dom/ExceptionCode.h"
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +010054#include "core/dom/FullscreenController.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010055#include "core/dom/MutationObserverInterestGroup.h"
56#include "core/dom/MutationRecord.h"
57#include "core/dom/NamedNodeMap.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010058#include "core/dom/NodeRenderStyle.h"
59#include "core/dom/NodeRenderingContext.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010060#include "core/dom/PseudoElement.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010061#include "core/dom/ScriptableDocumentParser.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010062#include "core/dom/SelectorQuery.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010063#include "core/dom/Text.h"
Torne (Richard Coles)e5249552013-05-15 11:35:13 +010064#include "core/dom/shadow/InsertionPoint.h"
65#include "core/dom/shadow/ShadowRoot.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010066#include "core/editing/FrameSelection.h"
67#include "core/editing/TextIterator.h"
68#include "core/editing/htmlediting.h"
69#include "core/html/ClassList.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010070#include "core/html/HTMLCollection.h"
71#include "core/html/HTMLDocument.h"
72#include "core/html/HTMLElement.h"
73#include "core/html/HTMLFormControlsCollection.h"
74#include "core/html/HTMLFrameOwnerElement.h"
75#include "core/html/HTMLLabelElement.h"
76#include "core/html/HTMLOptionsCollection.h"
77#include "core/html/HTMLTableRowsCollection.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010078#include "core/html/parser/HTMLParserIdioms.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010079#include "core/page/ContentSecurityPolicy.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010080#include "core/page/FocusController.h"
81#include "core/page/Frame.h"
82#include "core/page/FrameView.h"
83#include "core/page/Page.h"
84#include "core/page/PointerLockController.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010085#include "core/rendering/FlowThreadController.h"
86#include "core/rendering/RenderRegion.h"
87#include "core/rendering/RenderView.h"
88#include "core/rendering/RenderWidget.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010089#include "core/svg/SVGDocumentExtensions.h"
90#include "core/svg/SVGElement.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010091#include "wtf/BitVector.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010092#include "wtf/HashFunctions.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010093#include "wtf/text/CString.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010094#include "wtf/text/TextPosition.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010095
96namespace WebCore {
97
98using namespace HTMLNames;
99using namespace XMLNames;
100
101static inline bool shouldIgnoreAttributeCase(const Element* e)
102{
103 return e && e->document()->isHTMLDocument() && e->isHTMLElement();
104}
Ben Murdoch591b9582013-07-10 11:41:44 +0100105
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100106class StyleResolverParentPusher {
107public:
108 StyleResolverParentPusher(Element* parent)
109 : m_parent(parent)
110 , m_pushedStyleResolver(0)
111 {
112 }
113 void push()
114 {
115 if (m_pushedStyleResolver)
116 return;
117 m_pushedStyleResolver = m_parent->document()->styleResolver();
118 m_pushedStyleResolver->pushParentElement(m_parent);
119 }
120 ~StyleResolverParentPusher()
121 {
122
123 if (!m_pushedStyleResolver)
124 return;
125
126 // This tells us that our pushed style selector is in a bad state,
127 // so we should just bail out in that scenario.
128 ASSERT(m_pushedStyleResolver == m_parent->document()->styleResolver());
129 if (m_pushedStyleResolver != m_parent->document()->styleResolver())
130 return;
131
132 m_pushedStyleResolver->popParentElement(m_parent);
133 }
134
135private:
136 Element* m_parent;
137 StyleResolver* m_pushedStyleResolver;
138};
139
140typedef Vector<RefPtr<Attr> > AttrNodeList;
141typedef HashMap<Element*, OwnPtr<AttrNodeList> > AttrNodeListMap;
142
143static AttrNodeListMap& attrNodeListMap()
144{
145 DEFINE_STATIC_LOCAL(AttrNodeListMap, map, ());
146 return map;
147}
148
149static AttrNodeList* attrNodeListForElement(Element* element)
150{
151 if (!element->hasSyntheticAttrChildNodes())
152 return 0;
153 ASSERT(attrNodeListMap().contains(element));
154 return attrNodeListMap().get(element);
155}
156
157static AttrNodeList* ensureAttrNodeListForElement(Element* element)
158{
159 if (element->hasSyntheticAttrChildNodes()) {
160 ASSERT(attrNodeListMap().contains(element));
161 return attrNodeListMap().get(element);
162 }
163 ASSERT(!attrNodeListMap().contains(element));
164 element->setHasSyntheticAttrChildNodes(true);
165 AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList));
166 return result.iterator->value.get();
167}
168
169static void removeAttrNodeListForElement(Element* element)
170{
171 ASSERT(element->hasSyntheticAttrChildNodes());
172 ASSERT(attrNodeListMap().contains(element));
173 attrNodeListMap().remove(element);
174 element->setHasSyntheticAttrChildNodes(false);
175}
176
177static Attr* findAttrNodeInList(AttrNodeList* attrNodeList, const QualifiedName& name)
178{
179 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
180 if (attrNodeList->at(i)->qualifiedName() == name)
181 return attrNodeList->at(i).get();
182 }
183 return 0;
184}
185
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100186PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document)
187{
188 return adoptRef(new Element(tagName, document, CreateElement));
189}
190
191Element::~Element()
192{
193#ifndef NDEBUG
194 if (document() && document()->renderer()) {
195 // When the document is not destroyed, an element that was part of a named flow
196 // content nodes should have been removed from the content nodes collection
197 // and the inNamedFlow flag reset.
198 ASSERT(!inNamedFlow());
199 }
200#endif
201
Ben Murdoch591b9582013-07-10 11:41:44 +0100202 if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
203 cssomWrapper->clearParentElement();
204
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100205 if (hasRareData()) {
206 ElementRareData* data = elementRareData();
207 data->setPseudoElement(BEFORE, 0);
208 data->setPseudoElement(AFTER, 0);
Ben Murdoche69819b2013-07-17 14:56:49 +0100209 data->setPseudoElement(BACKDROP, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100210 data->clearShadow();
211 }
212
Ben Murdoch83750172013-07-24 10:36:59 +0100213 if (isCustomElement())
214 CustomElement::wasDestroyed(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100215
216 if (hasSyntheticAttrChildNodes())
217 detachAllAttrNodesFromElement();
218
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100219 if (hasPendingResources()) {
220 document()->accessSVGExtensions()->removeElementFromPendingResources(this);
221 ASSERT(!hasPendingResources());
222 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100223}
224
225inline ElementRareData* Element::elementRareData() const
226{
227 ASSERT(hasRareData());
228 return static_cast<ElementRareData*>(rareData());
229}
230
231inline ElementRareData* Element::ensureElementRareData()
232{
233 return static_cast<ElementRareData*>(ensureRareData());
234}
235
236void Element::clearTabIndexExplicitlyIfNeeded()
237{
238 if (hasRareData())
239 elementRareData()->clearTabIndexExplicitly();
240}
241
242void Element::setTabIndexExplicitly(short tabIndex)
243{
244 ensureElementRareData()->setTabIndexExplicitly(tabIndex);
245}
246
247bool Element::supportsFocus() const
248{
249 return hasRareData() && elementRareData()->tabIndexSetExplicitly();
250}
251
252short Element::tabIndex() const
253{
254 return hasRareData() ? elementRareData()->tabIndex() : 0;
255}
256
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100257bool Element::rendererIsFocusable() const
258{
259 // Elements in canvas fallback content are not rendered, but they are allowed to be
260 // focusable as long as their canvas is displayed and visible.
261 if (isInCanvasSubtree()) {
262 const Element* e = this;
263 while (e && !e->hasLocalName(canvasTag))
264 e = e->parentElement();
265 ASSERT(e);
266 return e->renderer() && e->renderer()->style()->visibility() == VISIBLE;
267 }
268
269 // FIXME: These asserts should be in Node::isFocusable, but there are some
Ben Murdoche69819b2013-07-17 14:56:49 +0100270 // callsites like Document::setFocusedElement that would currently fail on
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100271 // them. See crbug.com/251163
272 if (renderer()) {
273 ASSERT(!renderer()->needsLayout());
274 } else {
275 // We can't just use needsStyleRecalc() because if the node is in a
276 // display:none tree it might say it needs style recalc but the whole
277 // document is actually up to date.
278 ASSERT(!document()->childNeedsStyleRecalc());
279 }
280
281 // FIXME: Even if we are not visible, we might have a child that is visible.
282 // Hyatt wants to fix that some day with a "has visible content" flag or the like.
283 if (!renderer() || renderer()->style()->visibility() != VISIBLE)
284 return false;
285
286 return true;
287}
288
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100289DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, blur);
290DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, error);
291DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, focus);
292DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, load);
293
294PassRefPtr<Node> Element::cloneNode(bool deep)
295{
296 return deep ? cloneElementWithChildren() : cloneElementWithoutChildren();
297}
298
299PassRefPtr<Element> Element::cloneElementWithChildren()
300{
301 RefPtr<Element> clone = cloneElementWithoutChildren();
302 cloneChildNodes(clone.get());
303 return clone.release();
304}
305
306PassRefPtr<Element> Element::cloneElementWithoutChildren()
307{
308 RefPtr<Element> clone = cloneElementWithoutAttributesAndChildren();
309 // This will catch HTML elements in the wrong namespace that are not correctly copied.
310 // This is a sanity check as HTML overloads some of the DOM methods.
311 ASSERT(isHTMLElement() == clone->isHTMLElement());
312
313 clone->cloneDataFromElement(*this);
314 return clone.release();
315}
316
317PassRefPtr<Element> Element::cloneElementWithoutAttributesAndChildren()
318{
319 return document()->createElement(tagQName(), false);
320}
321
322PassRefPtr<Attr> Element::detachAttribute(size_t index)
323{
324 ASSERT(elementData());
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100325 const Attribute* attribute = elementData()->attributeItem(index);
326 RefPtr<Attr> attrNode = attrIfExists(attribute->name());
327 if (attrNode)
328 detachAttrNodeAtIndex(attrNode.get(), index);
329 else {
330 attrNode = Attr::create(document(), attribute->name(), attribute->value());
331 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
332 }
333 return attrNode.release();
334}
335
336void Element::detachAttrNodeAtIndex(Attr* attr, size_t index)
337{
338 ASSERT(attr);
339 ASSERT(elementData());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100340
341 const Attribute* attribute = elementData()->attributeItem(index);
342 ASSERT(attribute);
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100343 ASSERT(attribute->name() == attr->qualifiedName());
344 detachAttrNodeFromElementWithValue(attr, attribute->value());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100345 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100346}
347
348void Element::removeAttribute(const QualifiedName& name)
349{
350 if (!elementData())
351 return;
352
353 size_t index = elementData()->getAttributeItemIndex(name);
354 if (index == notFound)
355 return;
356
357 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
358}
359
360void Element::setBooleanAttribute(const QualifiedName& name, bool value)
361{
362 if (value)
363 setAttribute(name, emptyAtom);
364 else
365 removeAttribute(name);
366}
367
368NamedNodeMap* Element::attributes() const
369{
370 ElementRareData* rareData = const_cast<Element*>(this)->ensureElementRareData();
371 if (NamedNodeMap* attributeMap = rareData->attributeMap())
372 return attributeMap;
373
374 rareData->setAttributeMap(NamedNodeMap::create(const_cast<Element*>(this)));
375 return rareData->attributeMap();
376}
377
Ben Murdoch83750172013-07-24 10:36:59 +0100378ActiveAnimations* Element::activeAnimations() const
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100379{
Ben Murdoch83750172013-07-24 10:36:59 +0100380 if (hasActiveAnimations())
381 return elementRareData()->activeAnimations();
382 return 0;
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100383}
384
Ben Murdoch83750172013-07-24 10:36:59 +0100385ActiveAnimations* Element::ensureActiveAnimations()
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100386{
Ben Murdoch83750172013-07-24 10:36:59 +0100387 ElementRareData* rareData = ensureElementRareData();
388 if (!elementRareData()->activeAnimations())
389 rareData->setActiveAnimations(adoptPtr(new ActiveAnimations()));
390 return rareData->activeAnimations();
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100391}
392
393bool Element::hasActiveAnimations() const
394{
Ben Murdoch83750172013-07-24 10:36:59 +0100395 if (!RuntimeEnabledFeatures::webAnimationsEnabled())
396 return false;
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100397
Ben Murdoch83750172013-07-24 10:36:59 +0100398 if (!hasRareData())
399 return false;
400
401 ActiveAnimations* activeAnimations = elementRareData()->activeAnimations();
402 return activeAnimations && !activeAnimations->isEmpty();
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100403}
404
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100405Node::NodeType Element::nodeType() const
406{
407 return ELEMENT_NODE;
408}
409
410bool Element::hasAttribute(const QualifiedName& name) const
411{
412 return hasAttributeNS(name.namespaceURI(), name.localName());
413}
414
415void Element::synchronizeAllAttributes() const
416{
417 if (!elementData())
418 return;
419 if (elementData()->m_styleAttributeIsDirty) {
420 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100421 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100422 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100423 if (elementData()->m_animatedSVGAttributesAreDirty) {
424 ASSERT(isSVGElement());
425 toSVGElement(this)->synchronizeAnimatedSVGAttribute(anyQName());
426 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100427}
428
429inline void Element::synchronizeAttribute(const QualifiedName& name) const
430{
431 if (!elementData())
432 return;
433 if (UNLIKELY(name == styleAttr && elementData()->m_styleAttributeIsDirty)) {
434 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100435 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100436 return;
437 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100438 if (UNLIKELY(elementData()->m_animatedSVGAttributesAreDirty)) {
439 ASSERT(isSVGElement());
440 toSVGElement(this)->synchronizeAnimatedSVGAttribute(name);
441 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100442}
443
444inline void Element::synchronizeAttribute(const AtomicString& localName) const
445{
446 // This version of synchronizeAttribute() is streamlined for the case where you don't have a full QualifiedName,
447 // e.g when called from DOM API.
448 if (!elementData())
449 return;
450 if (elementData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(localName, styleAttr.localName(), shouldIgnoreAttributeCase(this))) {
451 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100452 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100453 return;
454 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100455 if (elementData()->m_animatedSVGAttributesAreDirty) {
456 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
457 ASSERT(isSVGElement());
458 static_cast<const SVGElement*>(this)->synchronizeAnimatedSVGAttribute(QualifiedName(nullAtom, localName, nullAtom));
459 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100460}
461
462const AtomicString& Element::getAttribute(const QualifiedName& name) const
463{
464 if (!elementData())
465 return nullAtom;
466 synchronizeAttribute(name);
467 if (const Attribute* attribute = getAttributeItem(name))
468 return attribute->value();
469 return nullAtom;
470}
471
Ben Murdoch591b9582013-07-10 11:41:44 +0100472void Element::scrollIntoView(bool alignToTop)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100473{
474 document()->updateLayoutIgnorePendingStylesheets();
475
476 if (!renderer())
477 return;
478
479 LayoutRect bounds = boundingBox();
480 // Align to the top / bottom and to the closest edge.
481 if (alignToTop)
482 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
483 else
484 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
485}
486
487void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
488{
489 document()->updateLayoutIgnorePendingStylesheets();
490
491 if (!renderer())
492 return;
493
494 LayoutRect bounds = boundingBox();
495 if (centerIfNeeded)
496 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
497 else
498 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
499}
500
501void Element::scrollByUnits(int units, ScrollGranularity granularity)
502{
503 document()->updateLayoutIgnorePendingStylesheets();
504
505 if (!renderer())
506 return;
507
508 if (!renderer()->hasOverflowClip())
509 return;
510
511 ScrollDirection direction = ScrollDown;
512 if (units < 0) {
513 direction = ScrollUp;
514 units = -units;
515 }
516 Node* stopNode = this;
517 toRenderBox(renderer())->scroll(direction, granularity, units, &stopNode);
518}
519
520void Element::scrollByLines(int lines)
521{
522 scrollByUnits(lines, ScrollByLine);
523}
524
525void Element::scrollByPages(int pages)
526{
527 scrollByUnits(pages, ScrollByPage);
528}
529
530static float localZoomForRenderer(RenderObject* renderer)
531{
532 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
533 // other out, but the alternative is that we'd have to crawl up the whole render tree every
534 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
535 float zoomFactor = 1;
536 if (renderer->style()->effectiveZoom() != 1) {
537 // Need to find the nearest enclosing RenderObject that set up
538 // a differing zoom, and then we divide our result by it to eliminate the zoom.
539 RenderObject* prev = renderer;
540 for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) {
541 if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) {
542 zoomFactor = prev->style()->zoom();
543 break;
544 }
545 prev = curr;
546 }
547 if (prev->isRenderView())
548 zoomFactor = prev->style()->zoom();
549 }
550 return zoomFactor;
551}
552
553static int adjustForLocalZoom(LayoutUnit value, RenderObject* renderer)
554{
555 float zoomFactor = localZoomForRenderer(renderer);
556 if (zoomFactor == 1)
557 return value;
558 return lroundf(value / zoomFactor);
559}
560
561int Element::offsetLeft()
562{
563 document()->updateLayoutIgnorePendingStylesheets();
564 if (RenderBoxModelObject* renderer = renderBoxModelObject())
565 return adjustForLocalZoom(renderer->pixelSnappedOffsetLeft(), renderer);
566 return 0;
567}
568
569int Element::offsetTop()
570{
571 document()->updateLayoutIgnorePendingStylesheets();
572 if (RenderBoxModelObject* renderer = renderBoxModelObject())
573 return adjustForLocalZoom(renderer->pixelSnappedOffsetTop(), renderer);
574 return 0;
575}
576
577int Element::offsetWidth()
578{
Ben Murdoch591b9582013-07-10 11:41:44 +0100579 document()->updateStyleForNodeIfNeeded(this);
580
581 if (RenderBox* renderer = renderBox()) {
582 if (!renderer->requiresLayoutToDetermineWidth())
583 return adjustLayoutUnitForAbsoluteZoom(renderer->fixedOffsetWidth(), renderer).round();
584 }
585
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100586 document()->updateLayoutIgnorePendingStylesheets();
587 if (RenderBoxModelObject* renderer = renderBoxModelObject())
588 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetWidth(), renderer).round();
589 return 0;
590}
591
592int Element::offsetHeight()
593{
594 document()->updateLayoutIgnorePendingStylesheets();
595 if (RenderBoxModelObject* renderer = renderBoxModelObject())
596 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetHeight(), renderer).round();
597 return 0;
598}
599
600Element* Element::bindingsOffsetParent()
601{
602 Element* element = offsetParent();
603 if (!element || !element->isInShadowTree())
604 return element;
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100605 return element->containingShadowRoot()->shouldExposeToBindings() ? element : 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100606}
607
608Element* Element::offsetParent()
609{
610 document()->updateLayoutIgnorePendingStylesheets();
611 if (RenderObject* renderer = this->renderer())
612 return renderer->offsetParent();
613 return 0;
614}
615
616int Element::clientLeft()
617{
618 document()->updateLayoutIgnorePendingStylesheets();
619
620 if (RenderBox* renderer = renderBox())
621 return adjustForAbsoluteZoom(roundToInt(renderer->clientLeft()), renderer);
622 return 0;
623}
624
625int Element::clientTop()
626{
627 document()->updateLayoutIgnorePendingStylesheets();
628
629 if (RenderBox* renderer = renderBox())
630 return adjustForAbsoluteZoom(roundToInt(renderer->clientTop()), renderer);
631 return 0;
632}
633
634int Element::clientWidth()
635{
636 document()->updateLayoutIgnorePendingStylesheets();
637
638 // When in strict mode, clientWidth for the document element should return the width of the containing frame.
639 // When in quirks mode, clientWidth for the body element should return the width of the containing frame.
640 bool inQuirksMode = document()->inQuirksMode();
641 if ((!inQuirksMode && document()->documentElement() == this) ||
642 (inQuirksMode && isHTMLElement() && document()->body() == this)) {
643 if (FrameView* view = document()->view()) {
644 if (RenderView* renderView = document()->renderView())
645 return adjustForAbsoluteZoom(view->layoutWidth(), renderView);
646 }
647 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100648
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100649 if (RenderBox* renderer = renderBox())
650 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientWidth(), renderer).round();
651 return 0;
652}
653
654int Element::clientHeight()
655{
656 document()->updateLayoutIgnorePendingStylesheets();
657
658 // When in strict mode, clientHeight for the document element should return the height of the containing frame.
659 // When in quirks mode, clientHeight for the body element should return the height of the containing frame.
Ben Murdoch591b9582013-07-10 11:41:44 +0100660 bool inQuirksMode = document()->inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100661
662 if ((!inQuirksMode && document()->documentElement() == this) ||
663 (inQuirksMode && isHTMLElement() && document()->body() == this)) {
664 if (FrameView* view = document()->view()) {
665 if (RenderView* renderView = document()->renderView())
666 return adjustForAbsoluteZoom(view->layoutHeight(), renderView);
667 }
668 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100669
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100670 if (RenderBox* renderer = renderBox())
671 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientHeight(), renderer).round();
672 return 0;
673}
674
675int Element::scrollLeft()
676{
677 document()->updateLayoutIgnorePendingStylesheets();
678 if (RenderBox* rend = renderBox())
679 return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
680 return 0;
681}
682
683int Element::scrollTop()
684{
685 document()->updateLayoutIgnorePendingStylesheets();
686 if (RenderBox* rend = renderBox())
687 return adjustForAbsoluteZoom(rend->scrollTop(), rend);
688 return 0;
689}
690
691void Element::setScrollLeft(int newLeft)
692{
693 document()->updateLayoutIgnorePendingStylesheets();
694 if (RenderBox* rend = renderBox())
695 rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
696}
697
698void Element::setScrollTop(int newTop)
699{
700 document()->updateLayoutIgnorePendingStylesheets();
701 if (RenderBox* rend = renderBox())
702 rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
703}
704
705int Element::scrollWidth()
706{
707 document()->updateLayoutIgnorePendingStylesheets();
708 if (RenderBox* rend = renderBox())
709 return adjustForAbsoluteZoom(rend->scrollWidth(), rend);
710 return 0;
711}
712
713int Element::scrollHeight()
714{
715 document()->updateLayoutIgnorePendingStylesheets();
716 if (RenderBox* rend = renderBox())
717 return adjustForAbsoluteZoom(rend->scrollHeight(), rend);
718 return 0;
719}
720
721IntRect Element::boundsInRootViewSpace()
722{
723 document()->updateLayoutIgnorePendingStylesheets();
724
725 FrameView* view = document()->view();
726 if (!view)
727 return IntRect();
728
729 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100730 if (isSVGElement() && renderer()) {
731 // Get the bounding rectangle from the SVG model.
732 SVGElement* svgElement = toSVGElement(this);
733 FloatRect localRect;
734 if (svgElement->getBoundingBox(localRect))
735 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100736 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100737 // Get the bounding rectangle from the box model.
738 if (renderBoxModelObject())
739 renderBoxModelObject()->absoluteQuads(quads);
740 }
741
742 if (quads.isEmpty())
743 return IntRect();
744
745 IntRect result = quads[0].enclosingBoundingBox();
746 for (size_t i = 1; i < quads.size(); ++i)
747 result.unite(quads[i].enclosingBoundingBox());
748
749 result = view->contentsToRootView(result);
750 return result;
751}
752
753PassRefPtr<ClientRectList> Element::getClientRects()
754{
755 document()->updateLayoutIgnorePendingStylesheets();
756
757 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject();
758 if (!renderBoxModelObject)
759 return ClientRectList::create();
760
761 // FIXME: Handle SVG elements.
762 // FIXME: Handle table/inline-table with a caption.
763
764 Vector<FloatQuad> quads;
765 renderBoxModelObject->absoluteQuads(quads);
766 document()->adjustFloatQuadsForScrollAndAbsoluteZoom(quads, renderBoxModelObject);
767 return ClientRectList::create(quads);
768}
769
770PassRefPtr<ClientRect> Element::getBoundingClientRect()
771{
772 document()->updateLayoutIgnorePendingStylesheets();
773
774 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100775 if (isSVGElement() && renderer() && !renderer()->isSVGRoot()) {
776 // Get the bounding rectangle from the SVG model.
777 SVGElement* svgElement = toSVGElement(this);
778 FloatRect localRect;
779 if (svgElement->getBoundingBox(localRect))
780 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100781 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100782 // Get the bounding rectangle from the box model.
783 if (renderBoxModelObject())
784 renderBoxModelObject()->absoluteQuads(quads);
785 }
786
787 if (quads.isEmpty())
788 return ClientRect::create();
789
790 FloatRect result = quads[0].boundingBox();
791 for (size_t i = 1; i < quads.size(); ++i)
792 result.unite(quads[i].boundingBox());
793
794 document()->adjustFloatRectForScrollAndAbsoluteZoom(result, renderer());
795 return ClientRect::create(result);
796}
Ben Murdoch591b9582013-07-10 11:41:44 +0100797
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100798IntRect Element::screenRect() const
799{
800 if (!renderer())
801 return IntRect();
802 // FIXME: this should probably respect transforms
803 return document()->view()->contentsToScreen(renderer()->absoluteBoundingBoxRectIgnoringTransforms());
804}
805
806const AtomicString& Element::getAttribute(const AtomicString& localName) const
807{
808 if (!elementData())
809 return nullAtom;
810 synchronizeAttribute(localName);
811 if (const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase(this)))
812 return attribute->value();
813 return nullAtom;
814}
815
816const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
817{
818 return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
819}
820
821void Element::setAttribute(const AtomicString& localName, const AtomicString& value, ExceptionCode& ec)
822{
823 if (!Document::isValidName(localName)) {
Ben Murdoche69819b2013-07-17 14:56:49 +0100824 ec = InvalidCharacterError;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100825 return;
826 }
827
828 synchronizeAttribute(localName);
829 const AtomicString& caseAdjustedLocalName = shouldIgnoreAttributeCase(this) ? localName.lower() : localName;
830
831 size_t index = elementData() ? elementData()->getAttributeItemIndex(caseAdjustedLocalName, false) : notFound;
832 const QualifiedName& qName = index != notFound ? attributeItem(index)->name() : QualifiedName(nullAtom, caseAdjustedLocalName, nullAtom);
833 setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute);
834}
835
836void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
837{
838 synchronizeAttribute(name);
839 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : notFound;
840 setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute);
841}
842
843void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value)
844{
845 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : notFound;
846 setAttributeInternal(index, name, value, InSynchronizationOfLazyAttribute);
847}
848
849inline void Element::setAttributeInternal(size_t index, const QualifiedName& name, const AtomicString& newValue, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
850{
851 if (newValue.isNull()) {
852 if (index != notFound)
853 removeAttributeInternal(index, inSynchronizationOfLazyAttribute);
854 return;
855 }
856
857 if (index == notFound) {
858 addAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute);
859 return;
860 }
861
862 if (!inSynchronizationOfLazyAttribute)
863 willModifyAttribute(name, attributeItem(index)->value(), newValue);
864
865 if (newValue != attributeItem(index)->value()) {
866 // If there is an Attr node hooked to this attribute, the Attr::setValue() call below
867 // will write into the ElementData.
868 // FIXME: Refactor this so it makes some sense.
869 if (RefPtr<Attr> attrNode = inSynchronizationOfLazyAttribute ? 0 : attrIfExists(name))
870 attrNode->setValue(newValue);
871 else
872 ensureUniqueElementData()->attributeItem(index)->setValue(newValue);
873 }
874
875 if (!inSynchronizationOfLazyAttribute)
876 didModifyAttribute(name, newValue);
877}
878
879static inline AtomicString makeIdForStyleResolution(const AtomicString& value, bool inQuirksMode)
880{
881 if (inQuirksMode)
882 return value.lower();
883 return value;
884}
885
Ben Murdoch7757ec22013-07-23 11:17:36 +0100886static bool checkNeedsStyleInvalidationForIdChange(const AtomicString& oldId, const AtomicString& newId, const RuleFeatureSet& features)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100887{
888 ASSERT(newId != oldId);
Ben Murdoch7757ec22013-07-23 11:17:36 +0100889 if (!oldId.isEmpty() && features.hasSelectorForId(oldId))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100890 return true;
Ben Murdoch7757ec22013-07-23 11:17:36 +0100891 if (!newId.isEmpty() && features.hasSelectorForId(newId))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100892 return true;
893 return false;
894}
895
Ben Murdoch591b9582013-07-10 11:41:44 +0100896void Element::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100897{
898 if (ElementShadow* parentElementShadow = shadowOfParentForDistribution(this)) {
899 if (shouldInvalidateDistributionWhenAttributeChanged(parentElementShadow, name, newValue))
900 parentElementShadow->invalidateDistribution();
901 }
902
903 parseAttribute(name, newValue);
904
905 document()->incDOMTreeVersion();
906
907 StyleResolver* styleResolver = document()->styleResolverIfExists();
Ben Murdoche69819b2013-07-17 14:56:49 +0100908 bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < SubtreeStyleChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100909 bool shouldInvalidateStyle = false;
910
Ben Murdoch591b9582013-07-10 11:41:44 +0100911 if (isStyledElement() && name == styleAttr) {
912 styleAttributeChanged(newValue, reason);
913 } else if (isStyledElement() && isPresentationAttribute(name)) {
914 elementData()->m_presentationAttributeStyleIsDirty = true;
Ben Murdoche69819b2013-07-17 14:56:49 +0100915 setNeedsStyleRecalc(LocalStyleChange);
Ben Murdoch591b9582013-07-10 11:41:44 +0100916 }
917
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100918 if (isIdAttributeName(name)) {
919 AtomicString oldId = elementData()->idForStyleResolution();
920 AtomicString newId = makeIdForStyleResolution(newValue, document()->inQuirksMode());
921 if (newId != oldId) {
922 elementData()->setIdForStyleResolution(newId);
Ben Murdoch7757ec22013-07-23 11:17:36 +0100923 shouldInvalidateStyle = testShouldInvalidateStyle && checkNeedsStyleInvalidationForIdChange(oldId, newId, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100924 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100925 } else if (name == classAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100926 classAttributeChanged(newValue);
Ben Murdoch591b9582013-07-10 11:41:44 +0100927 } else if (name == HTMLNames::nameAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100928 setHasName(!newValue.isNull());
Ben Murdoch591b9582013-07-10 11:41:44 +0100929 } else if (name == HTMLNames::pseudoAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100930 shouldInvalidateStyle |= testShouldInvalidateStyle && isInShadowTree();
Ben Murdoch591b9582013-07-10 11:41:44 +0100931 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100932
933 invalidateNodeListCachesInAncestors(&name, this);
934
935 // If there is currently no StyleResolver, we can't be sure that this attribute change won't affect style.
936 shouldInvalidateStyle |= !styleResolver;
937
938 if (shouldInvalidateStyle)
939 setNeedsStyleRecalc();
940
941 if (AXObjectCache* cache = document()->existingAXObjectCache())
942 cache->handleAttributeChanged(name, this);
943}
944
945inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
946{
Ben Murdoche69819b2013-07-17 14:56:49 +0100947 if (name == isAttr)
Ben Murdoch0019e4e2013-07-18 11:57:54 +0100948 CustomElementRegistrationContext::setTypeExtension(this, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100949 attributeChanged(name, newValue, reason);
950}
951
952template <typename CharacterType>
953static inline bool classStringHasClassName(const CharacterType* characters, unsigned length)
954{
955 ASSERT(length > 0);
956
957 unsigned i = 0;
958 do {
959 if (isNotHTMLSpace(characters[i]))
960 break;
961 ++i;
962 } while (i < length);
963
964 return i < length;
965}
966
967static inline bool classStringHasClassName(const AtomicString& newClassString)
968{
969 unsigned length = newClassString.length();
970
971 if (!length)
972 return false;
973
974 if (newClassString.is8Bit())
975 return classStringHasClassName(newClassString.characters8(), length);
976 return classStringHasClassName(newClassString.characters16(), length);
977}
978
979template<typename Checker>
980static bool checkSelectorForClassChange(const SpaceSplitString& changedClasses, const Checker& checker)
981{
982 unsigned changedSize = changedClasses.size();
983 for (unsigned i = 0; i < changedSize; ++i) {
984 if (checker.hasSelectorForClass(changedClasses[i]))
985 return true;
986 }
987 return false;
988}
989
990template<typename Checker>
991static bool checkSelectorForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, const Checker& checker)
992{
993 unsigned oldSize = oldClasses.size();
994 if (!oldSize)
995 return checkSelectorForClassChange(newClasses, checker);
996 BitVector remainingClassBits;
997 remainingClassBits.ensureSize(oldSize);
998 // Class vectors tend to be very short. This is faster than using a hash table.
999 unsigned newSize = newClasses.size();
1000 for (unsigned i = 0; i < newSize; ++i) {
1001 for (unsigned j = 0; j < oldSize; ++j) {
1002 if (newClasses[i] == oldClasses[j]) {
1003 remainingClassBits.quickSet(j);
1004 continue;
1005 }
1006 }
1007 if (checker.hasSelectorForClass(newClasses[i]))
1008 return true;
1009 }
1010 for (unsigned i = 0; i < oldSize; ++i) {
1011 // If the bit is not set the the corresponding class has been removed.
1012 if (remainingClassBits.quickGet(i))
1013 continue;
1014 if (checker.hasSelectorForClass(oldClasses[i]))
1015 return true;
1016 }
1017 return false;
1018}
1019
1020void Element::classAttributeChanged(const AtomicString& newClassString)
1021{
1022 StyleResolver* styleResolver = document()->styleResolverIfExists();
Ben Murdoche69819b2013-07-17 14:56:49 +01001023 bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < SubtreeStyleChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001024 bool shouldInvalidateStyle = false;
1025
1026 if (classStringHasClassName(newClassString)) {
1027 const bool shouldFoldCase = document()->inQuirksMode();
1028 const SpaceSplitString oldClasses = elementData()->classNames();
1029 elementData()->setClass(newClassString, shouldFoldCase);
1030 const SpaceSplitString& newClasses = elementData()->classNames();
Ben Murdoch7757ec22013-07-23 11:17:36 +01001031 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, newClasses, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001032 } else {
1033 const SpaceSplitString& oldClasses = elementData()->classNames();
Ben Murdoch7757ec22013-07-23 11:17:36 +01001034 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, styleResolver->ruleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001035 elementData()->clearClass();
1036 }
1037
1038 if (hasRareData())
1039 elementRareData()->clearClassListValueForQuirksMode();
1040
1041 if (shouldInvalidateStyle)
1042 setNeedsStyleRecalc();
1043}
1044
1045bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
1046{
1047 ASSERT(elementShadow);
1048 const SelectRuleFeatureSet& featureSet = elementShadow->distributor().ensureSelectFeatureSet(elementShadow);
1049
1050 if (isIdAttributeName(name)) {
1051 AtomicString oldId = elementData()->idForStyleResolution();
1052 AtomicString newId = makeIdForStyleResolution(newValue, document()->inQuirksMode());
1053 if (newId != oldId) {
1054 if (!oldId.isEmpty() && featureSet.hasSelectorForId(oldId))
1055 return true;
1056 if (!newId.isEmpty() && featureSet.hasSelectorForId(newId))
1057 return true;
1058 }
1059 }
1060
1061 if (name == HTMLNames::classAttr) {
1062 const AtomicString& newClassString = newValue;
1063 if (classStringHasClassName(newClassString)) {
1064 const bool shouldFoldCase = document()->inQuirksMode();
1065 const SpaceSplitString& oldClasses = elementData()->classNames();
1066 const SpaceSplitString newClasses(newClassString, shouldFoldCase);
1067 if (checkSelectorForClassChange(oldClasses, newClasses, featureSet))
1068 return true;
1069 } else {
1070 const SpaceSplitString& oldClasses = elementData()->classNames();
1071 if (checkSelectorForClassChange(oldClasses, featureSet))
1072 return true;
1073 }
1074 }
1075
1076 return featureSet.hasSelectorForAttribute(name.localName());
1077}
1078
1079// Returns true is the given attribute is an event handler.
1080// We consider an event handler any attribute that begins with "on".
1081// It is a simple solution that has the advantage of not requiring any
1082// code or configuration change if a new event handler is defined.
1083
1084static inline bool isEventHandlerAttribute(const Attribute& attribute)
1085{
1086 return attribute.name().namespaceURI().isNull() && attribute.name().localName().startsWith("on");
1087}
1088
1089bool Element::isJavaScriptURLAttribute(const Attribute& attribute) const
1090{
1091 return isURLAttribute(attribute) && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(attribute.value()));
1092}
1093
1094void Element::stripScriptingAttributes(Vector<Attribute>& attributeVector) const
1095{
1096 size_t destination = 0;
1097 for (size_t source = 0; source < attributeVector.size(); ++source) {
1098 if (isEventHandlerAttribute(attributeVector[source])
1099 || isJavaScriptURLAttribute(attributeVector[source])
1100 || isHTMLContentAttribute(attributeVector[source]))
1101 continue;
1102
1103 if (source != destination)
1104 attributeVector[destination] = attributeVector[source];
1105
1106 ++destination;
1107 }
1108 attributeVector.shrink(destination);
1109}
1110
1111void Element::parserSetAttributes(const Vector<Attribute>& attributeVector)
1112{
1113 ASSERT(!inDocument());
1114 ASSERT(!parentNode());
1115 ASSERT(!m_elementData);
1116
1117 if (attributeVector.isEmpty())
1118 return;
1119
1120 if (document() && document()->sharedObjectPool())
1121 m_elementData = document()->sharedObjectPool()->cachedShareableElementDataWithAttributes(attributeVector);
1122 else
1123 m_elementData = ShareableElementData::createWithAttributes(attributeVector);
1124
1125 // Use attributeVector instead of m_elementData because attributeChanged might modify m_elementData.
1126 for (unsigned i = 0; i < attributeVector.size(); ++i)
1127 attributeChangedFromParserOrByCloning(attributeVector[i].name(), attributeVector[i].value(), ModifiedDirectly);
1128}
1129
1130bool Element::hasAttributes() const
1131{
1132 synchronizeAllAttributes();
1133 return elementData() && elementData()->length();
1134}
1135
1136bool Element::hasEquivalentAttributes(const Element* other) const
1137{
1138 synchronizeAllAttributes();
1139 other->synchronizeAllAttributes();
1140 if (elementData() == other->elementData())
1141 return true;
1142 if (elementData())
1143 return elementData()->isEquivalent(other->elementData());
1144 if (other->elementData())
1145 return other->elementData()->isEquivalent(elementData());
1146 return true;
1147}
1148
1149String Element::nodeName() const
1150{
1151 return m_tagName.toString();
1152}
1153
1154String Element::nodeNamePreservingCase() const
1155{
1156 return m_tagName.toString();
1157}
1158
1159void Element::setPrefix(const AtomicString& prefix, ExceptionCode& ec)
1160{
1161 ec = 0;
1162 checkSetPrefix(prefix, ec);
1163 if (ec)
1164 return;
1165
1166 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
1167}
1168
1169KURL Element::baseURI() const
1170{
1171 const AtomicString& baseAttribute = getAttribute(baseAttr);
1172 KURL base(KURL(), baseAttribute);
1173 if (!base.protocol().isEmpty())
1174 return base;
1175
1176 ContainerNode* parent = parentNode();
1177 if (!parent)
1178 return base;
1179
1180 const KURL& parentBase = parent->baseURI();
1181 if (parentBase.isNull())
1182 return base;
1183
1184 return KURL(parentBase, baseAttribute);
1185}
1186
1187const AtomicString& Element::imageSourceURL() const
1188{
1189 return getAttribute(srcAttr);
1190}
1191
1192bool Element::rendererIsNeeded(const NodeRenderingContext& context)
1193{
1194 return context.style()->display() != NONE;
1195}
1196
Ben Murdoch591b9582013-07-10 11:41:44 +01001197RenderObject* Element::createRenderer(RenderStyle* style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001198{
1199 return RenderObject::createObject(this, style);
1200}
1201
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001202bool Element::isInert() const
1203{
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001204 const Element* dialog = document()->activeModalDialog();
Ben Murdoch591b9582013-07-10 11:41:44 +01001205 if (dialog && !containsIncludingShadowDOM(dialog) && !dialog->containsIncludingShadowDOM(this))
1206 return true;
1207 return document()->ownerElement() && document()->ownerElement()->isInert();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001208}
1209
1210Node::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
1225 if (!insertionPoint->isInTreeScope())
1226 return InsertionDone;
1227
1228 if (hasRareData())
1229 elementRareData()->clearClassListValueForQuirksMode();
1230
1231 TreeScope* scope = insertionPoint->treeScope();
1232 if (scope != treeScope())
1233 return InsertionDone;
1234
Ben Murdoche69819b2013-07-17 14:56:49 +01001235 if (isUpgradedCustomElement())
Ben Murdoch83750172013-07-24 10:36:59 +01001236 CustomElement::didEnterDocument(this);
Ben Murdoche69819b2013-07-17 14:56:49 +01001237
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001238 const AtomicString& idValue = getIdAttribute();
1239 if (!idValue.isNull())
1240 updateId(scope, nullAtom, idValue);
1241
1242 const AtomicString& nameValue = getNameAttribute();
1243 if (!nameValue.isNull())
1244 updateName(nullAtom, nameValue);
1245
1246 if (hasTagName(labelTag)) {
1247 if (scope->shouldCacheLabelsByForAttribute())
1248 updateLabel(scope, nullAtom, fastGetAttribute(forAttr));
1249 }
1250
1251 return InsertionDone;
1252}
1253
1254void Element::removedFrom(ContainerNode* insertionPoint)
1255{
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001256 bool wasInDocument = insertionPoint->document();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001257
1258 if (Element* before = pseudoElement(BEFORE))
1259 before->removedFrom(insertionPoint);
1260
1261 if (Element* after = pseudoElement(AFTER))
1262 after->removedFrom(insertionPoint);
1263
Ben Murdoche69819b2013-07-17 14:56:49 +01001264 if (Element* backdrop = pseudoElement(BACKDROP))
1265 backdrop->removedFrom(insertionPoint);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001266 document()->removeFromTopLayer(this);
Ben Murdoche69819b2013-07-17 14:56:49 +01001267
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001268 if (containsFullScreenElement())
1269 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
1270
1271 if (document()->page())
1272 document()->page()->pointerLockController()->elementRemoved(this);
1273
1274 setSavedLayerScrollOffset(IntSize());
1275
1276 if (insertionPoint->isInTreeScope() && treeScope() == document()) {
1277 const AtomicString& idValue = getIdAttribute();
1278 if (!idValue.isNull())
1279 updateId(insertionPoint->treeScope(), idValue, nullAtom);
1280
1281 const AtomicString& nameValue = getNameAttribute();
1282 if (!nameValue.isNull())
1283 updateName(nameValue, nullAtom);
1284
1285 if (hasTagName(labelTag)) {
1286 TreeScope* treeScope = insertionPoint->treeScope();
1287 if (treeScope->shouldCacheLabelsByForAttribute())
1288 updateLabel(treeScope, fastGetAttribute(forAttr), nullAtom);
1289 }
1290 }
1291
1292 ContainerNode::removedFrom(insertionPoint);
Ben Murdoche69819b2013-07-17 14:56:49 +01001293 if (wasInDocument) {
1294 if (hasPendingResources())
1295 document()->accessSVGExtensions()->removeElementFromPendingResources(this);
1296
Ben Murdoch83750172013-07-24 10:36:59 +01001297 if (isUpgradedCustomElement())
1298 CustomElement::didLeaveDocument(this);
Ben Murdoche69819b2013-07-17 14:56:49 +01001299 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001300}
1301
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001302void Element::createRendererIfNeeded(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001303{
Ben Murdoch83750172013-07-24 10:36:59 +01001304 NodeRenderingContext(this, context.resolvedStyle).createRendererForElementIfNeeded();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001305}
1306
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001307void Element::attach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001308{
1309 PostAttachCallbackDisabler callbackDisabler(this);
1310 StyleResolverParentPusher parentPusher(this);
1311 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1312
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001313 createRendererIfNeeded(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001314
1315 if (parentElement() && parentElement()->isInCanvasSubtree())
1316 setIsInCanvasSubtree(true);
1317
1318 createPseudoElementIfNeeded(BEFORE);
1319
1320 // When a shadow root exists, it does the work of attaching the children.
1321 if (ElementShadow* shadow = this->shadow()) {
1322 parentPusher.push();
Ben Murdoch591b9582013-07-10 11:41:44 +01001323 shadow->attach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001324 } else if (firstChild())
1325 parentPusher.push();
1326
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001327 ContainerNode::attach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001328
1329 createPseudoElementIfNeeded(AFTER);
Ben Murdoche69819b2013-07-17 14:56:49 +01001330 createPseudoElementIfNeeded(BACKDROP);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001331
Ben Murdoch591b9582013-07-10 11:41:44 +01001332 if (hasRareData()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001333 ElementRareData* data = elementRareData();
1334 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
Ben Murdoch7757ec22013-07-23 11:17:36 +01001335 if (isFocusable() && document()->focusedElement() == this)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001336 document()->updateFocusAppearanceSoon(false /* don't restore selection */);
1337 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1338 }
1339 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001340
1341 // FIXME: It doesn't appear safe to call didRecalculateStyleForElement when
1342 // not in a Document::recalcStyle. Since we're hopefully going to always
1343 // lazyAttach in the future that problem should go away.
1344 if (document()->inStyleRecalc())
1345 InspectorInstrumentation::didRecalculateStyleForElement(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001346}
1347
1348void Element::unregisterNamedFlowContentNode()
1349{
1350 if (RuntimeEnabledFeatures::cssRegionsEnabled() && inNamedFlow() && document()->renderView())
1351 document()->renderView()->flowThreadController()->unregisterNamedFlowContentNode(this);
1352}
1353
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001354void Element::detach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001355{
1356 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1357 unregisterNamedFlowContentNode();
1358 cancelFocusAppearanceUpdate();
1359 if (hasRareData()) {
1360 ElementRareData* data = elementRareData();
1361 data->setPseudoElement(BEFORE, 0);
1362 data->setPseudoElement(AFTER, 0);
Ben Murdoche69819b2013-07-17 14:56:49 +01001363 data->setPseudoElement(BACKDROP, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001364 data->setIsInCanvasSubtree(false);
1365 data->resetComputedStyle();
1366 data->resetDynamicRestyleObservations();
Ben Murdoch591b9582013-07-10 11:41:44 +01001367 data->setIsInsideRegion(false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001368 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001369 if (ElementShadow* shadow = this->shadow())
1370 shadow->detach(context);
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001371 ContainerNode::detach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001372}
1373
1374bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle)
1375{
1376 ASSERT(currentStyle == renderStyle());
1377 ASSERT(renderer());
1378
1379 if (!currentStyle)
1380 return false;
1381
1382 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles();
1383 if (!pseudoStyleCache)
1384 return false;
1385
1386 size_t cacheSize = pseudoStyleCache->size();
1387 for (size_t i = 0; i < cacheSize; ++i) {
1388 RefPtr<RenderStyle> newPseudoStyle;
1389 PseudoId pseudoId = pseudoStyleCache->at(i)->styleType();
1390 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
1391 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle);
1392 else
1393 newPseudoStyle = renderer()->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
1394 if (!newPseudoStyle)
1395 return true;
1396 if (*newPseudoStyle != *pseudoStyleCache->at(i)) {
1397 if (pseudoId < FIRST_INTERNAL_PSEUDOID)
1398 newStyle->setHasPseudoStyle(pseudoId);
1399 newStyle->addCachedPseudoStyle(newPseudoStyle);
1400 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
1401 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
1402 // is needed, but for now just assume a layout will be required. The diff code
1403 // in RenderObject::setStyle would need to be factored out so that it could be reused.
1404 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
1405 }
1406 return true;
1407 }
1408 }
1409 return false;
1410}
1411
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001412PassRefPtr<RenderStyle> Element::styleForRenderer()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001413{
1414 if (hasCustomStyleCallbacks()) {
1415 if (RefPtr<RenderStyle> style = customStyleForRenderer())
1416 return style.release();
1417 }
1418
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001419 return originalStyleForRenderer();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001420}
1421
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001422PassRefPtr<RenderStyle> Element::originalStyleForRenderer()
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001423{
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001424 return document()->styleResolver()->styleForElement(this);
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001425}
1426
Ben Murdoche69819b2013-07-17 14:56:49 +01001427bool Element::recalcStyle(StyleChange change)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001428{
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001429 ASSERT(document()->inStyleRecalc());
1430
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001431 if (hasCustomStyleCallbacks())
1432 willRecalcStyle(change);
1433
1434 // Ref currentStyle in case it would otherwise be deleted when setting the new style in the renderer.
Ben Murdoch83750172013-07-24 10:36:59 +01001435 RefPtr<RenderStyle> currentStyle = renderStyle();
1436 bool hasParentStyle = static_cast<bool>(parentRenderStyle());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001437 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
1438 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
1439
Ben Murdoch83750172013-07-24 10:36:59 +01001440 if (change > NoChange || needsStyleRecalc()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001441 if (hasRareData())
1442 elementRareData()->resetComputedStyle();
1443 }
1444 if (hasParentStyle && (change >= Inherit || needsStyleRecalc())) {
1445 StyleChange localChange = Detach;
1446 RefPtr<RenderStyle> newStyle;
1447 if (currentStyle) {
1448 // FIXME: This still recalcs style twice when changing display types, but saves
1449 // us from recalcing twice when going from none -> anything else which is more
1450 // common, especially during lazy attach.
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001451 newStyle = styleForRenderer();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001452 localChange = Node::diff(currentStyle.get(), newStyle.get(), document());
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001453 } else if (attached() && isActiveInsertionPoint(this)) {
1454 // Active InsertionPoints will never have renderers so there's no reason to
1455 // reattach them repeatedly once they're already attached.
1456 localChange = change;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001457 }
1458 if (localChange == Detach) {
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001459 AttachContext reattachContext;
1460 reattachContext.resolvedStyle = newStyle.get();
1461 reattach(reattachContext);
1462
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001463 // attach recalculates the style for all children. No need to do it twice.
1464 clearNeedsStyleRecalc();
1465 clearChildNeedsStyleRecalc();
1466
1467 if (hasCustomStyleCallbacks())
1468 didRecalcStyle(change);
Ben Murdoche69819b2013-07-17 14:56:49 +01001469 return true;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001470 }
1471
Ben Murdoch591b9582013-07-10 11:41:44 +01001472 InspectorInstrumentation::didRecalculateStyleForElement(this);
1473
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001474 if (RenderObject* renderer = this->renderer()) {
Ben Murdoche69819b2013-07-17 14:56:49 +01001475 if (localChange != NoChange || pseudoStyleCacheIsInvalid(currentStyle.get(), newStyle.get()) || (change == Force && renderer->requiresForcedStyleRecalcPropagation()) || shouldNotifyRendererWithIdenticalStyles())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001476 renderer->setAnimatableStyle(newStyle.get());
1477 else if (needsStyleRecalc()) {
1478 // Although no change occurred, we use the new style so that the cousin style sharing code won't get
1479 // fooled into believing this style is the same.
1480 renderer->setStyleInternal(newStyle.get());
1481 }
1482 }
1483
1484 // 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
1485 // 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).
1486 if (document()->styleSheetCollection()->usesRemUnits() && document()->documentElement() == this && localChange != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize()) {
1487 // Cached RenderStyles may depend on the re units.
1488 document()->styleResolver()->invalidateMatchedPropertiesCache();
1489 change = Force;
1490 }
1491
Ben Murdoche69819b2013-07-17 14:56:49 +01001492 if (styleChangeType() == SubtreeStyleChange)
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001493 change = Force;
1494 else if (change != Force)
1495 change = localChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001496 }
1497 StyleResolverParentPusher parentPusher(this);
1498
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001499 if (ElementShadow* shadow = this->shadow()) {
Ben Murdoch83750172013-07-24 10:36:59 +01001500 for (ShadowRoot* root = shadow->youngestShadowRoot(); root; root = root->olderShadowRoot()) {
1501 if (shouldRecalcStyle(change, root)) {
1502 parentPusher.push();
1503 root->recalcStyle(change);
1504 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001505 }
1506 }
1507
1508 if (shouldRecalcStyle(change, this))
1509 updatePseudoElement(BEFORE, change);
1510
1511 // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
1512 // For now we will just worry about the common case, since it's a lot trickier to get the second case right
1513 // without doing way too much re-resolution.
1514 bool forceCheckOfNextElementSibling = false;
1515 bool forceCheckOfAnyElementSibling = false;
Ben Murdoche69819b2013-07-17 14:56:49 +01001516 bool forceReattachOfAnyWhitespaceSibling = false;
1517 for (Node* child = firstChild(); child; child = child->nextSibling()) {
1518 bool didReattach = false;
1519
1520 if (child->renderer())
1521 forceReattachOfAnyWhitespaceSibling = false;
1522
1523 if (child->isTextNode()) {
1524 if (forceReattachOfAnyWhitespaceSibling && toText(child)->containsOnlyWhitespace())
1525 child->reattach();
1526 else
1527 didReattach = toText(child)->recalcTextStyle(change);
1528 } else if (child->isElementNode()) {
1529 Element* element = toElement(child);
1530
1531 if (forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling)
1532 element->setNeedsStyleRecalc();
1533
1534 bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() == SubtreeStyleChange;
1535 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
1536 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
1537
1538 if (shouldRecalcStyle(change, element)) {
1539 parentPusher.push();
1540 didReattach = element->recalcStyle(change);
1541 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001542 }
Ben Murdoche69819b2013-07-17 14:56:49 +01001543
1544 forceReattachOfAnyWhitespaceSibling = didReattach || forceReattachOfAnyWhitespaceSibling;
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001545 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001546
1547 if (shouldRecalcStyle(change, this))
1548 updatePseudoElement(AFTER, change);
1549
1550 clearNeedsStyleRecalc();
1551 clearChildNeedsStyleRecalc();
Ben Murdoch591b9582013-07-10 11:41:44 +01001552
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001553 if (hasCustomStyleCallbacks())
1554 didRecalcStyle(change);
Ben Murdoche69819b2013-07-17 14:56:49 +01001555 return false;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001556}
1557
1558ElementShadow* Element::shadow() const
1559{
1560 return hasRareData() ? elementRareData()->shadow() : 0;
1561}
1562
1563ElementShadow* Element::ensureShadow()
1564{
1565 return ensureElementRareData()->ensureShadow();
1566}
1567
1568void Element::didAffectSelector(AffectedSelectorMask mask)
1569{
1570 setNeedsStyleRecalc();
1571 if (ElementShadow* elementShadow = shadowOfParentForDistribution(this))
1572 elementShadow->didAffectSelector(mask);
1573}
1574
1575PassRefPtr<ShadowRoot> Element::createShadowRoot(ExceptionCode& ec)
1576{
1577 if (alwaysCreateUserAgentShadowRoot())
1578 ensureUserAgentShadowRoot();
1579
1580 if (RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled())
1581 return ensureShadow()->addShadowRoot(this, ShadowRoot::AuthorShadowRoot);
1582
1583 // Since some elements recreates shadow root dynamically, multiple shadow
1584 // subtrees won't work well in that element. Until they are fixed, we disable
1585 // adding author shadow root for them.
1586 if (!areAuthorShadowsAllowed()) {
Ben Murdoche69819b2013-07-17 14:56:49 +01001587 ec = HierarchyRequestError;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001588 return 0;
1589 }
1590 return ensureShadow()->addShadowRoot(this, ShadowRoot::AuthorShadowRoot);
1591}
1592
1593ShadowRoot* Element::shadowRoot() const
1594{
1595 ElementShadow* elementShadow = shadow();
1596 if (!elementShadow)
1597 return 0;
1598 ShadowRoot* shadowRoot = elementShadow->youngestShadowRoot();
1599 if (shadowRoot->type() == ShadowRoot::AuthorShadowRoot)
1600 return shadowRoot;
1601 return 0;
1602}
1603
1604ShadowRoot* Element::userAgentShadowRoot() const
1605{
1606 if (ElementShadow* elementShadow = shadow()) {
1607 if (ShadowRoot* shadowRoot = elementShadow->oldestShadowRoot()) {
1608 ASSERT(shadowRoot->type() == ShadowRoot::UserAgentShadowRoot);
1609 return shadowRoot;
1610 }
1611 }
1612
1613 return 0;
1614}
1615
1616ShadowRoot* Element::ensureUserAgentShadowRoot()
1617{
1618 if (ShadowRoot* shadowRoot = userAgentShadowRoot())
1619 return shadowRoot;
1620 ShadowRoot* shadowRoot = ensureShadow()->addShadowRoot(this, ShadowRoot::UserAgentShadowRoot);
1621 didAddUserAgentShadowRoot(shadowRoot);
1622 return shadowRoot;
1623}
1624
1625const AtomicString& Element::shadowPseudoId() const
1626{
1627 return pseudo();
1628}
1629
1630bool Element::childTypeAllowed(NodeType type) const
1631{
1632 switch (type) {
1633 case ELEMENT_NODE:
1634 case TEXT_NODE:
1635 case COMMENT_NODE:
1636 case PROCESSING_INSTRUCTION_NODE:
1637 case CDATA_SECTION_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001638 return true;
1639 default:
1640 break;
1641 }
1642 return false;
1643}
1644
Ben Murdoch83750172013-07-24 10:36:59 +01001645static void inline checkForEmptyStyleChange(Element* element, RenderStyle* style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001646{
1647 if (!style && !element->styleAffectedByEmpty())
1648 return;
1649
1650 if (!style || (element->styleAffectedByEmpty() && (!style->emptyState() || element->hasChildNodes())))
1651 element->setNeedsStyleRecalc();
1652}
1653
1654static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
1655 Node* beforeChange, Node* afterChange, int childCountDelta)
1656{
Ben Murdoch83750172013-07-24 10:36:59 +01001657 if (!e->attached() || e->document()->hasPendingForcedStyleRecalc() || e->styleChangeType() == SubtreeStyleChange)
1658 return;
1659
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001660 // :empty selector.
1661 checkForEmptyStyleChange(e, style);
Ben Murdoch591b9582013-07-10 11:41:44 +01001662
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001663 if (!style || (e->needsStyleRecalc() && e->childrenAffectedByPositionalRules()))
1664 return;
1665
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001666 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
1667 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1668 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
1669 // backward case.
1670 // |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.
1671 // 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 +01001672 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
1673 if ((e->childrenAffectedByForwardPositionalRules() && afterChange) || (e->childrenAffectedByBackwardPositionalRules() && beforeChange)) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001674 e->setNeedsStyleRecalc();
Ben Murdoch83750172013-07-24 10:36:59 +01001675 return;
1676 }
1677
1678 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1679 // In the DOM case, we only need to do something if |afterChange| is not 0.
1680 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
1681 if (e->childrenAffectedByFirstChildRules() && afterChange) {
1682 // Find our new first child.
1683 Node* newFirstChild = e->firstElementChild();
1684 RenderStyle* newFirstChildStyle = newFirstChild ? newFirstChild->renderStyle() : 0;
1685
1686 // Find the first element node following |afterChange|
1687 Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling();
1688 RenderStyle* firstElementAfterInsertionStyle = firstElementAfterInsertion ? firstElementAfterInsertion->renderStyle() : 0;
1689
1690 // This is the insert/append case.
1691 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertionStyle && firstElementAfterInsertionStyle->firstChildState())
1692 firstElementAfterInsertion->setNeedsStyleRecalc();
1693
1694 // We also have to handle node removal.
1695 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChildStyle || !newFirstChildStyle->firstChildState()))
1696 newFirstChild->setNeedsStyleRecalc();
1697 }
1698
1699 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1700 // In the DOM case, we only need to do something if |afterChange| is not 0.
1701 if (e->childrenAffectedByLastChildRules() && beforeChange) {
1702 // Find our new last child.
1703 Node* newLastChild = e->lastElementChild();
1704 RenderStyle* newLastChildStyle = newLastChild ? newLastChild->renderStyle() : 0;
1705
1706 // Find the last element node going backwards from |beforeChange|
1707 Node* lastElementBeforeInsertion = beforeChange->isElementNode() ? beforeChange : beforeChange->previousElementSibling();
1708 RenderStyle* lastElementBeforeInsertionStyle = lastElementBeforeInsertion ? lastElementBeforeInsertion->renderStyle() : 0;
1709
1710 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertionStyle && lastElementBeforeInsertionStyle->lastChildState())
1711 lastElementBeforeInsertion->setNeedsStyleRecalc();
1712
1713 // 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
1714 // to match now.
1715 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChildStyle || !newLastChildStyle->lastChildState()))
1716 newLastChild->setNeedsStyleRecalc();
1717 }
1718
1719 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
1720 // that could be affected by this DOM change.
1721 if (e->childrenAffectedByDirectAdjacentRules() && afterChange) {
1722 if (Node* firstElementAfterInsertion = afterChange->nextElementSibling())
1723 firstElementAfterInsertion->setNeedsStyleRecalc();
1724 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001725}
1726
1727void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
1728{
1729 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
1730 if (changedByParser)
1731 checkForEmptyStyleChange(this, renderStyle());
1732 else
1733 checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
1734
Ben Murdoch83750172013-07-24 10:36:59 +01001735 if (ElementShadow* shadow = this->shadow())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001736 shadow->invalidateDistribution();
1737}
1738
1739void Element::removeAllEventListeners()
1740{
1741 ContainerNode::removeAllEventListeners();
1742 if (ElementShadow* shadow = this->shadow())
1743 shadow->removeAllEventListeners();
1744}
1745
1746void Element::beginParsingChildren()
1747{
1748 clearIsParsingChildrenFinished();
1749 StyleResolver* styleResolver = document()->styleResolverIfExists();
1750 if (styleResolver && attached())
1751 styleResolver->pushParentElement(this);
1752}
1753
1754void Element::finishParsingChildren()
1755{
1756 ContainerNode::finishParsingChildren();
1757 setIsParsingChildrenFinished();
1758 checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
1759 if (StyleResolver* styleResolver = document()->styleResolverIfExists())
1760 styleResolver->popParentElement(this);
1761}
1762
1763#ifndef NDEBUG
1764void Element::formatForDebugger(char* buffer, unsigned length) const
1765{
1766 StringBuilder result;
1767 String s;
1768
1769 result.append(nodeName());
1770
1771 s = getIdAttribute();
1772 if (s.length() > 0) {
1773 if (result.length() > 0)
1774 result.appendLiteral("; ");
1775 result.appendLiteral("id=");
1776 result.append(s);
1777 }
1778
1779 s = getAttribute(classAttr);
1780 if (s.length() > 0) {
1781 if (result.length() > 0)
1782 result.appendLiteral("; ");
1783 result.appendLiteral("class=");
1784 result.append(s);
1785 }
1786
1787 strncpy(buffer, result.toString().utf8().data(), length - 1);
1788}
1789#endif
1790
1791const Vector<RefPtr<Attr> >& Element::attrNodeList()
1792{
1793 ASSERT(hasSyntheticAttrChildNodes());
1794 return *attrNodeListForElement(this);
1795}
1796
1797PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionCode& ec)
1798{
1799 if (!attrNode) {
Ben Murdoche69819b2013-07-17 14:56:49 +01001800 ec = TypeMismatchError;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001801 return 0;
1802 }
1803
1804 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName());
1805 if (oldAttrNode.get() == attrNode)
1806 return attrNode; // This Attr is already attached to the element.
1807
Ben Murdoche69819b2013-07-17 14:56:49 +01001808 // 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 +01001809 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
1810 if (attrNode->ownerElement()) {
Ben Murdoche69819b2013-07-17 14:56:49 +01001811 ec = InUseAttributeError;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001812 return 0;
1813 }
1814
1815 synchronizeAllAttributes();
1816 UniqueElementData* elementData = ensureUniqueElementData();
1817
1818 size_t index = elementData->getAttributeItemIndex(attrNode->qualifiedName());
1819 if (index != notFound) {
1820 if (oldAttrNode)
1821 detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData->attributeItem(index)->value());
1822 else
1823 oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), elementData->attributeItem(index)->value());
1824 }
1825
1826 setAttributeInternal(index, attrNode->qualifiedName(), attrNode->value(), NotInSynchronizationOfLazyAttribute);
1827
1828 attrNode->attachToElement(this);
Ben Murdoch591b9582013-07-10 11:41:44 +01001829 treeScope()->adoptIfNeeded(attrNode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001830 ensureAttrNodeListForElement(this)->append(attrNode);
1831
1832 return oldAttrNode.release();
1833}
1834
1835PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionCode& ec)
1836{
1837 return setAttributeNode(attr, ec);
1838}
1839
1840PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec)
1841{
1842 if (!attr) {
Ben Murdoche69819b2013-07-17 14:56:49 +01001843 ec = TypeMismatchError;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001844 return 0;
1845 }
1846 if (attr->ownerElement() != this) {
Ben Murdoche69819b2013-07-17 14:56:49 +01001847 ec = NotFoundError;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001848 return 0;
1849 }
1850
1851 ASSERT(document() == attr->document());
1852
1853 synchronizeAttribute(attr->qualifiedName());
1854
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001855 size_t index = elementData()->getAttrIndex(attr);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001856 if (index == notFound) {
Ben Murdoche69819b2013-07-17 14:56:49 +01001857 ec = NotFoundError;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001858 return 0;
1859 }
1860
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001861 RefPtr<Attr> guard(attr);
1862 detachAttrNodeAtIndex(attr, index);
1863 return guard.release();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001864}
1865
1866bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionCode& ec)
1867{
1868 String prefix, localName;
1869 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec))
1870 return false;
1871 ASSERT(!ec);
1872
1873 QualifiedName qName(prefix, localName, namespaceURI);
1874
1875 if (!Document::hasValidNamespaceForAttributes(qName)) {
Ben Murdoche69819b2013-07-17 14:56:49 +01001876 ec = NamespaceError;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001877 return false;
1878 }
1879
1880 out = qName;
1881 return true;
1882}
1883
1884void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode& ec)
1885{
1886 QualifiedName parsedName = anyName;
1887 if (!parseAttributeName(parsedName, namespaceURI, qualifiedName, ec))
1888 return;
1889 setAttribute(parsedName, value);
1890}
1891
1892void Element::removeAttributeInternal(size_t index, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1893{
1894 ASSERT_WITH_SECURITY_IMPLICATION(index < attributeCount());
1895
1896 UniqueElementData* elementData = ensureUniqueElementData();
1897
1898 QualifiedName name = elementData->attributeItem(index)->name();
1899 AtomicString valueBeingRemoved = elementData->attributeItem(index)->value();
1900
1901 if (!inSynchronizationOfLazyAttribute) {
1902 if (!valueBeingRemoved.isNull())
1903 willModifyAttribute(name, valueBeingRemoved, nullAtom);
1904 }
1905
1906 if (RefPtr<Attr> attrNode = attrIfExists(name))
1907 detachAttrNodeFromElementWithValue(attrNode.get(), elementData->attributeItem(index)->value());
1908
1909 elementData->removeAttribute(index);
1910
1911 if (!inSynchronizationOfLazyAttribute)
1912 didRemoveAttribute(name);
1913}
1914
1915void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1916{
1917 if (!inSynchronizationOfLazyAttribute)
1918 willModifyAttribute(name, nullAtom, value);
1919 ensureUniqueElementData()->addAttribute(name, value);
1920 if (!inSynchronizationOfLazyAttribute)
1921 didAddAttribute(name, value);
1922}
1923
1924void Element::removeAttribute(const AtomicString& name)
1925{
1926 if (!elementData())
1927 return;
1928
1929 AtomicString localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1930 size_t index = elementData()->getAttributeItemIndex(localName, false);
1931 if (index == notFound) {
1932 if (UNLIKELY(localName == styleAttr) && elementData()->m_styleAttributeIsDirty && isStyledElement())
Ben Murdoch591b9582013-07-10 11:41:44 +01001933 removeAllInlineStyleProperties();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001934 return;
1935 }
1936
1937 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
1938}
1939
1940void Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName)
1941{
1942 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI));
1943}
1944
1945PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& localName)
1946{
1947 if (!elementData())
1948 return 0;
1949 synchronizeAttribute(localName);
1950 const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase(this));
1951 if (!attribute)
1952 return 0;
1953 return ensureAttr(attribute->name());
1954}
1955
1956PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
1957{
1958 if (!elementData())
1959 return 0;
1960 QualifiedName qName(nullAtom, localName, namespaceURI);
1961 synchronizeAttribute(qName);
1962 const Attribute* attribute = elementData()->getAttributeItem(qName);
1963 if (!attribute)
1964 return 0;
1965 return ensureAttr(attribute->name());
1966}
1967
1968bool Element::hasAttribute(const AtomicString& localName) const
1969{
1970 if (!elementData())
1971 return false;
1972 synchronizeAttribute(localName);
1973 return elementData()->getAttributeItem(shouldIgnoreAttributeCase(this) ? localName.lower() : localName, false);
1974}
1975
1976bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
1977{
1978 if (!elementData())
1979 return false;
1980 QualifiedName qName(nullAtom, localName, namespaceURI);
1981 synchronizeAttribute(qName);
1982 return elementData()->getAttributeItem(qName);
1983}
1984
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001985void Element::focus(bool restorePreviousSelection, FocusDirection direction)
1986{
1987 if (!inDocument())
1988 return;
1989
1990 Document* doc = document();
Ben Murdoch7757ec22013-07-23 11:17:36 +01001991 if (doc->focusedElement() == this)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001992 return;
1993
1994 // If the stylesheets have already been loaded we can reliably check isFocusable.
1995 // If not, we continue and set the focused node on the focus controller below so
Ben Murdoch591b9582013-07-10 11:41:44 +01001996 // that it can be updated soon after attach.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001997 if (doc->haveStylesheetsLoaded()) {
1998 doc->updateLayoutIgnorePendingStylesheets();
1999 if (!isFocusable())
2000 return;
2001 }
2002
2003 if (!supportsFocus())
2004 return;
2005
2006 RefPtr<Node> protect;
2007 if (Page* page = doc->page()) {
2008 // Focus and change event handlers can cause us to lose our last ref.
2009 // If a focus event handler changes the focus to a different node it
2010 // does not make sense to continue and update appearence.
2011 protect = this;
Ben Murdoche69819b2013-07-17 14:56:49 +01002012 if (!page->focusController()->setFocusedElement(this, doc->frame(), direction))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002013 return;
2014 }
2015
2016 // Setting the focused node above might have invalidated the layout due to scripts.
2017 doc->updateLayoutIgnorePendingStylesheets();
2018
2019 if (!isFocusable()) {
2020 ensureElementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
2021 return;
2022 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002023
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002024 cancelFocusAppearanceUpdate();
2025 updateFocusAppearance(restorePreviousSelection);
2026}
2027
2028void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
2029{
2030 if (isRootEditableElement()) {
2031 Frame* frame = document()->frame();
2032 if (!frame)
2033 return;
Ben Murdoch591b9582013-07-10 11:41:44 +01002034
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002035 // When focusing an editable element in an iframe, don't reset the selection if it already contains a selection.
2036 if (this == frame->selection()->rootEditableElement())
2037 return;
2038
2039 // FIXME: We should restore the previous selection if there is one.
2040 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
Ben Murdoch591b9582013-07-10 11:41:44 +01002041
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002042 if (frame->selection()->shouldChangeSelection(newSelection)) {
2043 frame->selection()->setSelection(newSelection);
2044 frame->selection()->revealSelection();
2045 }
2046 } else if (renderer() && !renderer()->isWidget())
2047 renderer()->scrollRectToVisible(boundingBox());
2048}
2049
2050void Element::blur()
2051{
2052 cancelFocusAppearanceUpdate();
Ben Murdoche69819b2013-07-17 14:56:49 +01002053 if (treeScope()->adjustedFocusedElement() == this) {
2054 Document* doc = document();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002055 if (doc->frame())
Ben Murdoche69819b2013-07-17 14:56:49 +01002056 doc->frame()->page()->focusController()->setFocusedElement(0, doc->frame());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002057 else
Ben Murdoche69819b2013-07-17 14:56:49 +01002058 doc->setFocusedElement(0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002059 }
2060}
2061
2062String Element::innerText()
2063{
2064 // We need to update layout, since plainText uses line boxes in the render tree.
2065 document()->updateLayoutIgnorePendingStylesheets();
2066
2067 if (!renderer())
2068 return textContent(true);
2069
2070 return plainText(rangeOfContents(const_cast<Element*>(this)).get());
2071}
2072
2073String Element::outerText()
2074{
2075 // Getting outerText is the same as getting innerText, only
2076 // setting is different. You would think this should get the plain
2077 // text for the outer range, but this is wrong, <br> for instance
2078 // would return different values for inner and outer text by such
2079 // a rule, but it doesn't in WinIE, and we want to match that.
2080 return innerText();
2081}
2082
Ben Murdoch591b9582013-07-10 11:41:44 +01002083String Element::textFromChildren()
2084{
2085 Text* firstTextNode = 0;
2086 bool foundMultipleTextNodes = false;
2087 unsigned totalLength = 0;
2088
2089 for (Node* child = firstChild(); child; child = child->nextSibling()) {
2090 if (!child->isTextNode())
2091 continue;
2092 Text* text = toText(child);
2093 if (!firstTextNode)
2094 firstTextNode = text;
2095 else
2096 foundMultipleTextNodes = true;
2097 unsigned length = text->data().length();
2098 if (length > std::numeric_limits<unsigned>::max() - totalLength)
2099 return emptyString();
2100 totalLength += length;
2101 }
2102
2103 if (!firstTextNode)
2104 return emptyString();
2105
2106 if (firstTextNode && !foundMultipleTextNodes) {
2107 firstTextNode->atomize();
2108 return firstTextNode->data();
2109 }
2110
2111 StringBuilder content;
2112 content.reserveCapacity(totalLength);
2113 for (Node* child = firstTextNode; child; child = child->nextSibling()) {
2114 if (!child->isTextNode())
2115 continue;
2116 content.append(toText(child)->data());
2117 }
2118
2119 ASSERT(content.length() == totalLength);
2120 return content.toString();
2121}
2122
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002123const AtomicString& Element::pseudo() const
2124{
2125 return getAttribute(pseudoAttr);
2126}
2127
2128void Element::setPseudo(const AtomicString& value)
2129{
2130 setAttribute(pseudoAttr, value);
2131}
2132
2133LayoutSize Element::minimumSizeForResizing() const
2134{
2135 return hasRareData() ? elementRareData()->minimumSizeForResizing() : defaultMinimumSizeForResizing();
2136}
2137
2138void Element::setMinimumSizeForResizing(const LayoutSize& size)
2139{
2140 if (!hasRareData() && size == defaultMinimumSizeForResizing())
2141 return;
2142 ensureElementRareData()->setMinimumSizeForResizing(size);
2143}
2144
2145RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
2146{
2147 if (PseudoElement* element = pseudoElement(pseudoElementSpecifier))
2148 return element->computedStyle();
2149
2150 // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
2151 // properties, which are only known by the renderer because it did the layout, will be correct and so that the
2152 // values returned for the ":selection" pseudo-element will be correct.
2153 if (RenderStyle* usedStyle = renderStyle()) {
2154 if (pseudoElementSpecifier) {
2155 RenderStyle* cachedPseudoStyle = usedStyle->getCachedPseudoStyle(pseudoElementSpecifier);
2156 return cachedPseudoStyle ? cachedPseudoStyle : usedStyle;
2157 } else
2158 return usedStyle;
2159 }
2160
2161 if (!attached())
2162 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
2163 // document tree and figure out when to destroy the computed style for such elements.
2164 return 0;
2165
2166 ElementRareData* data = ensureElementRareData();
2167 if (!data->computedStyle())
2168 data->setComputedStyle(document()->styleForElementIgnoringPendingStylesheets(this));
2169 return pseudoElementSpecifier ? data->computedStyle()->getCachedPseudoStyle(pseudoElementSpecifier) : data->computedStyle();
2170}
2171
2172void Element::setStyleAffectedByEmpty()
2173{
2174 ensureElementRareData()->setStyleAffectedByEmpty(true);
2175}
2176
2177void Element::setChildrenAffectedByHover(bool value)
2178{
2179 if (value || hasRareData())
2180 ensureElementRareData()->setChildrenAffectedByHover(value);
2181}
2182
2183void Element::setChildrenAffectedByActive(bool value)
2184{
2185 if (value || hasRareData())
2186 ensureElementRareData()->setChildrenAffectedByActive(value);
2187}
2188
2189void Element::setChildrenAffectedByDrag(bool value)
2190{
2191 if (value || hasRareData())
2192 ensureElementRareData()->setChildrenAffectedByDrag(value);
2193}
2194
2195void Element::setChildrenAffectedByFirstChildRules()
2196{
2197 ensureElementRareData()->setChildrenAffectedByFirstChildRules(true);
2198}
2199
2200void Element::setChildrenAffectedByLastChildRules()
2201{
2202 ensureElementRareData()->setChildrenAffectedByLastChildRules(true);
2203}
2204
2205void Element::setChildrenAffectedByDirectAdjacentRules()
2206{
2207 ensureElementRareData()->setChildrenAffectedByDirectAdjacentRules(true);
2208}
2209
2210void Element::setChildrenAffectedByForwardPositionalRules()
2211{
2212 ensureElementRareData()->setChildrenAffectedByForwardPositionalRules(true);
2213}
2214
2215void Element::setChildrenAffectedByBackwardPositionalRules()
2216{
2217 ensureElementRareData()->setChildrenAffectedByBackwardPositionalRules(true);
2218}
2219
2220void Element::setChildIndex(unsigned index)
2221{
2222 ElementRareData* rareData = ensureElementRareData();
2223 if (RenderStyle* style = renderStyle())
2224 style->setUnique();
2225 rareData->setChildIndex(index);
2226}
2227
2228bool Element::hasFlagsSetDuringStylingOfChildren() const
2229{
2230 if (!hasRareData())
2231 return false;
2232 return rareDataChildrenAffectedByHover()
2233 || rareDataChildrenAffectedByActive()
2234 || rareDataChildrenAffectedByDrag()
2235 || rareDataChildrenAffectedByFirstChildRules()
2236 || rareDataChildrenAffectedByLastChildRules()
2237 || rareDataChildrenAffectedByDirectAdjacentRules()
2238 || rareDataChildrenAffectedByForwardPositionalRules()
2239 || rareDataChildrenAffectedByBackwardPositionalRules();
2240}
2241
2242bool Element::rareDataStyleAffectedByEmpty() const
2243{
2244 ASSERT(hasRareData());
2245 return elementRareData()->styleAffectedByEmpty();
2246}
2247
2248bool Element::rareDataChildrenAffectedByHover() const
2249{
2250 ASSERT(hasRareData());
2251 return elementRareData()->childrenAffectedByHover();
2252}
2253
2254bool Element::rareDataChildrenAffectedByActive() const
2255{
2256 ASSERT(hasRareData());
2257 return elementRareData()->childrenAffectedByActive();
2258}
2259
2260bool Element::rareDataChildrenAffectedByDrag() const
2261{
2262 ASSERT(hasRareData());
2263 return elementRareData()->childrenAffectedByDrag();
2264}
2265
2266bool Element::rareDataChildrenAffectedByFirstChildRules() const
2267{
2268 ASSERT(hasRareData());
2269 return elementRareData()->childrenAffectedByFirstChildRules();
2270}
2271
2272bool Element::rareDataChildrenAffectedByLastChildRules() const
2273{
2274 ASSERT(hasRareData());
2275 return elementRareData()->childrenAffectedByLastChildRules();
2276}
2277
2278bool Element::rareDataChildrenAffectedByDirectAdjacentRules() const
2279{
2280 ASSERT(hasRareData());
2281 return elementRareData()->childrenAffectedByDirectAdjacentRules();
2282}
2283
2284bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
2285{
2286 ASSERT(hasRareData());
2287 return elementRareData()->childrenAffectedByForwardPositionalRules();
2288}
2289
2290bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
2291{
2292 ASSERT(hasRareData());
2293 return elementRareData()->childrenAffectedByBackwardPositionalRules();
2294}
2295
2296unsigned Element::rareDataChildIndex() const
2297{
2298 ASSERT(hasRareData());
2299 return elementRareData()->childIndex();
2300}
2301
2302void Element::setIsInCanvasSubtree(bool isInCanvasSubtree)
2303{
2304 ensureElementRareData()->setIsInCanvasSubtree(isInCanvasSubtree);
2305}
2306
2307bool Element::isInCanvasSubtree() const
2308{
2309 return hasRareData() && elementRareData()->isInCanvasSubtree();
2310}
2311
Ben Murdoch591b9582013-07-10 11:41:44 +01002312void Element::setIsInsideRegion(bool value)
2313{
2314 if (value == isInsideRegion())
2315 return;
2316
2317 ensureElementRareData()->setIsInsideRegion(value);
2318}
2319
2320bool Element::isInsideRegion() const
2321{
2322 return hasRareData() ? elementRareData()->isInsideRegion() : false;
2323}
2324
2325void Element::setRegionOversetState(RegionOversetState state)
2326{
2327 ensureElementRareData()->setRegionOversetState(state);
2328}
2329
2330RegionOversetState Element::regionOversetState() const
2331{
2332 return hasRareData() ? elementRareData()->regionOversetState() : RegionUndefined;
2333}
2334
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002335AtomicString Element::computeInheritedLanguage() const
2336{
2337 const Node* n = this;
2338 AtomicString value;
2339 // The language property is inherited, so we iterate over the parents to find the first language.
2340 do {
2341 if (n->isElementNode()) {
2342 if (const ElementData* elementData = toElement(n)->elementData()) {
2343 // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7
2344 if (const Attribute* attribute = elementData->getAttributeItem(XMLNames::langAttr))
2345 value = attribute->value();
2346 else if (const Attribute* attribute = elementData->getAttributeItem(HTMLNames::langAttr))
2347 value = attribute->value();
2348 }
2349 } else if (n->isDocumentNode()) {
2350 // checking the MIME content-language
2351 value = toDocument(n)->contentLanguage();
2352 }
2353
2354 n = n->parentNode();
2355 } while (n && value.isNull());
2356
2357 return value;
2358}
2359
2360Locale& Element::locale() const
2361{
2362 return document()->getCachedLocale(computeInheritedLanguage());
2363}
2364
2365void Element::cancelFocusAppearanceUpdate()
2366{
2367 if (hasRareData())
2368 elementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
Ben Murdoch7757ec22013-07-23 11:17:36 +01002369 if (document()->focusedElement() == this)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002370 document()->cancelFocusAppearanceUpdate();
2371}
2372
2373void Element::normalizeAttributes()
2374{
2375 if (!hasAttributes())
2376 return;
2377 for (unsigned i = 0; i < attributeCount(); ++i) {
2378 if (RefPtr<Attr> attr = attrIfExists(attributeItem(i)->name()))
2379 attr->normalize();
2380 }
2381}
2382
2383void Element::updatePseudoElement(PseudoId pseudoId, StyleChange change)
2384{
2385 PseudoElement* element = pseudoElement(pseudoId);
2386 if (element && (needsStyleRecalc() || shouldRecalcStyle(change, element))) {
2387 // PseudoElement styles hang off their parent element's style so if we needed
2388 // a style recalc we should Force one on the pseudo.
2389 element->recalcStyle(needsStyleRecalc() ? Force : change);
2390
2391 // Wait until our parent is not displayed or pseudoElementRendererIsNeeded
2392 // is false, otherwise we could continously create and destroy PseudoElements
2393 // when RenderObject::isChildAllowed on our parent returns false for the
2394 // PseudoElement's renderer for each style recalc.
2395 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01002396 elementRareData()->setPseudoElement(pseudoId, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002397 } else if (change >= Inherit || needsStyleRecalc())
2398 createPseudoElementIfNeeded(pseudoId);
2399}
2400
2401void Element::createPseudoElementIfNeeded(PseudoId pseudoId)
2402{
Ben Murdoche69819b2013-07-17 14:56:49 +01002403 if ((pseudoId == BEFORE || pseudoId == AFTER) && !document()->styleSheetCollection()->usesBeforeAfterRules())
2404 return;
2405
2406 if (pseudoId == BACKDROP && !isInTopLayer())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002407 return;
2408
2409 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
2410 return;
2411
2412 if (!renderer()->canHaveGeneratedChildren())
2413 return;
2414
2415 ASSERT(!isPseudoElement());
2416 RefPtr<PseudoElement> element = PseudoElement::create(this, pseudoId);
Ben Murdoche69819b2013-07-17 14:56:49 +01002417 if (pseudoId == BACKDROP)
2418 document()->addToTopLayer(element.get(), this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002419 element->attach();
Ben Murdoche69819b2013-07-17 14:56:49 +01002420
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01002421 ensureElementRareData()->setPseudoElement(pseudoId, element.release());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002422}
2423
2424PseudoElement* Element::pseudoElement(PseudoId pseudoId) const
2425{
2426 return hasRareData() ? elementRareData()->pseudoElement(pseudoId) : 0;
2427}
2428
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002429RenderObject* Element::pseudoElementRenderer(PseudoId pseudoId) const
2430{
2431 if (PseudoElement* element = pseudoElement(pseudoId))
2432 return element->renderer();
2433 return 0;
2434}
2435
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002436bool Element::webkitMatchesSelector(const String& selector, ExceptionCode& ec)
2437{
2438 if (selector.isEmpty()) {
Ben Murdoche69819b2013-07-17 14:56:49 +01002439 ec = SyntaxError;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002440 return false;
2441 }
2442
2443 SelectorQuery* selectorQuery = document()->selectorQueryCache()->add(selector, document(), ec);
2444 if (!selectorQuery)
2445 return false;
2446 return selectorQuery->matches(this);
2447}
2448
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002449DOMTokenList* Element::classList()
2450{
2451 ElementRareData* data = ensureElementRareData();
2452 if (!data->classList())
2453 data->setClassList(ClassList::create(this));
2454 return data->classList();
2455}
2456
2457DOMStringMap* Element::dataset()
2458{
2459 ElementRareData* data = ensureElementRareData();
2460 if (!data->dataset())
2461 data->setDataset(DatasetDOMStringMap::create(this));
2462 return data->dataset();
2463}
2464
2465KURL Element::getURLAttribute(const QualifiedName& name) const
2466{
2467#if !ASSERT_DISABLED
2468 if (elementData()) {
2469 if (const Attribute* attribute = getAttributeItem(name))
2470 ASSERT(isURLAttribute(*attribute));
2471 }
2472#endif
2473 return document()->completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
2474}
2475
2476KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
2477{
2478#if !ASSERT_DISABLED
2479 if (elementData()) {
2480 if (const Attribute* attribute = getAttributeItem(name))
2481 ASSERT(isURLAttribute(*attribute));
2482 }
2483#endif
2484 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
2485 if (value.isEmpty())
2486 return KURL();
2487 return document()->completeURL(value);
2488}
2489
2490int Element::getIntegralAttribute(const QualifiedName& attributeName) const
2491{
2492 return getAttribute(attributeName).string().toInt();
2493}
2494
2495void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
2496{
2497 // FIXME: Need an AtomicString version of String::number.
2498 setAttribute(attributeName, String::number(value));
2499}
2500
2501unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
2502{
2503 return getAttribute(attributeName).string().toUInt();
2504}
2505
2506void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
2507{
2508 // FIXME: Need an AtomicString version of String::number.
2509 setAttribute(attributeName, String::number(value));
2510}
2511
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002512bool Element::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
2513{
2514 // Only create renderers for SVG elements whose parents are SVG elements, or for proper <svg xmlns="svgNS"> subdocuments.
2515 if (childContext.node()->isSVGElement())
2516 return childContext.node()->hasTagName(SVGNames::svgTag) || isSVGElement();
2517
2518 return ContainerNode::childShouldCreateRenderer(childContext);
2519}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002520
2521void Element::webkitRequestFullscreen()
2522{
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01002523 FullscreenController::from(document())->requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, FullscreenController::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002524}
2525
2526void Element::webkitRequestFullScreen(unsigned short flags)
2527{
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01002528 FullscreenController::from(document())->requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), FullscreenController::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002529}
2530
2531bool Element::containsFullScreenElement() const
2532{
2533 return hasRareData() && elementRareData()->containsFullScreenElement();
2534}
2535
2536void Element::setContainsFullScreenElement(bool flag)
2537{
2538 ensureElementRareData()->setContainsFullScreenElement(flag);
Ben Murdoche69819b2013-07-17 14:56:49 +01002539 setNeedsStyleRecalc(SubtreeStyleChange);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002540}
2541
2542static Element* parentCrossingFrameBoundaries(Element* element)
2543{
2544 ASSERT(element);
2545 return element->parentElement() ? element->parentElement() : element->document()->ownerElement();
2546}
2547
2548void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool flag)
2549{
2550 Element* element = this;
2551 while ((element = parentCrossingFrameBoundaries(element)))
2552 element->setContainsFullScreenElement(flag);
2553}
2554
2555bool Element::isInTopLayer() const
2556{
2557 return hasRareData() && elementRareData()->isInTopLayer();
2558}
2559
2560void Element::setIsInTopLayer(bool inTopLayer)
2561{
2562 if (isInTopLayer() == inTopLayer)
2563 return;
2564 ensureElementRareData()->setIsInTopLayer(inTopLayer);
2565
2566 // We must ensure a reattach occurs so the renderer is inserted in the correct sibling order under RenderView according to its
2567 // top layer position, or in its usual place if not in the top layer.
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002568 lazyReattachIfAttached();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002569}
2570
2571void Element::webkitRequestPointerLock()
2572{
2573 if (document()->page())
2574 document()->page()->pointerLockController()->requestPointerLock(this);
2575}
2576
2577SpellcheckAttributeState Element::spellcheckAttributeState() const
2578{
2579 const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
2580 if (value == nullAtom)
2581 return SpellcheckAttributeDefault;
2582 if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
2583 return SpellcheckAttributeTrue;
2584 if (equalIgnoringCase(value, "false"))
2585 return SpellcheckAttributeFalse;
2586
2587 return SpellcheckAttributeDefault;
2588}
2589
2590bool Element::isSpellCheckingEnabled() const
2591{
2592 for (const Element* element = this; element; element = element->parentOrShadowHostElement()) {
2593 switch (element->spellcheckAttributeState()) {
2594 case SpellcheckAttributeTrue:
2595 return true;
2596 case SpellcheckAttributeFalse:
2597 return false;
2598 case SpellcheckAttributeDefault:
2599 break;
2600 }
2601 }
2602
2603 return true;
2604}
2605
2606RenderRegion* Element::renderRegion() const
2607{
2608 if (renderer() && renderer()->isRenderRegion())
2609 return toRenderRegion(renderer());
2610
2611 return 0;
2612}
2613
Ben Murdoch591b9582013-07-10 11:41:44 +01002614bool Element::shouldMoveToFlowThread(RenderStyle* styleToUse) const
2615{
2616 ASSERT(styleToUse);
2617
2618 if (FullscreenController::isActiveFullScreenElement(this))
2619 return false;
2620
2621 if (isInShadowTree())
2622 return false;
2623
2624 if (styleToUse->flowThread().isEmpty())
2625 return false;
2626
2627 return !isRegisteredWithNamedFlow();
2628}
2629
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002630const AtomicString& Element::webkitRegionOverset() const
2631{
2632 document()->updateLayoutIgnorePendingStylesheets();
2633
2634 DEFINE_STATIC_LOCAL(AtomicString, undefinedState, ("undefined", AtomicString::ConstructFromLiteral));
2635 if (!RuntimeEnabledFeatures::cssRegionsEnabled() || !renderRegion())
2636 return undefinedState;
2637
Ben Murdoch591b9582013-07-10 11:41:44 +01002638 switch (renderRegion()->regionOversetState()) {
2639 case RegionFit: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002640 DEFINE_STATIC_LOCAL(AtomicString, fitState, ("fit", AtomicString::ConstructFromLiteral));
2641 return fitState;
2642 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002643 case RegionEmpty: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002644 DEFINE_STATIC_LOCAL(AtomicString, emptyState, ("empty", AtomicString::ConstructFromLiteral));
2645 return emptyState;
2646 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002647 case RegionOverset: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002648 DEFINE_STATIC_LOCAL(AtomicString, overflowState, ("overset", AtomicString::ConstructFromLiteral));
2649 return overflowState;
2650 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002651 case RegionUndefined:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002652 return undefinedState;
2653 }
2654
2655 ASSERT_NOT_REACHED();
2656 return undefinedState;
2657}
2658
2659Vector<RefPtr<Range> > Element::webkitGetRegionFlowRanges() const
2660{
2661 document()->updateLayoutIgnorePendingStylesheets();
2662
2663 Vector<RefPtr<Range> > rangeObjects;
2664 if (RuntimeEnabledFeatures::cssRegionsEnabled() && renderer() && renderer()->isRenderRegion()) {
2665 RenderRegion* region = toRenderRegion(renderer());
2666 if (region->isValid())
2667 region->getRanges(rangeObjects);
2668 }
2669
2670 return rangeObjects;
2671}
2672
2673#ifndef NDEBUG
2674bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
2675{
2676 if (name == HTMLNames::styleAttr)
2677 return false;
2678
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002679 if (isSVGElement())
2680 return !static_cast<const SVGElement*>(this)->isAnimatableAttribute(name);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002681
2682 return true;
2683}
2684#endif
2685
2686#ifdef DUMP_NODE_STATISTICS
2687bool Element::hasNamedNodeMap() const
2688{
2689 return hasRareData() && elementRareData()->attributeMap();
2690}
2691#endif
2692
2693inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName)
2694{
2695 if (!inDocument() || isInShadowTree())
2696 return;
2697
2698 if (oldName == newName)
2699 return;
2700
2701 if (shouldRegisterAsNamedItem())
2702 updateNamedItemRegistration(oldName, newName);
2703}
2704
2705inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
2706{
2707 if (!isInTreeScope())
2708 return;
2709
2710 if (oldId == newId)
2711 return;
2712
2713 updateId(treeScope(), oldId, newId);
2714}
2715
2716inline void Element::updateId(TreeScope* scope, const AtomicString& oldId, const AtomicString& newId)
2717{
2718 ASSERT(isInTreeScope());
2719 ASSERT(oldId != newId);
2720
2721 if (!oldId.isEmpty())
2722 scope->removeElementById(oldId, this);
2723 if (!newId.isEmpty())
2724 scope->addElementById(newId, this);
2725
2726 if (shouldRegisterAsExtraNamedItem())
2727 updateExtraNamedItemRegistration(oldId, newId);
2728}
2729
2730void Element::updateLabel(TreeScope* scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
2731{
2732 ASSERT(hasTagName(labelTag));
2733
2734 if (!inDocument())
2735 return;
2736
2737 if (oldForAttributeValue == newForAttributeValue)
2738 return;
2739
2740 if (!oldForAttributeValue.isEmpty())
Ben Murdoche69819b2013-07-17 14:56:49 +01002741 scope->removeLabel(oldForAttributeValue, toHTMLLabelElement(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002742 if (!newForAttributeValue.isEmpty())
Ben Murdoche69819b2013-07-17 14:56:49 +01002743 scope->addLabel(newForAttributeValue, toHTMLLabelElement(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002744}
2745
Ben Murdoch7757ec22013-07-23 11:17:36 +01002746static bool hasSelectorForAttribute(Document* document, const AtomicString& localName)
2747{
2748 return document->styleResolver() && document->styleResolver()->ruleFeatureSet().hasSelectorForAttribute(localName);
2749}
2750
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002751void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
2752{
2753 if (isIdAttributeName(name))
2754 updateId(oldValue, newValue);
2755 else if (name == HTMLNames::nameAttr)
2756 updateName(oldValue, newValue);
2757 else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
2758 TreeScope* scope = treeScope();
2759 if (scope->shouldCacheLabelsByForAttribute())
2760 updateLabel(scope, oldValue, newValue);
2761 }
2762
2763 if (oldValue != newValue) {
Ben Murdoch7757ec22013-07-23 11:17:36 +01002764 if (attached() && hasSelectorForAttribute(document(), name.localName()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002765 setNeedsStyleRecalc();
Ben Murdoche69819b2013-07-17 14:56:49 +01002766
2767 if (isUpgradedCustomElement())
Ben Murdoch83750172013-07-24 10:36:59 +01002768 CustomElement::attributeDidChange(this, name.localName(), oldValue, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002769 }
2770
2771 if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(this, name))
2772 recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue));
2773
2774 InspectorInstrumentation::willModifyDOMAttr(document(), this, oldValue, newValue);
2775}
2776
2777void Element::didAddAttribute(const QualifiedName& name, const AtomicString& value)
2778{
2779 attributeChanged(name, value);
2780 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value);
2781 dispatchSubtreeModifiedEvent();
2782}
2783
2784void Element::didModifyAttribute(const QualifiedName& name, const AtomicString& value)
2785{
2786 attributeChanged(name, value);
2787 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value);
2788 // Do not dispatch a DOMSubtreeModified event here; see bug 81141.
2789}
2790
2791void Element::didRemoveAttribute(const QualifiedName& name)
2792{
2793 attributeChanged(name, nullAtom);
2794 InspectorInstrumentation::didRemoveDOMAttr(document(), this, name.localName());
2795 dispatchSubtreeModifiedEvent();
2796}
2797
Ben Murdoche69819b2013-07-17 14:56:49 +01002798void Element::didMoveToNewDocument(Document* oldDocument)
2799{
2800 Node::didMoveToNewDocument(oldDocument);
2801
2802 // If the documents differ by quirks mode then they differ by case sensitivity
2803 // for class and id names so we need to go through the attribute change logic
2804 // to pick up the new casing in the ElementData.
2805 if (oldDocument->inQuirksMode() != document()->inQuirksMode()) {
2806 if (hasID())
2807 setIdAttribute(getIdAttribute());
2808 if (hasClass())
2809 setAttribute(HTMLNames::classAttr, getClassAttribute());
2810 }
2811}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002812
2813void Element::updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName)
2814{
2815 if (!document()->isHTMLDocument())
2816 return;
2817
2818 if (!oldName.isEmpty())
2819 toHTMLDocument(document())->removeNamedItem(oldName);
2820
2821 if (!newName.isEmpty())
2822 toHTMLDocument(document())->addNamedItem(newName);
2823}
2824
2825void Element::updateExtraNamedItemRegistration(const AtomicString& oldId, const AtomicString& newId)
2826{
2827 if (!document()->isHTMLDocument())
2828 return;
2829
2830 if (!oldId.isEmpty())
2831 toHTMLDocument(document())->removeExtraNamedItem(oldId);
2832
2833 if (!newId.isEmpty())
2834 toHTMLDocument(document())->addExtraNamedItem(newId);
2835}
2836
2837PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
2838{
2839 if (HTMLCollection* collection = cachedHTMLCollection(type))
2840 return collection;
2841
2842 RefPtr<HTMLCollection> collection;
2843 if (type == TableRows) {
2844 ASSERT(hasTagName(tableTag));
2845 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
2846 } else if (type == SelectOptions) {
2847 ASSERT(hasTagName(selectTag));
2848 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
2849 } else if (type == FormControls) {
2850 ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
2851 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
2852 }
2853 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLCollection>(this, type);
2854}
2855
Ben Murdoch591b9582013-07-10 11:41:44 +01002856static void scheduleLayerUpdateCallback(Node* node)
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002857{
Ben Murdoche69819b2013-07-17 14:56:49 +01002858 // Notify the renderer even is the styles are identical since it may need to
2859 // create or destroy a RenderLayer.
2860 node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002861}
2862
Ben Murdoch591b9582013-07-10 11:41:44 +01002863void Element::scheduleLayerUpdate()
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002864{
2865 if (postAttachCallbacksAreSuspended())
Ben Murdoch591b9582013-07-10 11:41:44 +01002866 queuePostAttachCallback(scheduleLayerUpdateCallback, this);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002867 else
Ben Murdoche69819b2013-07-17 14:56:49 +01002868 scheduleLayerUpdateCallback(this);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002869}
2870
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002871HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
2872{
2873 return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0;
2874}
2875
2876IntSize Element::savedLayerScrollOffset() const
2877{
2878 return hasRareData() ? elementRareData()->savedLayerScrollOffset() : IntSize();
2879}
2880
2881void Element::setSavedLayerScrollOffset(const IntSize& size)
2882{
2883 if (size.isZero() && !hasRareData())
2884 return;
2885 ensureElementRareData()->setSavedLayerScrollOffset(size);
2886}
2887
2888PassRefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
2889{
2890 if (AttrNodeList* attrNodeList = attrNodeListForElement(this))
2891 return findAttrNodeInList(attrNodeList, name);
2892 return 0;
2893}
2894
2895PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name)
2896{
2897 AttrNodeList* attrNodeList = ensureAttrNodeListForElement(this);
2898 RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
2899 if (!attrNode) {
2900 attrNode = Attr::create(this, name);
2901 treeScope()->adoptIfNeeded(attrNode.get());
2902 attrNodeList->append(attrNode);
2903 }
2904 return attrNode.release();
2905}
2906
2907void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value)
2908{
2909 ASSERT(hasSyntheticAttrChildNodes());
2910 attrNode->detachFromElementWithValue(value);
2911
2912 AttrNodeList* attrNodeList = attrNodeListForElement(this);
2913 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
2914 if (attrNodeList->at(i)->qualifiedName() == attrNode->qualifiedName()) {
2915 attrNodeList->remove(i);
2916 if (attrNodeList->isEmpty())
2917 removeAttrNodeListForElement(this);
2918 return;
2919 }
2920 }
2921 ASSERT_NOT_REACHED();
2922}
2923
2924void Element::detachAllAttrNodesFromElement()
2925{
2926 AttrNodeList* attrNodeList = attrNodeListForElement(this);
2927 ASSERT(attrNodeList);
2928
2929 for (unsigned i = 0; i < attributeCount(); ++i) {
2930 const Attribute* attribute = attributeItem(i);
2931 if (RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, attribute->name()))
2932 attrNode->detachFromElementWithValue(attribute->value());
2933 }
2934
2935 removeAttrNodeListForElement(this);
2936}
2937
2938void Element::willRecalcStyle(StyleChange)
2939{
2940 ASSERT(hasCustomStyleCallbacks());
2941}
2942
2943void Element::didRecalcStyle(StyleChange)
2944{
2945 ASSERT(hasCustomStyleCallbacks());
2946}
2947
2948
2949PassRefPtr<RenderStyle> Element::customStyleForRenderer()
2950{
2951 ASSERT(hasCustomStyleCallbacks());
2952 return 0;
2953}
2954
2955void Element::cloneAttributesFromElement(const Element& other)
2956{
2957 if (hasSyntheticAttrChildNodes())
2958 detachAllAttrNodesFromElement();
2959
2960 other.synchronizeAllAttributes();
2961 if (!other.m_elementData) {
2962 m_elementData.clear();
2963 return;
2964 }
2965
2966 const AtomicString& oldID = getIdAttribute();
2967 const AtomicString& newID = other.getIdAttribute();
2968
2969 if (!oldID.isNull() || !newID.isNull())
2970 updateId(oldID, newID);
2971
2972 const AtomicString& oldName = getNameAttribute();
2973 const AtomicString& newName = other.getNameAttribute();
2974
2975 if (!oldName.isNull() || !newName.isNull())
2976 updateName(oldName, newName);
2977
Ben Murdoche69819b2013-07-17 14:56:49 +01002978 // Quirks mode makes class and id not case sensitive. We can't share the ElementData
2979 // if the idForStyleResolution and the className need different casing.
2980 bool ownerDocumentsHaveDifferentCaseSensitivity = false;
2981 if (other.hasClass() || other.hasID())
2982 ownerDocumentsHaveDifferentCaseSensitivity = other.document()->inQuirksMode() != document()->inQuirksMode();
2983
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002984 // 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 +01002985 // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes,
2986 // and sharing the data won't result in different case sensitivity of class or id.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002987 if (other.m_elementData->isUnique()
Ben Murdoche69819b2013-07-17 14:56:49 +01002988 && !ownerDocumentsHaveDifferentCaseSensitivity
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002989 && !other.m_elementData->presentationAttributeStyle()
2990 && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper()))
2991 const_cast<Element&>(other).m_elementData = static_cast<const UniqueElementData*>(other.m_elementData.get())->makeShareableCopy();
2992
Ben Murdoche69819b2013-07-17 14:56:49 +01002993 if (!other.m_elementData->isUnique() && !ownerDocumentsHaveDifferentCaseSensitivity)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002994 m_elementData = other.m_elementData;
2995 else
2996 m_elementData = other.m_elementData->makeUniqueCopy();
2997
2998 for (unsigned i = 0; i < m_elementData->length(); ++i) {
2999 const Attribute* attribute = const_cast<const ElementData*>(m_elementData.get())->attributeItem(i);
3000 attributeChangedFromParserOrByCloning(attribute->name(), attribute->value(), ModifiedByCloning);
3001 }
3002}
3003
3004void Element::cloneDataFromElement(const Element& other)
3005{
3006 cloneAttributesFromElement(other);
3007 copyNonAttributePropertiesFromElement(other);
3008}
3009
3010void Element::createUniqueElementData()
3011{
3012 if (!m_elementData)
3013 m_elementData = UniqueElementData::create();
3014 else {
3015 ASSERT(!m_elementData->isUnique());
3016 m_elementData = static_cast<ShareableElementData*>(m_elementData.get())->makeUniqueCopy();
3017 }
3018}
3019
Torne (Richard Coles)81a51572013-05-13 16:52:28 +01003020InputMethodContext* Element::getInputContext()
3021{
3022 return ensureElementRareData()->ensureInputMethodContext(toHTMLElement(this));
3023}
3024
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003025bool Element::hasPendingResources() const
3026{
3027 return hasRareData() && elementRareData()->hasPendingResources();
3028}
3029
3030void Element::setHasPendingResources()
3031{
3032 ensureElementRareData()->setHasPendingResources(true);
3033}
3034
3035void Element::clearHasPendingResources()
3036{
3037 ensureElementRareData()->setHasPendingResources(false);
3038}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003039
Ben Murdoch591b9582013-07-10 11:41:44 +01003040struct PresentationAttributeCacheKey {
3041 PresentationAttributeCacheKey() : tagName(0) { }
Ben Murdoch83750172013-07-24 10:36:59 +01003042 StringImpl* tagName;
Ben Murdoch591b9582013-07-10 11:41:44 +01003043 // Only the values need refcounting.
Ben Murdoch83750172013-07-24 10:36:59 +01003044 Vector<pair<StringImpl*, AtomicString>, 3> attributesAndValues;
Ben Murdoch591b9582013-07-10 11:41:44 +01003045};
3046
3047struct PresentationAttributeCacheEntry {
3048 WTF_MAKE_FAST_ALLOCATED;
3049public:
3050 PresentationAttributeCacheKey key;
3051 RefPtr<StylePropertySet> value;
3052};
3053
3054typedef HashMap<unsigned, OwnPtr<PresentationAttributeCacheEntry>, AlreadyHashed> PresentationAttributeCache;
3055
3056static bool operator!=(const PresentationAttributeCacheKey& a, const PresentationAttributeCacheKey& b)
3057{
3058 if (a.tagName != b.tagName)
3059 return true;
3060 return a.attributesAndValues != b.attributesAndValues;
3061}
3062
3063static PresentationAttributeCache& presentationAttributeCache()
3064{
3065 DEFINE_STATIC_LOCAL(PresentationAttributeCache, cache, ());
3066 return cache;
3067}
3068
3069class PresentationAttributeCacheCleaner {
3070 WTF_MAKE_NONCOPYABLE(PresentationAttributeCacheCleaner); WTF_MAKE_FAST_ALLOCATED;
3071public:
3072 PresentationAttributeCacheCleaner()
3073 : m_hitCount(0)
3074 , m_cleanTimer(this, &PresentationAttributeCacheCleaner::cleanCache)
3075 {
3076 }
3077
3078 void didHitPresentationAttributeCache()
3079 {
3080 if (presentationAttributeCache().size() < minimumPresentationAttributeCacheSizeForCleaning)
3081 return;
3082
3083 m_hitCount++;
3084
3085 if (!m_cleanTimer.isActive())
3086 m_cleanTimer.startOneShot(presentationAttributeCacheCleanTimeInSeconds);
3087 }
3088
3089private:
3090 static const unsigned presentationAttributeCacheCleanTimeInSeconds = 60;
3091 static const int minimumPresentationAttributeCacheSizeForCleaning = 100;
3092 static const unsigned minimumPresentationAttributeCacheHitCountPerMinute = (100 * presentationAttributeCacheCleanTimeInSeconds) / 60;
3093
3094 void cleanCache(Timer<PresentationAttributeCacheCleaner>* timer)
3095 {
3096 ASSERT_UNUSED(timer, timer == &m_cleanTimer);
3097 unsigned hitCount = m_hitCount;
3098 m_hitCount = 0;
3099 if (hitCount > minimumPresentationAttributeCacheHitCountPerMinute)
3100 return;
3101 presentationAttributeCache().clear();
3102 }
3103
3104 unsigned m_hitCount;
3105 Timer<PresentationAttributeCacheCleaner> m_cleanTimer;
3106};
3107
3108static PresentationAttributeCacheCleaner& presentationAttributeCacheCleaner()
3109{
3110 DEFINE_STATIC_LOCAL(PresentationAttributeCacheCleaner, cleaner, ());
3111 return cleaner;
3112}
3113
3114void Element::synchronizeStyleAttributeInternal() const
3115{
3116 ASSERT(isStyledElement());
3117 ASSERT(elementData());
3118 ASSERT(elementData()->m_styleAttributeIsDirty);
3119 elementData()->m_styleAttributeIsDirty = false;
3120 if (const StylePropertySet* inlineStyle = this->inlineStyle())
3121 const_cast<Element*>(this)->setSynchronizedLazyAttribute(styleAttr, inlineStyle->asText());
3122}
3123
3124CSSStyleDeclaration* Element::style()
3125{
3126 if (!isStyledElement())
3127 return 0;
3128 return ensureMutableInlineStyle()->ensureInlineCSSStyleDeclaration(this);
3129}
3130
3131MutableStylePropertySet* Element::ensureMutableInlineStyle()
3132{
3133 ASSERT(isStyledElement());
3134 RefPtr<StylePropertySet>& inlineStyle = ensureUniqueElementData()->m_inlineStyle;
3135 if (!inlineStyle)
3136 inlineStyle = MutableStylePropertySet::create(strictToCSSParserMode(isHTMLElement() && !document()->inQuirksMode()));
3137 else if (!inlineStyle->isMutable())
3138 inlineStyle = inlineStyle->mutableCopy();
3139 ASSERT(inlineStyle->isMutable());
3140 return static_cast<MutableStylePropertySet*>(inlineStyle.get());
3141}
3142
3143PropertySetCSSStyleDeclaration* Element::inlineStyleCSSOMWrapper()
3144{
3145 if (!inlineStyle() || !inlineStyle()->hasCSSOMWrapper())
3146 return 0;
3147 PropertySetCSSStyleDeclaration* cssomWrapper = ensureMutableInlineStyle()->cssStyleDeclaration();
3148 ASSERT(cssomWrapper && cssomWrapper->parentElement() == this);
3149 return cssomWrapper;
3150}
3151
3152inline void Element::setInlineStyleFromString(const AtomicString& newStyleString)
3153{
3154 ASSERT(isStyledElement());
3155 RefPtr<StylePropertySet>& inlineStyle = elementData()->m_inlineStyle;
3156
3157 // Avoid redundant work if we're using shared attribute data with already parsed inline style.
3158 if (inlineStyle && !elementData()->isUnique())
3159 return;
3160
3161 // We reconstruct the property set instead of mutating if there is no CSSOM wrapper.
3162 // This makes wrapperless property sets immutable and so cacheable.
3163 if (inlineStyle && !inlineStyle->isMutable())
3164 inlineStyle.clear();
3165
3166 if (!inlineStyle) {
3167 inlineStyle = CSSParser::parseInlineStyleDeclaration(newStyleString, this);
3168 } else {
3169 ASSERT(inlineStyle->isMutable());
3170 static_pointer_cast<MutableStylePropertySet>(inlineStyle)->parseDeclaration(newStyleString, document()->elementSheet()->contents());
3171 }
3172}
3173
3174void Element::styleAttributeChanged(const AtomicString& newStyleString, AttributeModificationReason modificationReason)
3175{
3176 ASSERT(isStyledElement());
3177 WTF::OrdinalNumber startLineNumber = WTF::OrdinalNumber::beforeFirst();
3178 if (document() && document()->scriptableDocumentParser() && !document()->isInDocumentWrite())
3179 startLineNumber = document()->scriptableDocumentParser()->lineNumber();
3180
3181 if (newStyleString.isNull()) {
3182 if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
3183 cssomWrapper->clearParentElement();
3184 ensureUniqueElementData()->m_inlineStyle.clear();
3185 } else if (modificationReason == ModifiedByCloning || document()->contentSecurityPolicy()->allowInlineStyle(document()->url(), startLineNumber)) {
3186 setInlineStyleFromString(newStyleString);
3187 }
3188
3189 elementData()->m_styleAttributeIsDirty = false;
3190
Ben Murdoche69819b2013-07-17 14:56:49 +01003191 setNeedsStyleRecalc(LocalStyleChange);
Ben Murdoch591b9582013-07-10 11:41:44 +01003192 InspectorInstrumentation::didInvalidateStyleAttr(document(), this);
3193}
3194
3195void Element::inlineStyleChanged()
3196{
3197 ASSERT(isStyledElement());
Ben Murdoche69819b2013-07-17 14:56:49 +01003198 setNeedsStyleRecalc(LocalStyleChange);
Ben Murdoch591b9582013-07-10 11:41:44 +01003199 ASSERT(elementData());
3200 elementData()->m_styleAttributeIsDirty = true;
3201 InspectorInstrumentation::didInvalidateStyleAttr(document(), this);
3202}
3203
3204bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
3205{
3206 ASSERT(isStyledElement());
3207 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
3208 inlineStyleChanged();
3209 return true;
3210}
3211
3212bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
3213{
3214 ASSERT(isStyledElement());
3215 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
3216 inlineStyleChanged();
3217 return true;
3218}
3219
3220bool Element::setInlineStyleProperty(CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit, bool important)
3221{
3222 ASSERT(isStyledElement());
3223 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createValue(value, unit), important);
3224 inlineStyleChanged();
3225 return true;
3226}
3227
3228bool Element::setInlineStyleProperty(CSSPropertyID propertyID, const String& value, bool important)
3229{
3230 ASSERT(isStyledElement());
3231 bool changes = ensureMutableInlineStyle()->setProperty(propertyID, value, important, document()->elementSheet()->contents());
3232 if (changes)
3233 inlineStyleChanged();
3234 return changes;
3235}
3236
3237bool Element::removeInlineStyleProperty(CSSPropertyID propertyID)
3238{
3239 ASSERT(isStyledElement());
3240 if (!inlineStyle())
3241 return false;
3242 bool changes = ensureMutableInlineStyle()->removeProperty(propertyID);
3243 if (changes)
3244 inlineStyleChanged();
3245 return changes;
3246}
3247
3248void Element::removeAllInlineStyleProperties()
3249{
3250 ASSERT(isStyledElement());
3251 if (!inlineStyle() || inlineStyle()->isEmpty())
3252 return;
3253 ensureMutableInlineStyle()->clear();
3254 inlineStyleChanged();
3255}
3256
3257void Element::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
3258{
3259 ASSERT(isStyledElement());
3260 if (const StylePropertySet* inlineStyle = elementData() ? elementData()->inlineStyle() : 0)
3261 inlineStyle->addSubresourceStyleURLs(urls, document()->elementSheet()->contents());
3262}
3263
Ben Murdoch83750172013-07-24 10:36:59 +01003264static inline bool attributeNameSort(const pair<StringImpl*, AtomicString>& p1, const pair<StringImpl*, AtomicString>& p2)
Ben Murdoch591b9582013-07-10 11:41:44 +01003265{
3266 // Sort based on the attribute name pointers. It doesn't matter what the order is as long as it is always the same.
3267 return p1.first < p2.first;
3268}
3269
3270void Element::makePresentationAttributeCacheKey(PresentationAttributeCacheKey& result) const
3271{
3272 ASSERT(isStyledElement());
3273 // FIXME: Enable for SVG.
3274 if (namespaceURI() != xhtmlNamespaceURI)
3275 return;
3276 // Interpretation of the size attributes on <input> depends on the type attribute.
3277 if (hasTagName(inputTag))
3278 return;
3279 unsigned size = attributeCount();
3280 for (unsigned i = 0; i < size; ++i) {
3281 const Attribute* attribute = attributeItem(i);
3282 if (!isPresentationAttribute(attribute->name()))
3283 continue;
3284 if (!attribute->namespaceURI().isNull())
3285 return;
3286 // FIXME: Background URL may depend on the base URL and can't be shared. Disallow caching.
3287 if (attribute->name() == backgroundAttr)
3288 return;
3289 result.attributesAndValues.append(std::make_pair(attribute->localName().impl(), attribute->value()));
3290 }
3291 if (result.attributesAndValues.isEmpty())
3292 return;
3293 // Attribute order doesn't matter. Sort for easy equality comparison.
3294 std::sort(result.attributesAndValues.begin(), result.attributesAndValues.end(), attributeNameSort);
3295 // The cache key is non-null when the tagName is set.
3296 result.tagName = localName().impl();
3297}
3298
3299static unsigned computePresentationAttributeCacheHash(const PresentationAttributeCacheKey& key)
3300{
3301 if (!key.tagName)
3302 return 0;
3303 ASSERT(key.attributesAndValues.size());
3304 unsigned attributeHash = StringHasher::hashMemory(key.attributesAndValues.data(), key.attributesAndValues.size() * sizeof(key.attributesAndValues[0]));
3305 return WTF::pairIntHash(key.tagName->existingHash(), attributeHash);
3306}
3307
3308void Element::rebuildPresentationAttributeStyle()
3309{
3310 ASSERT(isStyledElement());
3311 PresentationAttributeCacheKey cacheKey;
3312 makePresentationAttributeCacheKey(cacheKey);
3313
3314 unsigned cacheHash = computePresentationAttributeCacheHash(cacheKey);
3315
3316 PresentationAttributeCache::iterator cacheIterator;
3317 if (cacheHash) {
3318 cacheIterator = presentationAttributeCache().add(cacheHash, nullptr).iterator;
3319 if (cacheIterator->value && cacheIterator->value->key != cacheKey)
3320 cacheHash = 0;
3321 } else {
3322 cacheIterator = presentationAttributeCache().end();
3323 }
3324
3325 RefPtr<StylePropertySet> style;
3326 if (cacheHash && cacheIterator->value) {
3327 style = cacheIterator->value->value;
3328 presentationAttributeCacheCleaner().didHitPresentationAttributeCache();
3329 } else {
3330 style = MutableStylePropertySet::create(isSVGElement() ? SVGAttributeMode : CSSQuirksMode);
3331 unsigned size = attributeCount();
3332 for (unsigned i = 0; i < size; ++i) {
3333 const Attribute* attribute = attributeItem(i);
3334 collectStyleForPresentationAttribute(attribute->name(), attribute->value(), static_cast<MutableStylePropertySet*>(style.get()));
3335 }
3336 }
3337
3338 // ShareableElementData doesn't store presentation attribute style, so make sure we have a UniqueElementData.
3339 UniqueElementData* elementData = ensureUniqueElementData();
3340
3341 elementData->m_presentationAttributeStyleIsDirty = false;
3342 elementData->m_presentationAttributeStyle = style->isEmpty() ? 0 : style;
3343
3344 if (!cacheHash || cacheIterator->value)
3345 return;
3346
3347 OwnPtr<PresentationAttributeCacheEntry> newEntry = adoptPtr(new PresentationAttributeCacheEntry);
3348 newEntry->key = cacheKey;
3349 newEntry->value = style.release();
3350
3351 static const int presentationAttributeCacheMaximumSize = 4096;
3352 if (presentationAttributeCache().size() > presentationAttributeCacheMaximumSize) {
3353 // Start building from scratch if the cache ever gets big.
3354 presentationAttributeCache().clear();
3355 presentationAttributeCache().set(cacheHash, newEntry.release());
3356 } else {
3357 cacheIterator->value = newEntry.release();
3358 }
3359}
3360
3361void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, CSSValueID identifier)
3362{
3363 ASSERT(isStyledElement());
3364 style->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier));
3365}
3366
3367void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit)
3368{
3369 ASSERT(isStyledElement());
3370 style->setProperty(propertyID, cssValuePool().createValue(value, unit));
3371}
3372
3373void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, const String& value)
3374{
3375 ASSERT(isStyledElement());
3376 style->setProperty(propertyID, value, false, document()->elementSheet()->contents());
3377}
3378
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003379void ElementData::deref()
3380{
3381 if (!derefBase())
3382 return;
3383
3384 if (m_isUnique)
3385 delete static_cast<UniqueElementData*>(this);
3386 else
3387 delete static_cast<ShareableElementData*>(this);
3388}
3389
3390ElementData::ElementData()
3391 : m_isUnique(true)
3392 , m_arraySize(0)
3393 , m_presentationAttributeStyleIsDirty(false)
3394 , m_styleAttributeIsDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003395 , m_animatedSVGAttributesAreDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003396{
3397}
3398
3399ElementData::ElementData(unsigned arraySize)
3400 : m_isUnique(false)
3401 , m_arraySize(arraySize)
3402 , m_presentationAttributeStyleIsDirty(false)
3403 , m_styleAttributeIsDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003404 , m_animatedSVGAttributesAreDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003405{
3406}
3407
3408struct SameSizeAsElementData : public RefCounted<SameSizeAsElementData> {
3409 unsigned bitfield;
3410 void* refPtrs[3];
3411};
3412
3413COMPILE_ASSERT(sizeof(ElementData) == sizeof(SameSizeAsElementData), element_attribute_data_should_stay_small);
3414
3415static size_t sizeForShareableElementDataWithAttributeCount(unsigned count)
3416{
3417 return sizeof(ShareableElementData) + sizeof(Attribute) * count;
3418}
3419
3420PassRefPtr<ShareableElementData> ShareableElementData::createWithAttributes(const Vector<Attribute>& attributes)
3421{
3422 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(attributes.size()));
3423 return adoptRef(new (slot) ShareableElementData(attributes));
3424}
3425
3426PassRefPtr<UniqueElementData> UniqueElementData::create()
3427{
3428 return adoptRef(new UniqueElementData);
3429}
3430
3431ShareableElementData::ShareableElementData(const Vector<Attribute>& attributes)
3432 : ElementData(attributes.size())
3433{
3434 for (unsigned i = 0; i < m_arraySize; ++i)
3435 new (&m_attributeArray[i]) Attribute(attributes[i]);
3436}
3437
3438ShareableElementData::~ShareableElementData()
3439{
3440 for (unsigned i = 0; i < m_arraySize; ++i)
3441 m_attributeArray[i].~Attribute();
3442}
3443
3444ShareableElementData::ShareableElementData(const UniqueElementData& other)
3445 : ElementData(other, false)
3446{
3447 ASSERT(!other.m_presentationAttributeStyle);
3448
3449 if (other.m_inlineStyle) {
3450 ASSERT(!other.m_inlineStyle->hasCSSOMWrapper());
3451 m_inlineStyle = other.m_inlineStyle->immutableCopyIfNeeded();
3452 }
3453
3454 for (unsigned i = 0; i < m_arraySize; ++i)
3455 new (&m_attributeArray[i]) Attribute(other.m_attributeVector.at(i));
3456}
3457
3458ElementData::ElementData(const ElementData& other, bool isUnique)
3459 : m_isUnique(isUnique)
3460 , m_arraySize(isUnique ? 0 : other.length())
3461 , m_presentationAttributeStyleIsDirty(other.m_presentationAttributeStyleIsDirty)
3462 , m_styleAttributeIsDirty(other.m_styleAttributeIsDirty)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003463 , m_animatedSVGAttributesAreDirty(other.m_animatedSVGAttributesAreDirty)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003464 , m_classNames(other.m_classNames)
3465 , m_idForStyleResolution(other.m_idForStyleResolution)
3466{
3467 // NOTE: The inline style is copied by the subclass copy constructor since we don't know what to do with it here.
3468}
3469
3470UniqueElementData::UniqueElementData()
3471{
3472}
3473
3474UniqueElementData::UniqueElementData(const UniqueElementData& other)
3475 : ElementData(other, true)
3476 , m_presentationAttributeStyle(other.m_presentationAttributeStyle)
3477 , m_attributeVector(other.m_attributeVector)
3478{
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003479 m_inlineStyle = other.m_inlineStyle ? other.m_inlineStyle->mutableCopy() : 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003480}
3481
3482UniqueElementData::UniqueElementData(const ShareableElementData& other)
3483 : ElementData(other, true)
3484{
3485 // An ShareableElementData should never have a mutable inline StylePropertySet attached.
3486 ASSERT(!other.m_inlineStyle || !other.m_inlineStyle->isMutable());
3487 m_inlineStyle = other.m_inlineStyle;
3488
3489 m_attributeVector.reserveCapacity(other.length());
3490 for (unsigned i = 0; i < other.length(); ++i)
3491 m_attributeVector.uncheckedAppend(other.m_attributeArray[i]);
3492}
3493
3494PassRefPtr<UniqueElementData> ElementData::makeUniqueCopy() const
3495{
3496 if (isUnique())
3497 return adoptRef(new UniqueElementData(static_cast<const UniqueElementData&>(*this)));
3498 return adoptRef(new UniqueElementData(static_cast<const ShareableElementData&>(*this)));
3499}
3500
3501PassRefPtr<ShareableElementData> UniqueElementData::makeShareableCopy() const
3502{
3503 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(m_attributeVector.size()));
3504 return adoptRef(new (slot) ShareableElementData(*this));
3505}
3506
3507void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value)
3508{
3509 m_attributeVector.append(Attribute(attributeName, value));
3510}
3511
3512void UniqueElementData::removeAttribute(size_t index)
3513{
3514 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
3515 m_attributeVector.remove(index);
3516}
3517
3518bool ElementData::isEquivalent(const ElementData* other) const
3519{
3520 if (!other)
3521 return isEmpty();
3522
3523 unsigned len = length();
3524 if (len != other->length())
3525 return false;
3526
3527 for (unsigned i = 0; i < len; i++) {
3528 const Attribute* attribute = attributeItem(i);
3529 const Attribute* otherAttr = other->getAttributeItem(attribute->name());
3530 if (!otherAttr || attribute->value() != otherAttr->value())
3531 return false;
3532 }
3533
3534 return true;
3535}
3536
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01003537size_t ElementData::getAttrIndex(Attr* attr) const
3538{
3539 // This relies on the fact that Attr's QualifiedName == the Attribute's name.
3540 for (unsigned i = 0; i < length(); ++i) {
3541 if (attributeItem(i)->name() == attr->qualifiedName())
3542 return i;
3543 }
3544 return notFound;
3545}
3546
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003547size_t ElementData::getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const
3548{
3549 // Continue to checking case-insensitively and/or full namespaced names if necessary:
3550 for (unsigned i = 0; i < length(); ++i) {
3551 const Attribute* attribute = attributeItem(i);
3552 if (!attribute->name().hasPrefix()) {
3553 if (shouldIgnoreAttributeCase && equalIgnoringCase(name, attribute->localName()))
3554 return i;
3555 } else {
3556 // FIXME: Would be faster to do this comparison without calling toString, which
3557 // generates a temporary string by concatenation. But this branch is only reached
3558 // if the attribute name has a prefix, which is rare in HTML.
3559 if (equalPossiblyIgnoringCase(name, attribute->name().toString(), shouldIgnoreAttributeCase))
3560 return i;
3561 }
3562 }
3563 return notFound;
3564}
3565
3566Attribute* UniqueElementData::getAttributeItem(const QualifiedName& name)
3567{
3568 for (unsigned i = 0; i < length(); ++i) {
3569 if (m_attributeVector.at(i).name().matches(name))
3570 return &m_attributeVector.at(i);
3571 }
3572 return 0;
3573}
3574
3575Attribute* UniqueElementData::attributeItem(unsigned index)
3576{
3577 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
3578 return &m_attributeVector.at(index);
3579}
3580
3581} // namespace WebCore