blob: 893d1dcd0c1742ee6992f912aa0184a351969a03 [file] [log] [blame]
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Peter Kelly (pmk@post.com)
5 * (C) 2001 Dirk Mueller (mueller@kde.org)
6 * (C) 2007 David Smith (catfish.man@gmail.com)
7 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2012, 2013 Apple Inc. All rights reserved.
8 * (C) 2007 Eric Seidel (eric@webkit.org)
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public License
21 * along with this library; see the file COPYING.LIB. If not, write to
22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301, USA.
24 */
25
26#include "config.h"
27#include "core/dom/Element.h"
28
Ben Murdoch591b9582013-07-10 11:41:44 +010029#include "CSSPropertyNames.h"
30#include "CSSValueKeywords.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010031#include "HTMLNames.h"
Ben Murdoch7757ec22013-07-23 11:17:36 +010032#include "RuntimeEnabledFeatures.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010033#include "SVGNames.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010034#include "XMLNames.h"
Ben Murdochdf957042013-08-06 11:01:27 +010035#include "bindings/v8/ExceptionState.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010036#include "core/accessibility/AXObjectCache.h"
Ben Murdoch83750172013-07-24 10:36:59 +010037#include "core/animation/DocumentTimeline.h"
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +010038#include "core/animation/css/CSSAnimations.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010039#include "core/css/CSSParser.h"
40#include "core/css/CSSStyleSheet.h"
41#include "core/css/CSSValuePool.h"
42#include "core/css/PropertySetCSSStyleDeclaration.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010043#include "core/css/StylePropertySet.h"
Torne (Richard Coles)81a51572013-05-13 16:52:28 +010044#include "core/css/resolver/StyleResolver.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010045#include "core/dom/Attr.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010046#include "core/dom/Attribute.h"
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010047#include "core/dom/CSSSelectorWatch.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010048#include "core/dom/ClientRect.h"
49#include "core/dom/ClientRectList.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010050#include "core/dom/DatasetDOMStringMap.h"
51#include "core/dom/Document.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010052#include "core/dom/DocumentSharedObjectPool.h"
53#include "core/dom/ElementRareData.h"
54#include "core/dom/ExceptionCode.h"
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +010055#include "core/dom/FullscreenElementStack.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010056#include "core/dom/MutationObserverInterestGroup.h"
57#include "core/dom/MutationRecord.h"
58#include "core/dom/NamedNodeMap.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010059#include "core/dom/NodeRenderStyle.h"
60#include "core/dom/NodeRenderingContext.h"
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +010061#include "core/dom/PostAttachCallbacks.h"
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +010062#include "core/dom/PresentationAttributeStyle.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010063#include "core/dom/PseudoElement.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010064#include "core/dom/ScriptableDocumentParser.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010065#include "core/dom/SelectorQuery.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010066#include "core/dom/Text.h"
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010067#include "core/dom/custom/CustomElement.h"
68#include "core/dom/custom/CustomElementRegistrationContext.h"
Torne (Richard Coles)e5249552013-05-15 11:35:13 +010069#include "core/dom/shadow/InsertionPoint.h"
70#include "core/dom/shadow/ShadowRoot.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010071#include "core/editing/FrameSelection.h"
72#include "core/editing/TextIterator.h"
73#include "core/editing/htmlediting.h"
Torne (Richard Coles)19cde672013-11-06 12:28:04 +000074#include "core/editing/markup.h"
Torne (Richard Coles)1e202182013-10-18 15:46:42 +010075#include "core/events/EventDispatcher.h"
76#include "core/events/FocusEvent.h"
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +010077#include "core/frame/ContentSecurityPolicy.h"
78#include "core/frame/Frame.h"
79#include "core/frame/FrameView.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010080#include "core/html/ClassList.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010081#include "core/html/HTMLCollection.h"
82#include "core/html/HTMLDocument.h"
83#include "core/html/HTMLElement.h"
84#include "core/html/HTMLFormControlsCollection.h"
85#include "core/html/HTMLFrameOwnerElement.h"
86#include "core/html/HTMLLabelElement.h"
87#include "core/html/HTMLOptionsCollection.h"
88#include "core/html/HTMLTableRowsCollection.h"
Torne (Richard Coles)19cde672013-11-06 12:28:04 +000089#include "core/html/HTMLTemplateElement.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010090#include "core/html/parser/HTMLParserIdioms.h"
Torne (Richard Coles)51b29062013-11-28 11:56:03 +000091#include "core/inspector/InspectorInstrumentation.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010092#include "core/page/FocusController.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010093#include "core/page/Page.h"
94#include "core/page/PointerLockController.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010095#include "core/rendering/FlowThreadController.h"
Torne (Richard Coles)51b29062013-11-28 11:56:03 +000096#include "core/rendering/RenderNamedFlowFragment.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010097#include "core/rendering/RenderView.h"
98#include "core/rendering/RenderWidget.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010099#include "core/svg/SVGDocumentExtensions.h"
100#include "core/svg/SVGElement.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100101#include "wtf/BitVector.h"
Ben Murdoch591b9582013-07-10 11:41:44 +0100102#include "wtf/HashFunctions.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100103#include "wtf/text/CString.h"
Ben Murdoch591b9582013-07-10 11:41:44 +0100104#include "wtf/text/TextPosition.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100105
106namespace WebCore {
107
108using namespace HTMLNames;
109using namespace XMLNames;
110
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100111class StyleResolverParentPusher {
112public:
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000113 explicit StyleResolverParentPusher(Element& parent)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100114 : m_parent(parent)
115 , m_pushedStyleResolver(0)
116 {
117 }
118 void push()
119 {
120 if (m_pushedStyleResolver)
121 return;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000122 m_pushedStyleResolver = m_parent.document().styleResolver();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100123 m_pushedStyleResolver->pushParentElement(m_parent);
124 }
125 ~StyleResolverParentPusher()
126 {
127
128 if (!m_pushedStyleResolver)
129 return;
130
131 // This tells us that our pushed style selector is in a bad state,
132 // so we should just bail out in that scenario.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000133 ASSERT(m_pushedStyleResolver == m_parent.document().styleResolver());
134 if (m_pushedStyleResolver != m_parent.document().styleResolver())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100135 return;
136
137 m_pushedStyleResolver->popParentElement(m_parent);
138 }
139
140private:
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000141 Element& m_parent;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100142 StyleResolver* m_pushedStyleResolver;
143};
144
145typedef Vector<RefPtr<Attr> > AttrNodeList;
146typedef HashMap<Element*, OwnPtr<AttrNodeList> > AttrNodeListMap;
147
148static AttrNodeListMap& attrNodeListMap()
149{
150 DEFINE_STATIC_LOCAL(AttrNodeListMap, map, ());
151 return map;
152}
153
154static AttrNodeList* attrNodeListForElement(Element* element)
155{
156 if (!element->hasSyntheticAttrChildNodes())
157 return 0;
158 ASSERT(attrNodeListMap().contains(element));
159 return attrNodeListMap().get(element);
160}
161
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100162static AttrNodeList& ensureAttrNodeListForElement(Element* element)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100163{
164 if (element->hasSyntheticAttrChildNodes()) {
165 ASSERT(attrNodeListMap().contains(element));
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100166 return *attrNodeListMap().get(element);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100167 }
168 ASSERT(!attrNodeListMap().contains(element));
169 element->setHasSyntheticAttrChildNodes(true);
170 AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList));
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100171 return *result.iterator->value;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100172}
173
174static void removeAttrNodeListForElement(Element* element)
175{
176 ASSERT(element->hasSyntheticAttrChildNodes());
177 ASSERT(attrNodeListMap().contains(element));
178 attrNodeListMap().remove(element);
179 element->setHasSyntheticAttrChildNodes(false);
180}
181
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000182static Attr* findAttrNodeInList(const AttrNodeList& attrNodeList, const QualifiedName& name)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100183{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000184 AttrNodeList::const_iterator end = attrNodeList.end();
185 for (AttrNodeList::const_iterator it = attrNodeList.begin(); it != end; ++it) {
186 if ((*it)->qualifiedName() == name)
187 return it->get();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100188 }
189 return 0;
190}
191
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100192PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document)
193{
194 return adoptRef(new Element(tagName, document, CreateElement));
195}
196
197Element::~Element()
198{
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000199 // When the document is not destroyed, an element that was part of a named flow
200 // content nodes should have been removed from the content nodes collection
201 // and the inNamedFlow flag reset.
202 ASSERT(!document().renderView() || !inNamedFlow());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100203
Ben Murdoch591b9582013-07-10 11:41:44 +0100204 if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
205 cssomWrapper->clearParentElement();
206
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100207 if (hasRareData()) {
208 ElementRareData* data = elementRareData();
209 data->setPseudoElement(BEFORE, 0);
210 data->setPseudoElement(AFTER, 0);
Ben Murdoche69819b2013-07-17 14:56:49 +0100211 data->setPseudoElement(BACKDROP, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100212 data->clearShadow();
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100213
214 if (RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
215 if (ActiveAnimations* activeAnimations = data->activeAnimations())
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000216 activeAnimations->cssAnimations().cancel();
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100217 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100218 }
219
Ben Murdoch83750172013-07-24 10:36:59 +0100220 if (isCustomElement())
221 CustomElement::wasDestroyed(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100222
223 if (hasSyntheticAttrChildNodes())
224 detachAllAttrNodesFromElement();
225
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100226 if (hasPendingResources()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100227 document().accessSVGExtensions()->removeElementFromPendingResources(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100228 ASSERT(!hasPendingResources());
229 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100230}
231
232inline ElementRareData* Element::elementRareData() const
233{
234 ASSERT(hasRareData());
235 return static_cast<ElementRareData*>(rareData());
236}
237
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100238inline ElementRareData& Element::ensureElementRareData()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100239{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100240 return static_cast<ElementRareData&>(ensureRareData());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100241}
242
243void Element::clearTabIndexExplicitlyIfNeeded()
244{
245 if (hasRareData())
246 elementRareData()->clearTabIndexExplicitly();
247}
248
249void Element::setTabIndexExplicitly(short tabIndex)
250{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100251 ensureElementRareData().setTabIndexExplicitly(tabIndex);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100252}
253
254bool Element::supportsFocus() const
255{
256 return hasRareData() && elementRareData()->tabIndexSetExplicitly();
257}
258
259short Element::tabIndex() const
260{
261 return hasRareData() ? elementRareData()->tabIndex() : 0;
262}
263
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100264bool Element::rendererIsFocusable() const
265{
266 // Elements in canvas fallback content are not rendered, but they are allowed to be
267 // focusable as long as their canvas is displayed and visible.
268 if (isInCanvasSubtree()) {
269 const Element* e = this;
270 while (e && !e->hasLocalName(canvasTag))
271 e = e->parentElement();
272 ASSERT(e);
273 return e->renderer() && e->renderer()->style()->visibility() == VISIBLE;
274 }
275
276 // FIXME: These asserts should be in Node::isFocusable, but there are some
Ben Murdoche69819b2013-07-17 14:56:49 +0100277 // callsites like Document::setFocusedElement that would currently fail on
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100278 // them. See crbug.com/251163
279 if (renderer()) {
280 ASSERT(!renderer()->needsLayout());
281 } else {
282 // We can't just use needsStyleRecalc() because if the node is in a
283 // display:none tree it might say it needs style recalc but the whole
284 // document is actually up to date.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100285 ASSERT(!document().childNeedsStyleRecalc());
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100286 }
287
288 // FIXME: Even if we are not visible, we might have a child that is visible.
289 // Hyatt wants to fix that some day with a "has visible content" flag or the like.
290 if (!renderer() || renderer()->style()->visibility() != VISIBLE)
291 return false;
292
293 return true;
294}
295
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100296PassRefPtr<Node> Element::cloneNode(bool deep)
297{
298 return deep ? cloneElementWithChildren() : cloneElementWithoutChildren();
299}
300
301PassRefPtr<Element> Element::cloneElementWithChildren()
302{
303 RefPtr<Element> clone = cloneElementWithoutChildren();
304 cloneChildNodes(clone.get());
305 return clone.release();
306}
307
308PassRefPtr<Element> Element::cloneElementWithoutChildren()
309{
310 RefPtr<Element> clone = cloneElementWithoutAttributesAndChildren();
311 // This will catch HTML elements in the wrong namespace that are not correctly copied.
312 // This is a sanity check as HTML overloads some of the DOM methods.
313 ASSERT(isHTMLElement() == clone->isHTMLElement());
314
315 clone->cloneDataFromElement(*this);
316 return clone.release();
317}
318
319PassRefPtr<Element> Element::cloneElementWithoutAttributesAndChildren()
320{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100321 return document().createElement(tagQName(), false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100322}
323
324PassRefPtr<Attr> Element::detachAttribute(size_t index)
325{
326 ASSERT(elementData());
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100327 const Attribute* attribute = elementData()->attributeItem(index);
328 RefPtr<Attr> attrNode = attrIfExists(attribute->name());
329 if (attrNode)
330 detachAttrNodeAtIndex(attrNode.get(), index);
331 else {
332 attrNode = Attr::create(document(), attribute->name(), attribute->value());
333 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
334 }
335 return attrNode.release();
336}
337
338void Element::detachAttrNodeAtIndex(Attr* attr, size_t index)
339{
340 ASSERT(attr);
341 ASSERT(elementData());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100342
343 const Attribute* attribute = elementData()->attributeItem(index);
344 ASSERT(attribute);
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100345 ASSERT(attribute->name() == attr->qualifiedName());
346 detachAttrNodeFromElementWithValue(attr, attribute->value());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100347 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100348}
349
350void Element::removeAttribute(const QualifiedName& name)
351{
352 if (!elementData())
353 return;
354
355 size_t index = elementData()->getAttributeItemIndex(name);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100356 if (index == kNotFound)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100357 return;
358
359 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
360}
361
362void Element::setBooleanAttribute(const QualifiedName& name, bool value)
363{
364 if (value)
365 setAttribute(name, emptyAtom);
366 else
367 removeAttribute(name);
368}
369
370NamedNodeMap* Element::attributes() const
371{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100372 ElementRareData& rareData = const_cast<Element*>(this)->ensureElementRareData();
373 if (NamedNodeMap* attributeMap = rareData.attributeMap())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100374 return attributeMap;
375
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100376 rareData.setAttributeMap(NamedNodeMap::create(const_cast<Element*>(this)));
377 return rareData.attributeMap();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100378}
379
Ben Murdoch83750172013-07-24 10:36:59 +0100380ActiveAnimations* Element::activeAnimations() const
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100381{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000382 if (hasRareData())
Ben Murdoch83750172013-07-24 10:36:59 +0100383 return elementRareData()->activeAnimations();
384 return 0;
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100385}
386
Ben Murdoch83750172013-07-24 10:36:59 +0100387ActiveAnimations* Element::ensureActiveAnimations()
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100388{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100389 ElementRareData& rareData = ensureElementRareData();
390 if (!rareData.activeAnimations())
391 rareData.setActiveAnimations(adoptPtr(new ActiveAnimations()));
392 return rareData.activeAnimations();
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100393}
394
395bool Element::hasActiveAnimations() const
396{
Ben Murdoch83750172013-07-24 10:36:59 +0100397 if (!RuntimeEnabledFeatures::webAnimationsEnabled())
398 return false;
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100399
Ben Murdoch83750172013-07-24 10:36:59 +0100400 if (!hasRareData())
401 return false;
402
403 ActiveAnimations* activeAnimations = elementRareData()->activeAnimations();
404 return activeAnimations && !activeAnimations->isEmpty();
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100405}
406
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100407Node::NodeType Element::nodeType() const
408{
409 return ELEMENT_NODE;
410}
411
412bool Element::hasAttribute(const QualifiedName& name) const
413{
414 return hasAttributeNS(name.namespaceURI(), name.localName());
415}
416
417void Element::synchronizeAllAttributes() const
418{
419 if (!elementData())
420 return;
421 if (elementData()->m_styleAttributeIsDirty) {
422 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100423 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100424 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100425 if (elementData()->m_animatedSVGAttributesAreDirty) {
426 ASSERT(isSVGElement());
427 toSVGElement(this)->synchronizeAnimatedSVGAttribute(anyQName());
428 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100429}
430
431inline void Element::synchronizeAttribute(const QualifiedName& name) const
432{
433 if (!elementData())
434 return;
435 if (UNLIKELY(name == styleAttr && elementData()->m_styleAttributeIsDirty)) {
436 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100437 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100438 return;
439 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100440 if (UNLIKELY(elementData()->m_animatedSVGAttributesAreDirty)) {
441 ASSERT(isSVGElement());
442 toSVGElement(this)->synchronizeAnimatedSVGAttribute(name);
443 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100444}
445
446inline void Element::synchronizeAttribute(const AtomicString& localName) const
447{
448 // This version of synchronizeAttribute() is streamlined for the case where you don't have a full QualifiedName,
449 // e.g when called from DOM API.
450 if (!elementData())
451 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100452 if (elementData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(localName, styleAttr.localName(), shouldIgnoreAttributeCase())) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100453 ASSERT(isStyledElement());
Ben Murdoch591b9582013-07-10 11:41:44 +0100454 synchronizeStyleAttributeInternal();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100455 return;
456 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100457 if (elementData()->m_animatedSVGAttributesAreDirty) {
458 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
459 ASSERT(isSVGElement());
460 static_cast<const SVGElement*>(this)->synchronizeAnimatedSVGAttribute(QualifiedName(nullAtom, localName, nullAtom));
461 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100462}
463
464const AtomicString& Element::getAttribute(const QualifiedName& name) const
465{
466 if (!elementData())
467 return nullAtom;
468 synchronizeAttribute(name);
469 if (const Attribute* attribute = getAttributeItem(name))
470 return attribute->value();
471 return nullAtom;
472}
473
Ben Murdoch591b9582013-07-10 11:41:44 +0100474void Element::scrollIntoView(bool alignToTop)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100475{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100476 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100477
478 if (!renderer())
479 return;
480
481 LayoutRect bounds = boundingBox();
482 // Align to the top / bottom and to the closest edge.
483 if (alignToTop)
484 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
485 else
486 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
487}
488
489void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
490{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100491 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100492
493 if (!renderer())
494 return;
495
496 LayoutRect bounds = boundingBox();
497 if (centerIfNeeded)
498 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
499 else
500 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
501}
502
503void Element::scrollByUnits(int units, ScrollGranularity granularity)
504{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100505 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100506
507 if (!renderer())
508 return;
509
510 if (!renderer()->hasOverflowClip())
511 return;
512
513 ScrollDirection direction = ScrollDown;
514 if (units < 0) {
515 direction = ScrollUp;
516 units = -units;
517 }
518 Node* stopNode = this;
519 toRenderBox(renderer())->scroll(direction, granularity, units, &stopNode);
520}
521
522void Element::scrollByLines(int lines)
523{
524 scrollByUnits(lines, ScrollByLine);
525}
526
527void Element::scrollByPages(int pages)
528{
529 scrollByUnits(pages, ScrollByPage);
530}
531
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000532static float localZoomForRenderer(RenderObject& renderer)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100533{
534 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
535 // other out, but the alternative is that we'd have to crawl up the whole render tree every
536 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
537 float zoomFactor = 1;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000538 if (renderer.style()->effectiveZoom() != 1) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100539 // Need to find the nearest enclosing RenderObject that set up
540 // a differing zoom, and then we divide our result by it to eliminate the zoom.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000541 RenderObject* prev = &renderer;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100542 for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) {
543 if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) {
544 zoomFactor = prev->style()->zoom();
545 break;
546 }
547 prev = curr;
548 }
549 if (prev->isRenderView())
550 zoomFactor = prev->style()->zoom();
551 }
552 return zoomFactor;
553}
554
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000555static int adjustForLocalZoom(LayoutUnit value, RenderObject& renderer)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100556{
557 float zoomFactor = localZoomForRenderer(renderer);
558 if (zoomFactor == 1)
559 return value;
560 return lroundf(value / zoomFactor);
561}
562
563int Element::offsetLeft()
564{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100565 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100566 if (RenderBoxModelObject* renderer = renderBoxModelObject())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000567 return adjustForLocalZoom(renderer->pixelSnappedOffsetLeft(), *renderer);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100568 return 0;
569}
570
571int Element::offsetTop()
572{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100573 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100574 if (RenderBoxModelObject* renderer = renderBoxModelObject())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000575 return adjustForLocalZoom(renderer->pixelSnappedOffsetTop(), *renderer);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100576 return 0;
577}
578
579int Element::offsetWidth()
580{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100581 document().updateStyleForNodeIfNeeded(this);
Ben Murdoch591b9582013-07-10 11:41:44 +0100582
583 if (RenderBox* renderer = renderBox()) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100584 if (renderer->canDetermineWidthWithoutLayout())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000585 return adjustLayoutUnitForAbsoluteZoom(renderer->fixedOffsetWidth(), *renderer).round();
Ben Murdoch591b9582013-07-10 11:41:44 +0100586 }
587
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100588 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100589 if (RenderBoxModelObject* renderer = renderBoxModelObject())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000590 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetWidth(), *renderer).round();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100591 return 0;
592}
593
594int Element::offsetHeight()
595{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100596 document().partialUpdateLayoutIgnorePendingStylesheets(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100597 if (RenderBoxModelObject* renderer = renderBoxModelObject())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000598 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetHeight(), *renderer).round();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100599 return 0;
600}
601
602Element* Element::bindingsOffsetParent()
603{
604 Element* element = offsetParent();
605 if (!element || !element->isInShadowTree())
606 return element;
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100607 return element->containingShadowRoot()->shouldExposeToBindings() ? element : 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100608}
609
610Element* Element::offsetParent()
611{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100612 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100613 if (RenderObject* renderer = this->renderer())
614 return renderer->offsetParent();
615 return 0;
616}
617
618int Element::clientLeft()
619{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100620 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100621
622 if (RenderBox* renderer = renderBox())
623 return adjustForAbsoluteZoom(roundToInt(renderer->clientLeft()), renderer);
624 return 0;
625}
626
627int Element::clientTop()
628{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100629 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100630
631 if (RenderBox* renderer = renderBox())
632 return adjustForAbsoluteZoom(roundToInt(renderer->clientTop()), renderer);
633 return 0;
634}
635
636int Element::clientWidth()
637{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100638 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100639
640 // When in strict mode, clientWidth for the document element should return the width of the containing frame.
641 // When in quirks mode, clientWidth for the body element should return the width of the containing frame.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100642 bool inQuirksMode = document().inQuirksMode();
643 if ((!inQuirksMode && document().documentElement() == this)
644 || (inQuirksMode && isHTMLElement() && document().body() == this)) {
645 if (FrameView* view = document().view()) {
646 if (RenderView* renderView = document().renderView())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100647 return adjustForAbsoluteZoom(view->layoutSize().width(), renderView);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100648 }
649 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100650
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100651 if (RenderBox* renderer = renderBox())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000652 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientWidth(), *renderer).round();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100653 return 0;
654}
655
656int Element::clientHeight()
657{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100658 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100659
660 // When in strict mode, clientHeight for the document element should return the height of the containing frame.
661 // When in quirks mode, clientHeight for the body element should return the height of the containing frame.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100662 bool inQuirksMode = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100663
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100664 if ((!inQuirksMode && document().documentElement() == this)
665 || (inQuirksMode && isHTMLElement() && document().body() == this)) {
666 if (FrameView* view = document().view()) {
667 if (RenderView* renderView = document().renderView())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100668 return adjustForAbsoluteZoom(view->layoutSize().height(), renderView);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100669 }
670 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100671
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100672 if (RenderBox* renderer = renderBox())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000673 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientHeight(), *renderer).round();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100674 return 0;
675}
676
677int Element::scrollLeft()
678{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100679 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100680
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000681 if (document().documentElement() != this) {
682 if (RenderBox* rend = renderBox())
683 return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
684 return 0;
685 }
686
687 if (RuntimeEnabledFeatures::scrollTopLeftInteropEnabled()) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100688 if (document().inQuirksMode())
689 return 0;
690
691 if (FrameView* view = document().view()) {
692 if (RenderView* renderView = document().renderView())
693 return adjustForAbsoluteZoom(view->scrollX(), renderView);
694 }
695 }
696
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100697 return 0;
698}
699
700int Element::scrollTop()
701{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100702 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100703
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000704 if (document().documentElement() != this) {
705 if (RenderBox* rend = renderBox())
706 return adjustForAbsoluteZoom(rend->scrollTop(), rend);
707 return 0;
708 }
709
710 if (RuntimeEnabledFeatures::scrollTopLeftInteropEnabled()) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100711 if (document().inQuirksMode())
712 return 0;
713
714 if (FrameView* view = document().view()) {
715 if (RenderView* renderView = document().renderView())
716 return adjustForAbsoluteZoom(view->scrollY(), renderView);
717 }
718 }
719
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100720 return 0;
721}
722
723void Element::setScrollLeft(int newLeft)
724{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100725 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100726
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000727 if (document().documentElement() != this) {
728 if (RenderBox* rend = renderBox())
729 rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
730 return;
731 }
732
733 if (RuntimeEnabledFeatures::scrollTopLeftInteropEnabled()) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100734 if (document().inQuirksMode())
735 return;
736
737 Frame* frame = document().frame();
738 if (!frame)
739 return;
740 FrameView* view = frame->view();
741 if (!view)
742 return;
743
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100744 view->setScrollPosition(IntPoint(static_cast<int>(newLeft * frame->pageZoomFactor()), view->scrollY()));
745 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100746}
747
748void Element::setScrollTop(int newTop)
749{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100750 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100751
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000752 if (document().documentElement() != this) {
753 if (RenderBox* rend = renderBox())
754 rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
755 return;
756 }
757
758 if (RuntimeEnabledFeatures::scrollTopLeftInteropEnabled()) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100759 if (document().inQuirksMode())
760 return;
761
762 Frame* frame = document().frame();
763 if (!frame)
764 return;
765 FrameView* view = frame->view();
766 if (!view)
767 return;
768
Torne (Richard Coles)1e202182013-10-18 15:46:42 +0100769 view->setScrollPosition(IntPoint(view->scrollX(), static_cast<int>(newTop * frame->pageZoomFactor())));
770 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100771}
772
773int Element::scrollWidth()
774{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100775 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100776 if (RenderBox* rend = renderBox())
777 return adjustForAbsoluteZoom(rend->scrollWidth(), rend);
778 return 0;
779}
780
781int Element::scrollHeight()
782{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100783 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100784 if (RenderBox* rend = renderBox())
785 return adjustForAbsoluteZoom(rend->scrollHeight(), rend);
786 return 0;
787}
788
789IntRect Element::boundsInRootViewSpace()
790{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100791 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100792
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100793 FrameView* view = document().view();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100794 if (!view)
795 return IntRect();
796
797 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100798 if (isSVGElement() && renderer()) {
799 // Get the bounding rectangle from the SVG model.
800 SVGElement* svgElement = toSVGElement(this);
801 FloatRect localRect;
802 if (svgElement->getBoundingBox(localRect))
803 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100804 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100805 // Get the bounding rectangle from the box model.
806 if (renderBoxModelObject())
807 renderBoxModelObject()->absoluteQuads(quads);
808 }
809
810 if (quads.isEmpty())
811 return IntRect();
812
813 IntRect result = quads[0].enclosingBoundingBox();
814 for (size_t i = 1; i < quads.size(); ++i)
815 result.unite(quads[i].enclosingBoundingBox());
816
817 result = view->contentsToRootView(result);
818 return result;
819}
820
821PassRefPtr<ClientRectList> Element::getClientRects()
822{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100823 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100824
825 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject();
826 if (!renderBoxModelObject)
827 return ClientRectList::create();
828
829 // FIXME: Handle SVG elements.
830 // FIXME: Handle table/inline-table with a caption.
831
832 Vector<FloatQuad> quads;
833 renderBoxModelObject->absoluteQuads(quads);
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000834 document().adjustFloatQuadsForScrollAndAbsoluteZoom(quads, *renderBoxModelObject);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100835 return ClientRectList::create(quads);
836}
837
838PassRefPtr<ClientRect> Element::getBoundingClientRect()
839{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100840 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100841
842 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100843 if (isSVGElement() && renderer() && !renderer()->isSVGRoot()) {
844 // Get the bounding rectangle from the SVG model.
845 SVGElement* svgElement = toSVGElement(this);
846 FloatRect localRect;
847 if (svgElement->getBoundingBox(localRect))
848 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100849 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100850 // Get the bounding rectangle from the box model.
851 if (renderBoxModelObject())
852 renderBoxModelObject()->absoluteQuads(quads);
853 }
854
855 if (quads.isEmpty())
856 return ClientRect::create();
857
858 FloatRect result = quads[0].boundingBox();
859 for (size_t i = 1; i < quads.size(); ++i)
860 result.unite(quads[i].boundingBox());
861
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000862 ASSERT(renderer());
863 document().adjustFloatRectForScrollAndAbsoluteZoom(result, *renderer());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100864 return ClientRect::create(result);
865}
Ben Murdoch591b9582013-07-10 11:41:44 +0100866
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100867IntRect Element::screenRect() const
868{
869 if (!renderer())
870 return IntRect();
871 // FIXME: this should probably respect transforms
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100872 return document().view()->contentsToScreen(renderer()->absoluteBoundingBoxRectIgnoringTransforms());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100873}
874
875const AtomicString& Element::getAttribute(const AtomicString& localName) const
876{
877 if (!elementData())
878 return nullAtom;
879 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100880 if (const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100881 return attribute->value();
882 return nullAtom;
883}
884
885const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
886{
887 return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
888}
889
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000890void Element::setAttribute(const AtomicString& localName, const AtomicString& value, ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100891{
892 if (!Document::isValidName(localName)) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000893 exceptionState.throwUninformativeAndGenericDOMException(InvalidCharacterError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100894 return;
895 }
896
897 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +0100898 const AtomicString& caseAdjustedLocalName = shouldIgnoreAttributeCase() ? localName.lower() : localName;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100899
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100900 size_t index = elementData() ? elementData()->getAttributeItemIndex(caseAdjustedLocalName, false) : kNotFound;
901 const QualifiedName& qName = index != kNotFound ? attributeItem(index)->name() : QualifiedName(nullAtom, caseAdjustedLocalName, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100902 setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute);
903}
904
905void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
906{
907 synchronizeAttribute(name);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100908 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : kNotFound;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100909 setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute);
910}
911
912void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value)
913{
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100914 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : kNotFound;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100915 setAttributeInternal(index, name, value, InSynchronizationOfLazyAttribute);
916}
917
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000918ALWAYS_INLINE void Element::setAttributeInternal(size_t index, const QualifiedName& name, const AtomicString& newValue, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100919{
920 if (newValue.isNull()) {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100921 if (index != kNotFound)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100922 removeAttributeInternal(index, inSynchronizationOfLazyAttribute);
923 return;
924 }
925
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100926 if (index == kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100927 addAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute);
928 return;
929 }
930
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000931 const Attribute* existingAttribute = attributeItem(index);
932 QualifiedName existingAttributeName = existingAttribute->name();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100933
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100934 if (!inSynchronizationOfLazyAttribute)
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000935 willModifyAttribute(existingAttributeName, existingAttribute->value(), newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100936
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000937 if (newValue != existingAttribute->value()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100938 // If there is an Attr node hooked to this attribute, the Attr::setValue() call below
939 // will write into the ElementData.
940 // FIXME: Refactor this so it makes some sense.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100941 if (RefPtr<Attr> attrNode = inSynchronizationOfLazyAttribute ? 0 : attrIfExists(existingAttributeName))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100942 attrNode->setValue(newValue);
943 else
944 ensureUniqueElementData()->attributeItem(index)->setValue(newValue);
945 }
946
947 if (!inSynchronizationOfLazyAttribute)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100948 didModifyAttribute(existingAttributeName, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100949}
950
951static inline AtomicString makeIdForStyleResolution(const AtomicString& value, bool inQuirksMode)
952{
953 if (inQuirksMode)
954 return value.lower();
955 return value;
956}
957
Ben Murdoch7757ec22013-07-23 11:17:36 +0100958static bool checkNeedsStyleInvalidationForIdChange(const AtomicString& oldId, const AtomicString& newId, const RuleFeatureSet& features)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100959{
960 ASSERT(newId != oldId);
Ben Murdoch7757ec22013-07-23 11:17:36 +0100961 if (!oldId.isEmpty() && features.hasSelectorForId(oldId))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100962 return true;
Ben Murdoch7757ec22013-07-23 11:17:36 +0100963 if (!newId.isEmpty() && features.hasSelectorForId(newId))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100964 return true;
965 return false;
966}
967
Ben Murdoch591b9582013-07-10 11:41:44 +0100968void Element::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100969{
Torne (Richard Coles)19cde672013-11-06 12:28:04 +0000970 if (ElementShadow* parentElementShadow = shadowWhereNodeCanBeDistributed(*this)) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100971 if (shouldInvalidateDistributionWhenAttributeChanged(parentElementShadow, name, newValue))
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +0100972 parentElementShadow->setNeedsDistributionRecalc();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100973 }
974
975 parseAttribute(name, newValue);
976
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100977 document().incDOMTreeVersion();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100978
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100979 StyleResolver* styleResolver = document().styleResolverIfExists();
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +0000980 bool testShouldInvalidateStyle = inActiveDocument() && styleResolver && styleChangeType() < SubtreeStyleChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100981 bool shouldInvalidateStyle = false;
982
Ben Murdoch591b9582013-07-10 11:41:44 +0100983 if (isStyledElement() && name == styleAttr) {
984 styleAttributeChanged(newValue, reason);
985 } else if (isStyledElement() && isPresentationAttribute(name)) {
986 elementData()->m_presentationAttributeStyleIsDirty = true;
Ben Murdoche69819b2013-07-17 14:56:49 +0100987 setNeedsStyleRecalc(LocalStyleChange);
Ben Murdoch591b9582013-07-10 11:41:44 +0100988 }
989
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100990 if (isIdAttributeName(name)) {
991 AtomicString oldId = elementData()->idForStyleResolution();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100992 AtomicString newId = makeIdForStyleResolution(newValue, document().inQuirksMode());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100993 if (newId != oldId) {
994 elementData()->setIdForStyleResolution(newId);
Torne (Richard Coles)51b29062013-11-28 11:56:03 +0000995 shouldInvalidateStyle = testShouldInvalidateStyle && checkNeedsStyleInvalidationForIdChange(oldId, newId, styleResolver->ensureRuleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100996 }
Ben Murdoch591b9582013-07-10 11:41:44 +0100997 } else if (name == classAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100998 classAttributeChanged(newValue);
Ben Murdoch591b9582013-07-10 11:41:44 +0100999 } else if (name == HTMLNames::nameAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001000 setHasName(!newValue.isNull());
Ben Murdoch591b9582013-07-10 11:41:44 +01001001 } else if (name == HTMLNames::pseudoAttr) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001002 shouldInvalidateStyle |= testShouldInvalidateStyle && isInShadowTree();
Ben Murdoch591b9582013-07-10 11:41:44 +01001003 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001004
1005 invalidateNodeListCachesInAncestors(&name, this);
1006
1007 // If there is currently no StyleResolver, we can't be sure that this attribute change won't affect style.
1008 shouldInvalidateStyle |= !styleResolver;
1009
1010 if (shouldInvalidateStyle)
1011 setNeedsStyleRecalc();
1012
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001013 if (AXObjectCache* cache = document().existingAXObjectCache())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001014 cache->handleAttributeChanged(name, this);
1015}
1016
1017inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
1018{
Ben Murdoche69819b2013-07-17 14:56:49 +01001019 if (name == isAttr)
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001020 CustomElementRegistrationContext::setTypeExtension(this, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001021 attributeChanged(name, newValue, reason);
1022}
1023
1024template <typename CharacterType>
1025static inline bool classStringHasClassName(const CharacterType* characters, unsigned length)
1026{
1027 ASSERT(length > 0);
1028
1029 unsigned i = 0;
1030 do {
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001031 if (isNotHTMLSpace<CharacterType>(characters[i]))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001032 break;
1033 ++i;
1034 } while (i < length);
1035
1036 return i < length;
1037}
1038
1039static inline bool classStringHasClassName(const AtomicString& newClassString)
1040{
1041 unsigned length = newClassString.length();
1042
1043 if (!length)
1044 return false;
1045
1046 if (newClassString.is8Bit())
1047 return classStringHasClassName(newClassString.characters8(), length);
1048 return classStringHasClassName(newClassString.characters16(), length);
1049}
1050
1051template<typename Checker>
1052static bool checkSelectorForClassChange(const SpaceSplitString& changedClasses, const Checker& checker)
1053{
1054 unsigned changedSize = changedClasses.size();
1055 for (unsigned i = 0; i < changedSize; ++i) {
1056 if (checker.hasSelectorForClass(changedClasses[i]))
1057 return true;
1058 }
1059 return false;
1060}
1061
1062template<typename Checker>
1063static bool checkSelectorForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, const Checker& checker)
1064{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001065 if (!oldClasses.size())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001066 return checkSelectorForClassChange(newClasses, checker);
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001067
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001068 // Class vectors tend to be very short. This is faster than using a hash table.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001069 BitVector remainingClassBits;
1070 remainingClassBits.ensureSize(oldClasses.size());
1071
1072 for (unsigned i = 0; i < newClasses.size(); ++i) {
1073 bool found = false;
1074 for (unsigned j = 0; j < oldClasses.size(); ++j) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001075 if (newClasses[i] == oldClasses[j]) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001076 // Mark each class that is still in the newClasses so we can skip doing
1077 // an n^2 search below when looking for removals. We can't break from
1078 // this loop early since a class can appear more than once.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001079 remainingClassBits.quickSet(j);
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001080 found = true;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001081 }
1082 }
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001083 // Class was added.
1084 if (!found && checker.hasSelectorForClass(newClasses[i]))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001085 return true;
1086 }
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001087
1088 for (unsigned i = 0; i < oldClasses.size(); ++i) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001089 if (remainingClassBits.quickGet(i))
1090 continue;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001091 // Class was removed.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001092 if (checker.hasSelectorForClass(oldClasses[i]))
1093 return true;
1094 }
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001095
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001096 return false;
1097}
1098
1099void Element::classAttributeChanged(const AtomicString& newClassString)
1100{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001101 StyleResolver* styleResolver = document().styleResolverIfExists();
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001102 bool testShouldInvalidateStyle = inActiveDocument() && styleResolver && styleChangeType() < SubtreeStyleChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001103 bool shouldInvalidateStyle = false;
1104
1105 if (classStringHasClassName(newClassString)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001106 const bool shouldFoldCase = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001107 const SpaceSplitString oldClasses = elementData()->classNames();
1108 elementData()->setClass(newClassString, shouldFoldCase);
1109 const SpaceSplitString& newClasses = elementData()->classNames();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001110 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, newClasses, styleResolver->ensureRuleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001111 } else {
1112 const SpaceSplitString& oldClasses = elementData()->classNames();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001113 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, styleResolver->ensureRuleFeatureSet());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001114 elementData()->clearClass();
1115 }
1116
1117 if (hasRareData())
1118 elementRareData()->clearClassListValueForQuirksMode();
1119
1120 if (shouldInvalidateStyle)
1121 setNeedsStyleRecalc();
1122}
1123
1124bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
1125{
1126 ASSERT(elementShadow);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001127 const SelectRuleFeatureSet& featureSet = elementShadow->ensureSelectFeatureSet();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001128
1129 if (isIdAttributeName(name)) {
1130 AtomicString oldId = elementData()->idForStyleResolution();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001131 AtomicString newId = makeIdForStyleResolution(newValue, document().inQuirksMode());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001132 if (newId != oldId) {
1133 if (!oldId.isEmpty() && featureSet.hasSelectorForId(oldId))
1134 return true;
1135 if (!newId.isEmpty() && featureSet.hasSelectorForId(newId))
1136 return true;
1137 }
1138 }
1139
1140 if (name == HTMLNames::classAttr) {
1141 const AtomicString& newClassString = newValue;
1142 if (classStringHasClassName(newClassString)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001143 const bool shouldFoldCase = document().inQuirksMode();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001144 const SpaceSplitString& oldClasses = elementData()->classNames();
1145 const SpaceSplitString newClasses(newClassString, shouldFoldCase);
1146 if (checkSelectorForClassChange(oldClasses, newClasses, featureSet))
1147 return true;
1148 } else {
1149 const SpaceSplitString& oldClasses = elementData()->classNames();
1150 if (checkSelectorForClassChange(oldClasses, featureSet))
1151 return true;
1152 }
1153 }
1154
1155 return featureSet.hasSelectorForAttribute(name.localName());
1156}
1157
1158// Returns true is the given attribute is an event handler.
1159// We consider an event handler any attribute that begins with "on".
1160// It is a simple solution that has the advantage of not requiring any
1161// code or configuration change if a new event handler is defined.
1162
1163static inline bool isEventHandlerAttribute(const Attribute& attribute)
1164{
1165 return attribute.name().namespaceURI().isNull() && attribute.name().localName().startsWith("on");
1166}
1167
1168bool Element::isJavaScriptURLAttribute(const Attribute& attribute) const
1169{
1170 return isURLAttribute(attribute) && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(attribute.value()));
1171}
1172
1173void Element::stripScriptingAttributes(Vector<Attribute>& attributeVector) const
1174{
1175 size_t destination = 0;
1176 for (size_t source = 0; source < attributeVector.size(); ++source) {
1177 if (isEventHandlerAttribute(attributeVector[source])
1178 || isJavaScriptURLAttribute(attributeVector[source])
1179 || isHTMLContentAttribute(attributeVector[source]))
1180 continue;
1181
1182 if (source != destination)
1183 attributeVector[destination] = attributeVector[source];
1184
1185 ++destination;
1186 }
1187 attributeVector.shrink(destination);
1188}
1189
1190void Element::parserSetAttributes(const Vector<Attribute>& attributeVector)
1191{
1192 ASSERT(!inDocument());
1193 ASSERT(!parentNode());
1194 ASSERT(!m_elementData);
1195
1196 if (attributeVector.isEmpty())
1197 return;
1198
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001199 if (document().sharedObjectPool())
1200 m_elementData = document().sharedObjectPool()->cachedShareableElementDataWithAttributes(attributeVector);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001201 else
1202 m_elementData = ShareableElementData::createWithAttributes(attributeVector);
1203
1204 // Use attributeVector instead of m_elementData because attributeChanged might modify m_elementData.
1205 for (unsigned i = 0; i < attributeVector.size(); ++i)
1206 attributeChangedFromParserOrByCloning(attributeVector[i].name(), attributeVector[i].value(), ModifiedDirectly);
1207}
1208
1209bool Element::hasAttributes() const
1210{
1211 synchronizeAllAttributes();
1212 return elementData() && elementData()->length();
1213}
1214
1215bool Element::hasEquivalentAttributes(const Element* other) const
1216{
1217 synchronizeAllAttributes();
1218 other->synchronizeAllAttributes();
1219 if (elementData() == other->elementData())
1220 return true;
1221 if (elementData())
1222 return elementData()->isEquivalent(other->elementData());
1223 if (other->elementData())
1224 return other->elementData()->isEquivalent(elementData());
1225 return true;
1226}
1227
1228String Element::nodeName() const
1229{
1230 return m_tagName.toString();
1231}
1232
1233String Element::nodeNamePreservingCase() const
1234{
1235 return m_tagName.toString();
1236}
1237
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001238void Element::setPrefix(const AtomicString& prefix, ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001239{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001240 checkSetPrefix(prefix, exceptionState);
1241 if (exceptionState.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001242 return;
1243
1244 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
1245}
1246
1247KURL Element::baseURI() const
1248{
1249 const AtomicString& baseAttribute = getAttribute(baseAttr);
1250 KURL base(KURL(), baseAttribute);
1251 if (!base.protocol().isEmpty())
1252 return base;
1253
1254 ContainerNode* parent = parentNode();
1255 if (!parent)
1256 return base;
1257
1258 const KURL& parentBase = parent->baseURI();
1259 if (parentBase.isNull())
1260 return base;
1261
1262 return KURL(parentBase, baseAttribute);
1263}
1264
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001265const AtomicString Element::imageSourceURL() const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001266{
1267 return getAttribute(srcAttr);
1268}
1269
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001270bool Element::rendererIsNeeded(const RenderStyle& style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001271{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001272 return style.display() != NONE;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001273}
1274
Ben Murdoch591b9582013-07-10 11:41:44 +01001275RenderObject* Element::createRenderer(RenderStyle* style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001276{
1277 return RenderObject::createObject(this, style);
1278}
1279
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001280Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertionPoint)
1281{
1282 // need to do superclass processing first so inDocument() is true
1283 // by the time we reach updateId
1284 ContainerNode::insertedInto(insertionPoint);
1285
1286 if (containsFullScreenElement() && parentElement() && !parentElement()->containsFullScreenElement())
1287 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
1288
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00001289 ASSERT(!hasRareData() || !elementRareData()->hasPseudoElements());
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001290
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001291 if (!insertionPoint->isInTreeScope())
1292 return InsertionDone;
1293
1294 if (hasRareData())
1295 elementRareData()->clearClassListValueForQuirksMode();
1296
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001297 if (isUpgradedCustomElement() && inDocument())
1298 CustomElement::didEnterDocument(this, document());
1299
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001300 TreeScope& scope = insertionPoint->treeScope();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001301 if (scope != treeScope())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001302 return InsertionDone;
1303
1304 const AtomicString& idValue = getIdAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001305 if (!idValue.isNull())
1306 updateId(scope, nullAtom, idValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001307
1308 const AtomicString& nameValue = getNameAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001309 if (!nameValue.isNull())
1310 updateName(nullAtom, nameValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001311
1312 if (hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001313 if (scope.shouldCacheLabelsByForAttribute())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001314 updateLabel(scope, nullAtom, fastGetAttribute(forAttr));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001315 }
1316
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001317 if (parentElement() && parentElement()->isInCanvasSubtree())
1318 setIsInCanvasSubtree(true);
1319
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001320 return InsertionDone;
1321}
1322
1323void Element::removedFrom(ContainerNode* insertionPoint)
1324{
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001325 bool wasInDocument = insertionPoint->inDocument();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001326
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00001327 ASSERT(!hasRareData() || !elementRareData()->hasPseudoElements());
Ben Murdoche69819b2013-07-17 14:56:49 +01001328
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001329 if (containsFullScreenElement())
1330 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
1331
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001332 if (document().page())
1333 document().page()->pointerLockController().elementRemoved(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001334
1335 setSavedLayerScrollOffset(IntSize());
1336
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001337 if (insertionPoint->isInTreeScope() && treeScope() == document()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001338 const AtomicString& idValue = getIdAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001339 if (!idValue.isNull())
1340 updateId(insertionPoint->treeScope(), idValue, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001341
1342 const AtomicString& nameValue = getNameAttribute();
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001343 if (!nameValue.isNull())
1344 updateName(nameValue, nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001345
1346 if (hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001347 TreeScope& treeScope = insertionPoint->treeScope();
1348 if (treeScope.shouldCacheLabelsByForAttribute())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01001349 updateLabel(treeScope, fastGetAttribute(forAttr), nullAtom);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001350 }
1351 }
1352
1353 ContainerNode::removedFrom(insertionPoint);
Ben Murdoche69819b2013-07-17 14:56:49 +01001354 if (wasInDocument) {
1355 if (hasPendingResources())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001356 document().accessSVGExtensions()->removeElementFromPendingResources(this);
Ben Murdoche69819b2013-07-17 14:56:49 +01001357
Ben Murdoch83750172013-07-24 10:36:59 +01001358 if (isUpgradedCustomElement())
Ben Murdochfff88842013-07-30 15:20:09 +01001359 CustomElement::didLeaveDocument(this, insertionPoint->document());
Ben Murdoche69819b2013-07-17 14:56:49 +01001360 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001361
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00001362 document().removeFromTopLayer(this);
1363
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001364 if (hasRareData())
1365 elementRareData()->setIsInCanvasSubtree(false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001366}
1367
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001368void Element::attach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001369{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001370 ASSERT(document().inStyleRecalc());
1371
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001372 StyleResolverParentPusher parentPusher(*this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001373
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001374 // We've already been through detach when doing an attach, but we might
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001375 // need to clear any state that's been added since then.
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001376 if (hasRareData() && styleChangeType() == NeedsReattachStyleChange) {
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001377 ElementRareData* data = elementRareData();
1378 data->clearComputedStyle();
1379 data->resetDynamicRestyleObservations();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001380 // Only clear the style state if we're not going to reuse the style from recalcStyle.
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001381 if (!context.resolvedStyle)
1382 data->resetStyleState();
1383 }
1384
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001385 NodeRenderingContext(this, context.resolvedStyle).createRendererForElementIfNeeded();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001386
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001387 addCallbackSelectors();
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001388
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001389 createPseudoElementIfNeeded(BEFORE);
1390
1391 // When a shadow root exists, it does the work of attaching the children.
1392 if (ElementShadow* shadow = this->shadow()) {
1393 parentPusher.push();
Ben Murdoch591b9582013-07-10 11:41:44 +01001394 shadow->attach(context);
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001395 } else if (firstChild()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001396 parentPusher.push();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001397 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001398
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001399 ContainerNode::attach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001400
1401 createPseudoElementIfNeeded(AFTER);
Ben Murdoche69819b2013-07-17 14:56:49 +01001402 createPseudoElementIfNeeded(BACKDROP);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001403
Ben Murdoch591b9582013-07-10 11:41:44 +01001404 if (hasRareData()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001405 ElementRareData* data = elementRareData();
1406 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001407 if (isFocusable() && document().focusedElement() == this)
1408 document().updateFocusAppearanceSoon(false /* don't restore selection */);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001409 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1410 }
1411 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001412
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001413 InspectorInstrumentation::didRecalculateStyleForElement(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001414}
1415
1416void Element::unregisterNamedFlowContentNode()
1417{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001418 if (RuntimeEnabledFeatures::cssRegionsEnabled() && inNamedFlow() && document().renderView())
1419 document().renderView()->flowThreadController()->unregisterNamedFlowContentNode(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001420}
1421
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001422void Element::detach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001423{
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001424 RenderWidget::UpdateSuspendScope suspendWidgetHierarchyUpdates;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001425 unregisterNamedFlowContentNode();
1426 cancelFocusAppearanceUpdate();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001427 removeCallbackSelectors();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001428 if (hasRareData()) {
1429 ElementRareData* data = elementRareData();
1430 data->setPseudoElement(BEFORE, 0);
1431 data->setPseudoElement(AFTER, 0);
Ben Murdoche69819b2013-07-17 14:56:49 +01001432 data->setPseudoElement(BACKDROP, 0);
Ben Murdoch591b9582013-07-10 11:41:44 +01001433 data->setIsInsideRegion(false);
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001434
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001435 // attach() will perform the below steps for us when inside recalcStyle.
1436 if (!document().inStyleRecalc()) {
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001437 data->resetStyleState();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001438 data->clearComputedStyle();
1439 data->resetDynamicRestyleObservations();
1440 }
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001441
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001442 if (RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
1443 if (ActiveAnimations* activeAnimations = data->activeAnimations()) {
1444 if (context.performingReattach) {
1445 // FIXME: restart compositor animations rather than pull back to the main thread
1446 activeAnimations->cancelAnimationOnCompositor();
1447 } else {
1448 activeAnimations->cssAnimations().cancel();
1449 }
1450 }
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001451 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001452 }
Ben Murdoch591b9582013-07-10 11:41:44 +01001453 if (ElementShadow* shadow = this->shadow())
1454 shadow->detach(context);
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001455 ContainerNode::detach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001456}
1457
1458bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle)
1459{
1460 ASSERT(currentStyle == renderStyle());
1461 ASSERT(renderer());
1462
1463 if (!currentStyle)
1464 return false;
1465
1466 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles();
1467 if (!pseudoStyleCache)
1468 return false;
1469
1470 size_t cacheSize = pseudoStyleCache->size();
1471 for (size_t i = 0; i < cacheSize; ++i) {
1472 RefPtr<RenderStyle> newPseudoStyle;
1473 PseudoId pseudoId = pseudoStyleCache->at(i)->styleType();
1474 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
1475 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle);
1476 else
1477 newPseudoStyle = renderer()->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
1478 if (!newPseudoStyle)
1479 return true;
1480 if (*newPseudoStyle != *pseudoStyleCache->at(i)) {
1481 if (pseudoId < FIRST_INTERNAL_PSEUDOID)
1482 newStyle->setHasPseudoStyle(pseudoId);
1483 newStyle->addCachedPseudoStyle(newPseudoStyle);
1484 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
1485 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001486 // is needed, but for now just assume a layout will be required. The diff code
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001487 // in RenderObject::setStyle would need to be factored out so that it could be reused.
1488 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
1489 }
1490 return true;
1491 }
1492 }
1493 return false;
1494}
1495
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001496PassRefPtr<RenderStyle> Element::styleForRenderer()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001497{
1498 if (hasCustomStyleCallbacks()) {
1499 if (RefPtr<RenderStyle> style = customStyleForRenderer())
1500 return style.release();
1501 }
1502
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001503 return originalStyleForRenderer();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001504}
1505
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001506PassRefPtr<RenderStyle> Element::originalStyleForRenderer()
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001507{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001508 return document().styleResolver()->styleForElement(this);
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001509}
1510
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001511void Element::recalcStyle(StyleRecalcChange change, Text* nextTextSibling)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001512{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001513 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001514 ASSERT(!parentOrShadowHostNode()->needsStyleRecalc());
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001515
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001516 if (hasCustomStyleCallbacks())
1517 willRecalcStyle(change);
1518
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001519 if (change >= Inherit || needsStyleRecalc()) {
1520 if (hasRareData()) {
1521 ElementRareData* data = elementRareData();
1522 data->resetStyleState();
1523 data->clearComputedStyle();
1524 }
1525 if (parentRenderStyle())
1526 change = recalcOwnStyle(change);
1527 clearNeedsStyleRecalc();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001528 }
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01001529
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001530 // If we reattached we don't need to recalc the style of our descendants anymore.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001531 if ((change >= Inherit && change < Reattach) || childNeedsStyleRecalc())
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001532 recalcChildStyle(change);
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001533 clearChildNeedsStyleRecalc();
Ben Murdoch591b9582013-07-10 11:41:44 +01001534
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001535 if (hasCustomStyleCallbacks())
1536 didRecalcStyle(change);
1537
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001538 if (change == Reattach)
1539 reattachWhitespaceSiblings(nextTextSibling);
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001540}
1541
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001542StyleRecalcChange Element::recalcOwnStyle(StyleRecalcChange change)
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001543{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001544 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001545 ASSERT(!parentOrShadowHostNode()->needsStyleRecalc());
1546 ASSERT(change >= Inherit || needsStyleRecalc());
1547 ASSERT(parentRenderStyle());
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001548
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001549 RefPtr<RenderStyle> oldStyle = renderStyle();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001550 RefPtr<RenderStyle> newStyle;
1551 {
1552 CSSAnimationUpdateScope cssAnimationUpdateScope(this);
1553 newStyle = styleForRenderer();
1554 }
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001555 StyleRecalcChange localChange = RenderStyle::compare(oldStyle.get(), newStyle.get());
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001556
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001557 ASSERT(newStyle);
1558
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001559 if (localChange == Reattach) {
1560 AttachContext reattachContext;
1561 reattachContext.resolvedStyle = newStyle.get();
1562 reattach(reattachContext);
1563 return Reattach;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001564 }
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001565
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001566 ASSERT(oldStyle);
1567
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001568 InspectorInstrumentation::didRecalculateStyleForElement(this);
1569
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001570 if (localChange != NoChange)
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001571 updateCallbackSelectors(oldStyle.get(), newStyle.get());
1572
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001573 if (RenderObject* renderer = this->renderer()) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001574 if (localChange != NoChange || pseudoStyleCacheIsInvalid(oldStyle.get(), newStyle.get()) || shouldNotifyRendererWithIdenticalStyles()) {
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001575 renderer->setAnimatableStyle(newStyle.get());
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001576 } else {
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001577 // Although no change occurred, we use the new style so that the cousin style sharing code won't get
1578 // fooled into believing this style is the same.
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001579 // FIXME: We may be able to remove this hack, see discussion in
1580 // https://codereview.chromium.org/30453002/
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001581 renderer->setStyleInternal(newStyle.get());
1582 }
1583 }
1584
1585 // 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
1586 // all the way down the tree. This is simpler than having to maintain a cache of objects (and such font size changes should be rare anyway).
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001587 if (document().styleEngine()->usesRemUnits() && document().documentElement() == this && oldStyle->fontSize() != newStyle->fontSize()) {
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001588 // Cached RenderStyles may depend on the re units.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001589 document().styleResolver()->invalidateMatchedPropertiesCache();
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001590 return Force;
1591 }
1592
1593 if (styleChangeType() >= SubtreeStyleChange)
1594 return Force;
1595
1596 return max(localChange, change);
1597}
1598
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001599void Element::recalcChildStyle(StyleRecalcChange change)
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001600{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001601 ASSERT(document().inStyleRecalc());
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001602 ASSERT(change >= Inherit || childNeedsStyleRecalc());
1603 ASSERT(!needsStyleRecalc());
Torne (Richard Coles)c0e19a62013-08-30 15:15:11 +01001604
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001605 StyleResolverParentPusher parentPusher(*this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001606
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001607 for (ShadowRoot* root = youngestShadowRoot(); root; root = root->olderShadowRoot()) {
1608 if (shouldRecalcStyle(change, root)) {
1609 parentPusher.push();
1610 root->recalcStyle(change);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001611 }
1612 }
1613
1614 if (shouldRecalcStyle(change, this))
1615 updatePseudoElement(BEFORE, change);
1616
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001617 if (change < Force && hasRareData() && childNeedsStyleRecalc())
1618 checkForChildrenAdjacentRuleChanges();
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001619
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001620 // This loop is deliberately backwards because we use insertBefore in the rendering tree, and want to avoid
1621 // a potentially n^2 loop to find the insertion point while resolving style. Having us start from the last
1622 // child and work our way back means in the common case, we'll find the insertion point in O(1) time.
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001623 // See crbug.com/288225
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001624 StyleResolver& styleResolver = *document().styleResolver();
1625 Text* lastTextNode = 0;
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001626 for (Node* child = lastChild(); child; child = child->previousSibling()) {
1627 if (child->isTextNode()) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001628 toText(child)->recalcTextStyle(change, lastTextNode);
1629 lastTextNode = toText(child);
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001630 } else if (child->isElementNode()) {
1631 Element* element = toElement(child);
Ben Murdoche69819b2013-07-17 14:56:49 +01001632 if (shouldRecalcStyle(change, element)) {
1633 parentPusher.push();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001634 element->recalcStyle(change, lastTextNode);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001635 } else if (element->supportsStyleSharing()) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001636 styleResolver.addToStyleSharingList(*element);
Ben Murdoche69819b2013-07-17 14:56:49 +01001637 }
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001638 if (element->renderer())
1639 lastTextNode = 0;
Ben Murdoch591b9582013-07-10 11:41:44 +01001640 }
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001641 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001642
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001643 if (shouldRecalcStyle(change, this)) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001644 updatePseudoElement(AFTER, change);
Torne (Richard Coles)e1f1df52013-08-23 16:39:30 +01001645 updatePseudoElement(BACKDROP, change);
1646 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001647}
1648
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001649void Element::checkForChildrenAdjacentRuleChanges()
1650{
1651 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
1652 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
1653
1654 if (!hasDirectAdjacentRules && !hasIndirectAdjacentRules)
1655 return;
1656
1657 unsigned forceCheckOfNextElementCount = 0;
1658 bool forceCheckOfAnyElementSibling = false;
1659
1660 for (Node* child = firstChild(); child; child = child->nextSibling()) {
1661 if (!child->isElementNode())
1662 continue;
1663 Element* element = toElement(child);
1664 bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() >= SubtreeStyleChange;
1665
1666 if (forceCheckOfNextElementCount || forceCheckOfAnyElementSibling)
1667 element->setNeedsStyleRecalc();
1668
1669 if (forceCheckOfNextElementCount)
1670 forceCheckOfNextElementCount--;
1671
1672 if (childRulesChanged && hasDirectAdjacentRules)
1673 forceCheckOfNextElementCount = document().styleEngine()->maxDirectAdjacentSelectors();
1674
1675 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
1676 }
1677}
1678
1679void Element::updateCallbackSelectors(RenderStyle* oldStyle, RenderStyle* newStyle)
1680{
1681 Vector<String> emptyVector;
1682 const Vector<String>& oldCallbackSelectors = oldStyle ? oldStyle->callbackSelectors() : emptyVector;
1683 const Vector<String>& newCallbackSelectors = newStyle ? newStyle->callbackSelectors() : emptyVector;
1684 if (oldCallbackSelectors.isEmpty() && newCallbackSelectors.isEmpty())
1685 return;
1686 if (oldCallbackSelectors != newCallbackSelectors)
1687 CSSSelectorWatch::from(document()).updateSelectorMatches(oldCallbackSelectors, newCallbackSelectors);
1688}
1689
1690void Element::addCallbackSelectors()
1691{
1692 updateCallbackSelectors(0, renderStyle());
1693}
1694
1695void Element::removeCallbackSelectors()
1696{
1697 updateCallbackSelectors(renderStyle(), 0);
1698}
1699
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001700ElementShadow* Element::shadow() const
1701{
1702 return hasRareData() ? elementRareData()->shadow() : 0;
1703}
1704
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001705ElementShadow& Element::ensureShadow()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001706{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001707 return ensureElementRareData().ensureShadow();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001708}
1709
1710void Element::didAffectSelector(AffectedSelectorMask mask)
1711{
1712 setNeedsStyleRecalc();
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00001713 if (ElementShadow* elementShadow = shadowWhereNodeCanBeDistributed(*this))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001714 elementShadow->didAffectSelector(mask);
1715}
1716
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001717PassRefPtr<ShadowRoot> Element::createShadowRoot(ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001718{
1719 if (alwaysCreateUserAgentShadowRoot())
1720 ensureUserAgentShadowRoot();
1721
1722 if (RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001723 return PassRefPtr<ShadowRoot>(ensureShadow().addShadowRoot(*this, ShadowRoot::AuthorShadowRoot));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001724
1725 // Since some elements recreates shadow root dynamically, multiple shadow
1726 // subtrees won't work well in that element. Until they are fixed, we disable
1727 // adding author shadow root for them.
1728 if (!areAuthorShadowsAllowed()) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001729 exceptionState.throwUninformativeAndGenericDOMException(HierarchyRequestError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001730 return 0;
1731 }
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001732 return PassRefPtr<ShadowRoot>(ensureShadow().addShadowRoot(*this, ShadowRoot::AuthorShadowRoot));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001733}
1734
1735ShadowRoot* Element::shadowRoot() const
1736{
1737 ElementShadow* elementShadow = shadow();
1738 if (!elementShadow)
1739 return 0;
1740 ShadowRoot* shadowRoot = elementShadow->youngestShadowRoot();
1741 if (shadowRoot->type() == ShadowRoot::AuthorShadowRoot)
1742 return shadowRoot;
1743 return 0;
1744}
1745
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001746void Element::didAddShadowRoot(ShadowRoot&)
1747{
1748}
1749
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001750ShadowRoot* Element::userAgentShadowRoot() const
1751{
1752 if (ElementShadow* elementShadow = shadow()) {
1753 if (ShadowRoot* shadowRoot = elementShadow->oldestShadowRoot()) {
1754 ASSERT(shadowRoot->type() == ShadowRoot::UserAgentShadowRoot);
1755 return shadowRoot;
1756 }
1757 }
1758
1759 return 0;
1760}
1761
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001762ShadowRoot& Element::ensureUserAgentShadowRoot()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001763{
1764 if (ShadowRoot* shadowRoot = userAgentShadowRoot())
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001765 return *shadowRoot;
1766 ShadowRoot& shadowRoot = ensureShadow().addShadowRoot(*this, ShadowRoot::UserAgentShadowRoot);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001767 didAddUserAgentShadowRoot(shadowRoot);
1768 return shadowRoot;
1769}
1770
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001771bool Element::childTypeAllowed(NodeType type) const
1772{
1773 switch (type) {
1774 case ELEMENT_NODE:
1775 case TEXT_NODE:
1776 case COMMENT_NODE:
1777 case PROCESSING_INSTRUCTION_NODE:
1778 case CDATA_SECTION_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001779 return true;
1780 default:
1781 break;
1782 }
1783 return false;
1784}
1785
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001786void Element::checkForEmptyStyleChange(RenderStyle* style)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001787{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001788 if (!style && !styleAffectedByEmpty())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001789 return;
1790
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001791 if (!style || (styleAffectedByEmpty() && (!style->emptyState() || hasChildNodes())))
1792 setNeedsStyleRecalc();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001793}
1794
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001795void Element::checkForSiblingStyleChanges(bool finishedParsingCallback, Node* beforeChange, Node* afterChange, int childCountDelta)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001796{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001797 if (!inActiveDocument() || document().hasPendingForcedStyleRecalc() || styleChangeType() >= SubtreeStyleChange)
Ben Murdoch83750172013-07-24 10:36:59 +01001798 return;
1799
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001800 RenderStyle* style = renderStyle();
Ben Murdoch591b9582013-07-10 11:41:44 +01001801
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001802 // :empty selector.
1803 checkForEmptyStyleChange(style);
1804
1805 if (!style || (needsStyleRecalc() && childrenAffectedByPositionalRules()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001806 return;
1807
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001808 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
1809 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1810 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
1811 // backward case.
1812 // |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.
1813 // 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 +01001814 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001815 if ((childrenAffectedByForwardPositionalRules() && afterChange) || (childrenAffectedByBackwardPositionalRules() && beforeChange)) {
1816 setNeedsStyleRecalc();
Ben Murdoch83750172013-07-24 10:36:59 +01001817 return;
1818 }
1819
1820 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1821 // In the DOM case, we only need to do something if |afterChange| is not 0.
1822 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001823 if (childrenAffectedByFirstChildRules() && afterChange) {
Ben Murdoch83750172013-07-24 10:36:59 +01001824 // Find our new first child.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001825 Node* newFirstChild = firstElementChild();
Ben Murdoch83750172013-07-24 10:36:59 +01001826 RenderStyle* newFirstChildStyle = newFirstChild ? newFirstChild->renderStyle() : 0;
1827
1828 // Find the first element node following |afterChange|
1829 Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling();
1830 RenderStyle* firstElementAfterInsertionStyle = firstElementAfterInsertion ? firstElementAfterInsertion->renderStyle() : 0;
1831
1832 // This is the insert/append case.
1833 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertionStyle && firstElementAfterInsertionStyle->firstChildState())
1834 firstElementAfterInsertion->setNeedsStyleRecalc();
1835
1836 // We also have to handle node removal.
1837 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChildStyle || !newFirstChildStyle->firstChildState()))
1838 newFirstChild->setNeedsStyleRecalc();
1839 }
1840
1841 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1842 // In the DOM case, we only need to do something if |afterChange| is not 0.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001843 if (childrenAffectedByLastChildRules() && beforeChange) {
Ben Murdoch83750172013-07-24 10:36:59 +01001844 // Find our new last child.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001845 Node* newLastChild = lastElementChild();
Ben Murdoch83750172013-07-24 10:36:59 +01001846 RenderStyle* newLastChildStyle = newLastChild ? newLastChild->renderStyle() : 0;
1847
1848 // Find the last element node going backwards from |beforeChange|
1849 Node* lastElementBeforeInsertion = beforeChange->isElementNode() ? beforeChange : beforeChange->previousElementSibling();
1850 RenderStyle* lastElementBeforeInsertionStyle = lastElementBeforeInsertion ? lastElementBeforeInsertion->renderStyle() : 0;
1851
1852 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertionStyle && lastElementBeforeInsertionStyle->lastChildState())
1853 lastElementBeforeInsertion->setNeedsStyleRecalc();
1854
1855 // 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
1856 // to match now.
1857 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChildStyle || !newLastChildStyle->lastChildState()))
1858 newLastChild->setNeedsStyleRecalc();
1859 }
1860
1861 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
1862 // that could be affected by this DOM change.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001863 if (childrenAffectedByDirectAdjacentRules() && afterChange) {
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001864 if (Node* firstElementAfterInsertion = afterChange->isElementNode() ? afterChange : afterChange->nextElementSibling())
Ben Murdoch83750172013-07-24 10:36:59 +01001865 firstElementAfterInsertion->setNeedsStyleRecalc();
1866 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001867}
1868
1869void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
1870{
1871 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
1872 if (changedByParser)
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001873 checkForEmptyStyleChange(renderStyle());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001874 else
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001875 checkForSiblingStyleChanges(false, beforeChange, afterChange, childCountDelta);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001876
Ben Murdoch83750172013-07-24 10:36:59 +01001877 if (ElementShadow* shadow = this->shadow())
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01001878 shadow->setNeedsDistributionRecalc();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001879}
1880
1881void Element::removeAllEventListeners()
1882{
1883 ContainerNode::removeAllEventListeners();
1884 if (ElementShadow* shadow = this->shadow())
1885 shadow->removeAllEventListeners();
1886}
1887
1888void Element::beginParsingChildren()
1889{
1890 clearIsParsingChildrenFinished();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001891}
1892
1893void Element::finishParsingChildren()
1894{
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001895 setIsParsingChildrenFinished();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001896 checkForSiblingStyleChanges(this, lastChild(), 0, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001897}
1898
1899#ifndef NDEBUG
1900void Element::formatForDebugger(char* buffer, unsigned length) const
1901{
1902 StringBuilder result;
1903 String s;
1904
1905 result.append(nodeName());
1906
1907 s = getIdAttribute();
1908 if (s.length() > 0) {
1909 if (result.length() > 0)
1910 result.appendLiteral("; ");
1911 result.appendLiteral("id=");
1912 result.append(s);
1913 }
1914
1915 s = getAttribute(classAttr);
1916 if (s.length() > 0) {
1917 if (result.length() > 0)
1918 result.appendLiteral("; ");
1919 result.appendLiteral("class=");
1920 result.append(s);
1921 }
1922
1923 strncpy(buffer, result.toString().utf8().data(), length - 1);
1924}
1925#endif
1926
1927const Vector<RefPtr<Attr> >& Element::attrNodeList()
1928{
1929 ASSERT(hasSyntheticAttrChildNodes());
1930 return *attrNodeListForElement(this);
1931}
1932
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001933PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001934{
1935 if (!attrNode) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001936 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001937 return 0;
1938 }
1939
1940 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName());
1941 if (oldAttrNode.get() == attrNode)
1942 return attrNode; // This Attr is already attached to the element.
1943
Ben Murdoche69819b2013-07-17 14:56:49 +01001944 // 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 +01001945 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
1946 if (attrNode->ownerElement()) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001947 exceptionState.throwUninformativeAndGenericDOMException(InUseAttributeError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001948 return 0;
1949 }
1950
1951 synchronizeAllAttributes();
1952 UniqueElementData* elementData = ensureUniqueElementData();
1953
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001954 size_t index = elementData->getAttributeItemIndex(attrNode->qualifiedName(), shouldIgnoreAttributeCase());
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001955 if (index != kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001956 if (oldAttrNode)
1957 detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData->attributeItem(index)->value());
1958 else
1959 oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), elementData->attributeItem(index)->value());
1960 }
1961
1962 setAttributeInternal(index, attrNode->qualifiedName(), attrNode->value(), NotInSynchronizationOfLazyAttribute);
1963
1964 attrNode->attachToElement(this);
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00001965 treeScope().adoptIfNeeded(*attrNode);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01001966 ensureAttrNodeListForElement(this).append(attrNode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001967
1968 return oldAttrNode.release();
1969}
1970
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001971PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001972{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001973 return setAttributeNode(attr, exceptionState);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001974}
1975
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001976PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001977{
1978 if (!attr) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001979 exceptionState.throwUninformativeAndGenericDOMException(TypeMismatchError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001980 return 0;
1981 }
1982 if (attr->ownerElement() != this) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001983 exceptionState.throwUninformativeAndGenericDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001984 return 0;
1985 }
1986
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01001987 ASSERT(document() == attr->document());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001988
1989 synchronizeAttribute(attr->qualifiedName());
1990
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001991 size_t index = elementData()->getAttrIndex(attr);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01001992 if (index == kNotFound) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00001993 exceptionState.throwUninformativeAndGenericDOMException(NotFoundError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001994 return 0;
1995 }
1996
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001997 RefPtr<Attr> guard(attr);
1998 detachAttrNodeAtIndex(attr, index);
1999 return guard.release();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002000}
2001
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002002bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002003{
2004 String prefix, localName;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002005 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, exceptionState))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002006 return false;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002007 ASSERT(!exceptionState.hadException());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002008
2009 QualifiedName qName(prefix, localName, namespaceURI);
2010
2011 if (!Document::hasValidNamespaceForAttributes(qName)) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002012 exceptionState.throwUninformativeAndGenericDOMException(NamespaceError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002013 return false;
2014 }
2015
2016 out = qName;
2017 return true;
2018}
2019
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002020void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002021{
2022 QualifiedName parsedName = anyName;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002023 if (!parseAttributeName(parsedName, namespaceURI, qualifiedName, exceptionState))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002024 return;
2025 setAttribute(parsedName, value);
2026}
2027
2028void Element::removeAttributeInternal(size_t index, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
2029{
2030 ASSERT_WITH_SECURITY_IMPLICATION(index < attributeCount());
2031
2032 UniqueElementData* elementData = ensureUniqueElementData();
2033
2034 QualifiedName name = elementData->attributeItem(index)->name();
2035 AtomicString valueBeingRemoved = elementData->attributeItem(index)->value();
2036
2037 if (!inSynchronizationOfLazyAttribute) {
2038 if (!valueBeingRemoved.isNull())
2039 willModifyAttribute(name, valueBeingRemoved, nullAtom);
2040 }
2041
2042 if (RefPtr<Attr> attrNode = attrIfExists(name))
2043 detachAttrNodeFromElementWithValue(attrNode.get(), elementData->attributeItem(index)->value());
2044
2045 elementData->removeAttribute(index);
2046
2047 if (!inSynchronizationOfLazyAttribute)
2048 didRemoveAttribute(name);
2049}
2050
2051void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
2052{
2053 if (!inSynchronizationOfLazyAttribute)
2054 willModifyAttribute(name, nullAtom, value);
2055 ensureUniqueElementData()->addAttribute(name, value);
2056 if (!inSynchronizationOfLazyAttribute)
2057 didAddAttribute(name, value);
2058}
2059
2060void Element::removeAttribute(const AtomicString& name)
2061{
2062 if (!elementData())
2063 return;
2064
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002065 AtomicString localName = shouldIgnoreAttributeCase() ? name.lower() : name;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002066 size_t index = elementData()->getAttributeItemIndex(localName, false);
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +01002067 if (index == kNotFound) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002068 if (UNLIKELY(localName == styleAttr) && elementData()->m_styleAttributeIsDirty && isStyledElement())
Ben Murdoch591b9582013-07-10 11:41:44 +01002069 removeAllInlineStyleProperties();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002070 return;
2071 }
2072
2073 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
2074}
2075
2076void Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName)
2077{
2078 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI));
2079}
2080
2081PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& localName)
2082{
2083 if (!elementData())
2084 return 0;
2085 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002086 const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002087 if (!attribute)
2088 return 0;
2089 return ensureAttr(attribute->name());
2090}
2091
2092PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
2093{
2094 if (!elementData())
2095 return 0;
2096 QualifiedName qName(nullAtom, localName, namespaceURI);
2097 synchronizeAttribute(qName);
2098 const Attribute* attribute = elementData()->getAttributeItem(qName);
2099 if (!attribute)
2100 return 0;
2101 return ensureAttr(attribute->name());
2102}
2103
2104bool Element::hasAttribute(const AtomicString& localName) const
2105{
2106 if (!elementData())
2107 return false;
2108 synchronizeAttribute(localName);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002109 return elementData()->getAttributeItem(shouldIgnoreAttributeCase() ? localName.lower() : localName, false);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002110}
2111
2112bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
2113{
2114 if (!elementData())
2115 return false;
2116 QualifiedName qName(nullAtom, localName, namespaceURI);
2117 synchronizeAttribute(qName);
2118 return elementData()->getAttributeItem(qName);
2119}
2120
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002121void Element::focus(bool restorePreviousSelection, FocusDirection direction)
2122{
2123 if (!inDocument())
2124 return;
2125
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002126 Document& doc = document();
2127 if (doc.focusedElement() == this)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002128 return;
2129
2130 // If the stylesheets have already been loaded we can reliably check isFocusable.
2131 // If not, we continue and set the focused node on the focus controller below so
Ben Murdoch591b9582013-07-10 11:41:44 +01002132 // that it can be updated soon after attach.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002133 if (doc.haveStylesheetsLoaded()) {
2134 doc.updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002135 if (!isFocusable())
2136 return;
2137 }
2138
2139 if (!supportsFocus())
2140 return;
2141
2142 RefPtr<Node> protect;
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002143 if (Page* page = doc.page()) {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002144 // Focus and change event handlers can cause us to lose our last ref.
2145 // If a focus event handler changes the focus to a different node it
2146 // does not make sense to continue and update appearence.
2147 protect = this;
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002148 if (!page->focusController().setFocusedElement(this, doc.frame(), direction))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002149 return;
2150 }
2151
2152 // Setting the focused node above might have invalidated the layout due to scripts.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002153 doc.updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002154
2155 if (!isFocusable()) {
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002156 ensureElementRareData().setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002157 return;
2158 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002159
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002160 cancelFocusAppearanceUpdate();
2161 updateFocusAppearance(restorePreviousSelection);
2162}
2163
2164void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
2165{
2166 if (isRootEditableElement()) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002167 Frame* frame = document().frame();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002168 if (!frame)
2169 return;
Ben Murdoch591b9582013-07-10 11:41:44 +01002170
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002171 // When focusing an editable element in an iframe, don't reset the selection if it already contains a selection.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002172 if (this == frame->selection().rootEditableElement())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002173 return;
2174
2175 // FIXME: We should restore the previous selection if there is one.
2176 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002177 frame->selection().setSelection(newSelection);
2178 frame->selection().revealSelection();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002179 } else if (renderer() && !renderer()->isWidget())
2180 renderer()->scrollRectToVisible(boundingBox());
2181}
2182
2183void Element::blur()
2184{
2185 cancelFocusAppearanceUpdate();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002186 if (treeScope().adjustedFocusedElement() == this) {
2187 Document& doc = document();
2188 if (doc.page())
2189 doc.page()->focusController().setFocusedElement(0, doc.frame());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002190 else
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002191 doc.setFocusedElement(0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002192 }
2193}
2194
Ben Murdochdf957042013-08-06 11:01:27 +01002195bool Element::isFocusable() const
2196{
2197 return inDocument() && supportsFocus() && !isInert() && rendererIsFocusable();
2198}
2199
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002200bool Element::isKeyboardFocusable() const
2201{
2202 return isFocusable() && tabIndex() >= 0;
2203}
2204
2205bool Element::isMouseFocusable() const
2206{
2207 return isFocusable();
2208}
2209
Ben Murdoch02772c62013-07-26 10:21:05 +01002210void Element::dispatchFocusEvent(Element* oldFocusedElement, FocusDirection)
2211{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002212 RefPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::focus, false, false, document().domWindow(), 0, oldFocusedElement);
Ben Murdoch02772c62013-07-26 10:21:05 +01002213 EventDispatcher::dispatchEvent(this, FocusEventDispatchMediator::create(event.release()));
2214}
2215
2216void Element::dispatchBlurEvent(Element* newFocusedElement)
2217{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002218 RefPtr<FocusEvent> event = FocusEvent::create(EventTypeNames::blur, false, false, document().domWindow(), 0, newFocusedElement);
Ben Murdoch02772c62013-07-26 10:21:05 +01002219 EventDispatcher::dispatchEvent(this, BlurEventDispatchMediator::create(event.release()));
2220}
2221
2222void Element::dispatchFocusInEvent(const AtomicString& eventType, Element* oldFocusedElement)
2223{
2224 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002225 ASSERT(eventType == EventTypeNames::focusin || eventType == EventTypeNames::DOMFocusIn);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002226 dispatchScopedEventDispatchMediator(FocusInEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document().domWindow(), 0, oldFocusedElement)));
Ben Murdoch02772c62013-07-26 10:21:05 +01002227}
2228
2229void Element::dispatchFocusOutEvent(const AtomicString& eventType, Element* newFocusedElement)
2230{
2231 ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01002232 ASSERT(eventType == EventTypeNames::focusout || eventType == EventTypeNames::DOMFocusOut);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002233 dispatchScopedEventDispatchMediator(FocusOutEventDispatchMediator::create(FocusEvent::create(eventType, true, false, document().domWindow(), 0, newFocusedElement)));
Ben Murdoch02772c62013-07-26 10:21:05 +01002234}
2235
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002236String Element::innerHTML() const
2237{
2238 return createMarkup(this, ChildrenOnly);
2239}
2240
2241String Element::outerHTML() const
2242{
2243 return createMarkup(this);
2244}
2245
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002246void Element::setInnerHTML(const String& html, ExceptionState& exceptionState)
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002247{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002248 if (RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(html, this, AllowScriptingContent, "innerHTML", exceptionState)) {
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002249 ContainerNode* container = this;
2250 if (hasTagName(templateTag))
2251 container = toHTMLTemplateElement(this)->content();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002252 replaceChildrenWithFragment(container, fragment.release(), exceptionState);
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002253 }
2254}
2255
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002256void Element::setOuterHTML(const String& html, ExceptionState& exceptionState)
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002257{
2258 Node* p = parentNode();
2259 if (!p || !p->isElementNode()) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002260 exceptionState.throwUninformativeAndGenericDOMException(NoModificationAllowedError);
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002261 return;
2262 }
2263 RefPtr<Element> parent = toElement(p);
2264 RefPtr<Node> prev = previousSibling();
2265 RefPtr<Node> next = nextSibling();
2266
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002267 RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(html, parent.get(), AllowScriptingContent, "outerHTML", exceptionState);
2268 if (exceptionState.hadException())
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002269 return;
2270
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002271 parent->replaceChild(fragment.release(), this, exceptionState);
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002272 RefPtr<Node> node = next ? next->previousSibling() : 0;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002273 if (!exceptionState.hadException() && node && node->isTextNode())
2274 mergeWithNextTextNode(node.release(), exceptionState);
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002275
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002276 if (!exceptionState.hadException() && prev && prev->isTextNode())
2277 mergeWithNextTextNode(prev.release(), exceptionState);
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002278}
2279
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002280String Element::innerText()
2281{
2282 // We need to update layout, since plainText uses line boxes in the render tree.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002283 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002284
2285 if (!renderer())
2286 return textContent(true);
2287
2288 return plainText(rangeOfContents(const_cast<Element*>(this)).get());
2289}
2290
2291String Element::outerText()
2292{
2293 // Getting outerText is the same as getting innerText, only
2294 // setting is different. You would think this should get the plain
2295 // text for the outer range, but this is wrong, <br> for instance
2296 // would return different values for inner and outer text by such
2297 // a rule, but it doesn't in WinIE, and we want to match that.
2298 return innerText();
2299}
2300
Ben Murdoch591b9582013-07-10 11:41:44 +01002301String Element::textFromChildren()
2302{
2303 Text* firstTextNode = 0;
2304 bool foundMultipleTextNodes = false;
2305 unsigned totalLength = 0;
2306
2307 for (Node* child = firstChild(); child; child = child->nextSibling()) {
2308 if (!child->isTextNode())
2309 continue;
2310 Text* text = toText(child);
2311 if (!firstTextNode)
2312 firstTextNode = text;
2313 else
2314 foundMultipleTextNodes = true;
2315 unsigned length = text->data().length();
2316 if (length > std::numeric_limits<unsigned>::max() - totalLength)
2317 return emptyString();
2318 totalLength += length;
2319 }
2320
2321 if (!firstTextNode)
2322 return emptyString();
2323
2324 if (firstTextNode && !foundMultipleTextNodes) {
2325 firstTextNode->atomize();
2326 return firstTextNode->data();
2327 }
2328
2329 StringBuilder content;
2330 content.reserveCapacity(totalLength);
2331 for (Node* child = firstTextNode; child; child = child->nextSibling()) {
2332 if (!child->isTextNode())
2333 continue;
2334 content.append(toText(child)->data());
2335 }
2336
2337 ASSERT(content.length() == totalLength);
2338 return content.toString();
2339}
2340
Ben Murdoch3c9e4ae2013-08-12 14:20:44 +01002341// pseudo is used via shadowPseudoId.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002342const AtomicString& Element::pseudo() const
2343{
2344 return getAttribute(pseudoAttr);
2345}
2346
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002347void Element::setPseudo(const AtomicString& value)
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002348{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002349 setAttribute(pseudoAttr, value);
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002350}
2351
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002352bool Element::isInDescendantTreeOf(const Element* shadowHost) const
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002353{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002354 ASSERT(shadowHost);
2355 ASSERT(isShadowHost(shadowHost));
2356
2357 const ShadowRoot* shadowRoot = containingShadowRoot();
2358 while (shadowRoot) {
2359 const Element* ancestorShadowHost = shadowRoot->shadowHost();
2360 if (ancestorShadowHost == shadowHost)
2361 return true;
2362 shadowRoot = ancestorShadowHost->containingShadowRoot();
2363 }
2364 return false;
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002365}
2366
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002367LayoutSize Element::minimumSizeForResizing() const
2368{
2369 return hasRareData() ? elementRareData()->minimumSizeForResizing() : defaultMinimumSizeForResizing();
2370}
2371
2372void Element::setMinimumSizeForResizing(const LayoutSize& size)
2373{
2374 if (!hasRareData() && size == defaultMinimumSizeForResizing())
2375 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002376 ensureElementRareData().setMinimumSizeForResizing(size);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002377}
2378
2379RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
2380{
2381 if (PseudoElement* element = pseudoElement(pseudoElementSpecifier))
2382 return element->computedStyle();
2383
2384 // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
2385 // properties, which are only known by the renderer because it did the layout, will be correct and so that the
2386 // values returned for the ":selection" pseudo-element will be correct.
2387 if (RenderStyle* usedStyle = renderStyle()) {
2388 if (pseudoElementSpecifier) {
2389 RenderStyle* cachedPseudoStyle = usedStyle->getCachedPseudoStyle(pseudoElementSpecifier);
2390 return cachedPseudoStyle ? cachedPseudoStyle : usedStyle;
2391 } else
2392 return usedStyle;
2393 }
2394
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00002395 if (!inActiveDocument())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002396 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
2397 // document tree and figure out when to destroy the computed style for such elements.
2398 return 0;
2399
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002400 ElementRareData& rareData = ensureElementRareData();
2401 if (!rareData.computedStyle())
2402 rareData.setComputedStyle(document().styleForElementIgnoringPendingStylesheets(this));
2403 return pseudoElementSpecifier ? rareData.computedStyle()->getCachedPseudoStyle(pseudoElementSpecifier) : rareData.computedStyle();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002404}
2405
2406void Element::setStyleAffectedByEmpty()
2407{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002408 ensureElementRareData().setStyleAffectedByEmpty(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002409}
2410
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002411void Element::setChildrenAffectedByFocus()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002412{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002413 ensureElementRareData().setChildrenAffectedByFocus(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002414}
2415
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002416void Element::setChildrenAffectedByHover()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002417{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002418 ensureElementRareData().setChildrenAffectedByHover(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002419}
2420
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002421void Element::setChildrenAffectedByActive()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002422{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002423 ensureElementRareData().setChildrenAffectedByActive(true);
2424}
2425
2426void Element::setChildrenAffectedByDrag()
2427{
2428 ensureElementRareData().setChildrenAffectedByDrag(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002429}
2430
2431void Element::setChildrenAffectedByFirstChildRules()
2432{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002433 ensureElementRareData().setChildrenAffectedByFirstChildRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002434}
2435
2436void Element::setChildrenAffectedByLastChildRules()
2437{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002438 ensureElementRareData().setChildrenAffectedByLastChildRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002439}
2440
2441void Element::setChildrenAffectedByDirectAdjacentRules()
2442{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002443 ensureElementRareData().setChildrenAffectedByDirectAdjacentRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002444}
2445
2446void Element::setChildrenAffectedByForwardPositionalRules()
2447{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002448 ensureElementRareData().setChildrenAffectedByForwardPositionalRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002449}
2450
2451void Element::setChildrenAffectedByBackwardPositionalRules()
2452{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002453 ensureElementRareData().setChildrenAffectedByBackwardPositionalRules(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002454}
2455
2456void Element::setChildIndex(unsigned index)
2457{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002458 ElementRareData& rareData = ensureElementRareData();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002459 if (RenderStyle* style = renderStyle())
2460 style->setUnique();
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002461 rareData.setChildIndex(index);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002462}
2463
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002464bool Element::childrenSupportStyleSharing() const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002465{
2466 if (!hasRareData())
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002467 return true;
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002468 return !rareDataChildrenAffectedByFocus()
2469 && !rareDataChildrenAffectedByHover()
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002470 && !rareDataChildrenAffectedByActive()
2471 && !rareDataChildrenAffectedByDrag()
2472 && !rareDataChildrenAffectedByFirstChildRules()
2473 && !rareDataChildrenAffectedByLastChildRules()
2474 && !rareDataChildrenAffectedByDirectAdjacentRules()
2475 && !rareDataChildrenAffectedByForwardPositionalRules()
2476 && !rareDataChildrenAffectedByBackwardPositionalRules();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002477}
2478
2479bool Element::rareDataStyleAffectedByEmpty() const
2480{
2481 ASSERT(hasRareData());
2482 return elementRareData()->styleAffectedByEmpty();
2483}
2484
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002485bool Element::rareDataChildrenAffectedByFocus() const
2486{
2487 ASSERT(hasRareData());
2488 return elementRareData()->childrenAffectedByFocus();
2489}
2490
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002491bool Element::rareDataChildrenAffectedByHover() const
2492{
2493 ASSERT(hasRareData());
2494 return elementRareData()->childrenAffectedByHover();
2495}
2496
2497bool Element::rareDataChildrenAffectedByActive() const
2498{
2499 ASSERT(hasRareData());
2500 return elementRareData()->childrenAffectedByActive();
2501}
2502
2503bool Element::rareDataChildrenAffectedByDrag() const
2504{
2505 ASSERT(hasRareData());
2506 return elementRareData()->childrenAffectedByDrag();
2507}
2508
2509bool Element::rareDataChildrenAffectedByFirstChildRules() const
2510{
2511 ASSERT(hasRareData());
2512 return elementRareData()->childrenAffectedByFirstChildRules();
2513}
2514
2515bool Element::rareDataChildrenAffectedByLastChildRules() const
2516{
2517 ASSERT(hasRareData());
2518 return elementRareData()->childrenAffectedByLastChildRules();
2519}
2520
2521bool Element::rareDataChildrenAffectedByDirectAdjacentRules() const
2522{
2523 ASSERT(hasRareData());
2524 return elementRareData()->childrenAffectedByDirectAdjacentRules();
2525}
2526
2527bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
2528{
2529 ASSERT(hasRareData());
2530 return elementRareData()->childrenAffectedByForwardPositionalRules();
2531}
2532
2533bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
2534{
2535 ASSERT(hasRareData());
2536 return elementRareData()->childrenAffectedByBackwardPositionalRules();
2537}
2538
2539unsigned Element::rareDataChildIndex() const
2540{
2541 ASSERT(hasRareData());
2542 return elementRareData()->childIndex();
2543}
2544
2545void Element::setIsInCanvasSubtree(bool isInCanvasSubtree)
2546{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002547 ensureElementRareData().setIsInCanvasSubtree(isInCanvasSubtree);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002548}
2549
2550bool Element::isInCanvasSubtree() const
2551{
2552 return hasRareData() && elementRareData()->isInCanvasSubtree();
2553}
2554
Ben Murdoch591b9582013-07-10 11:41:44 +01002555void Element::setIsInsideRegion(bool value)
2556{
2557 if (value == isInsideRegion())
2558 return;
2559
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002560 ensureElementRareData().setIsInsideRegion(value);
Ben Murdoch591b9582013-07-10 11:41:44 +01002561}
2562
2563bool Element::isInsideRegion() const
2564{
2565 return hasRareData() ? elementRareData()->isInsideRegion() : false;
2566}
2567
2568void Element::setRegionOversetState(RegionOversetState state)
2569{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002570 ensureElementRareData().setRegionOversetState(state);
Ben Murdoch591b9582013-07-10 11:41:44 +01002571}
2572
2573RegionOversetState Element::regionOversetState() const
2574{
2575 return hasRareData() ? elementRareData()->regionOversetState() : RegionUndefined;
2576}
2577
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002578AtomicString Element::computeInheritedLanguage() const
2579{
2580 const Node* n = this;
2581 AtomicString value;
2582 // The language property is inherited, so we iterate over the parents to find the first language.
2583 do {
2584 if (n->isElementNode()) {
2585 if (const ElementData* elementData = toElement(n)->elementData()) {
2586 // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7
2587 if (const Attribute* attribute = elementData->getAttributeItem(XMLNames::langAttr))
2588 value = attribute->value();
2589 else if (const Attribute* attribute = elementData->getAttributeItem(HTMLNames::langAttr))
2590 value = attribute->value();
2591 }
2592 } else if (n->isDocumentNode()) {
2593 // checking the MIME content-language
2594 value = toDocument(n)->contentLanguage();
2595 }
2596
2597 n = n->parentNode();
2598 } while (n && value.isNull());
2599
2600 return value;
2601}
2602
2603Locale& Element::locale() const
2604{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002605 return document().getCachedLocale(computeInheritedLanguage());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002606}
2607
2608void Element::cancelFocusAppearanceUpdate()
2609{
2610 if (hasRareData())
2611 elementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002612 if (document().focusedElement() == this)
2613 document().cancelFocusAppearanceUpdate();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002614}
2615
2616void Element::normalizeAttributes()
2617{
2618 if (!hasAttributes())
2619 return;
2620 for (unsigned i = 0; i < attributeCount(); ++i) {
2621 if (RefPtr<Attr> attr = attrIfExists(attributeItem(i)->name()))
2622 attr->normalize();
2623 }
2624}
2625
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002626void Element::updatePseudoElement(PseudoId pseudoId, StyleRecalcChange change)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002627{
2628 PseudoElement* element = pseudoElement(pseudoId);
2629 if (element && (needsStyleRecalc() || shouldRecalcStyle(change, element))) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002630 // Need to clear the cached style if the PseudoElement wants a recalc so it
2631 // computes a new style.
2632 if (element->needsStyleRecalc())
2633 renderer()->style()->removeCachedPseudoStyle(pseudoId);
2634
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002635 // PseudoElement styles hang off their parent element's style so if we needed
2636 // a style recalc we should Force one on the pseudo.
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002637 // FIXME: We should figure out the right text sibling to pass.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002638 element->recalcStyle(needsStyleRecalc() ? Force : change);
2639
2640 // Wait until our parent is not displayed or pseudoElementRendererIsNeeded
2641 // is false, otherwise we could continously create and destroy PseudoElements
2642 // when RenderObject::isChildAllowed on our parent returns false for the
2643 // PseudoElement's renderer for each style recalc.
2644 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01002645 elementRareData()->setPseudoElement(pseudoId, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002646 } else if (change >= Inherit || needsStyleRecalc())
2647 createPseudoElementIfNeeded(pseudoId);
2648}
2649
2650void Element::createPseudoElementIfNeeded(PseudoId pseudoId)
2651{
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002652 if (needsPseudoElement(pseudoId))
2653 createPseudoElement(pseudoId);
2654}
2655
2656bool Element::needsPseudoElement(PseudoId pseudoId) const
2657{
Ben Murdoche69819b2013-07-17 14:56:49 +01002658 if (pseudoId == BACKDROP && !isInTopLayer())
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002659 return false;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002660 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002661 return false;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002662 if (!renderer()->canHaveGeneratedChildren())
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002663 return false;
2664 return true;
2665}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002666
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +01002667void Element::createPseudoElement(PseudoId pseudoId)
2668{
2669 ASSERT(needsPseudoElement(pseudoId));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002670 ASSERT(!isPseudoElement());
2671 RefPtr<PseudoElement> element = PseudoElement::create(this, pseudoId);
Ben Murdoche69819b2013-07-17 14:56:49 +01002672 if (pseudoId == BACKDROP)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002673 document().addToTopLayer(element.get(), this);
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002674 element->insertedInto(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002675 element->attach();
Ben Murdoche69819b2013-07-17 14:56:49 +01002676
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002677 InspectorInstrumentation::pseudoElementCreated(element.get());
2678
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002679 ensureElementRareData().setPseudoElement(pseudoId, element.release());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002680}
2681
2682PseudoElement* Element::pseudoElement(PseudoId pseudoId) const
2683{
2684 return hasRareData() ? elementRareData()->pseudoElement(pseudoId) : 0;
2685}
2686
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002687RenderObject* Element::pseudoElementRenderer(PseudoId pseudoId) const
2688{
2689 if (PseudoElement* element = pseudoElement(pseudoId))
2690 return element->renderer();
2691 return 0;
2692}
2693
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002694bool Element::webkitMatchesSelector(const String& selector, ExceptionState& exceptionState)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002695{
2696 if (selector.isEmpty()) {
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002697 exceptionState.throwUninformativeAndGenericDOMException(SyntaxError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002698 return false;
2699 }
2700
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002701 SelectorQuery* selectorQuery = document().selectorQueryCache().add(selector, document(), exceptionState);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002702 if (!selectorQuery)
2703 return false;
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00002704 return selectorQuery->matches(*this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002705}
2706
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002707DOMTokenList* Element::classList()
2708{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002709 ElementRareData& rareData = ensureElementRareData();
2710 if (!rareData.classList())
2711 rareData.setClassList(ClassList::create(this));
2712 return rareData.classList();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002713}
2714
2715DOMStringMap* Element::dataset()
2716{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002717 ElementRareData& rareData = ensureElementRareData();
2718 if (!rareData.dataset())
2719 rareData.setDataset(DatasetDOMStringMap::create(this));
2720 return rareData.dataset();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002721}
2722
2723KURL Element::getURLAttribute(const QualifiedName& name) const
2724{
2725#if !ASSERT_DISABLED
2726 if (elementData()) {
2727 if (const Attribute* attribute = getAttributeItem(name))
2728 ASSERT(isURLAttribute(*attribute));
2729 }
2730#endif
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002731 return document().completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002732}
2733
2734KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
2735{
2736#if !ASSERT_DISABLED
2737 if (elementData()) {
2738 if (const Attribute* attribute = getAttributeItem(name))
2739 ASSERT(isURLAttribute(*attribute));
2740 }
2741#endif
2742 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
2743 if (value.isEmpty())
2744 return KURL();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002745 return document().completeURL(value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002746}
2747
2748int Element::getIntegralAttribute(const QualifiedName& attributeName) const
2749{
2750 return getAttribute(attributeName).string().toInt();
2751}
2752
2753void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
2754{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002755 setAttribute(attributeName, AtomicString::number(value));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002756}
2757
2758unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
2759{
2760 return getAttribute(attributeName).string().toUInt();
2761}
2762
2763void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
2764{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002765 setAttribute(attributeName, AtomicString::number(value));
2766}
2767
2768double Element::getFloatingPointAttribute(const QualifiedName& attributeName, double fallbackValue) const
2769{
2770 return parseToDoubleForNumberType(getAttribute(attributeName), fallbackValue);
2771}
2772
2773void Element::setFloatingPointAttribute(const QualifiedName& attributeName, double value)
2774{
2775 setAttribute(attributeName, AtomicString::number(value));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002776}
2777
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002778bool Element::childShouldCreateRenderer(const Node& child) const
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002779{
2780 // Only create renderers for SVG elements whose parents are SVG elements, or for proper <svg xmlns="svgNS"> subdocuments.
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002781 if (child.isSVGElement())
2782 return child.hasTagName(SVGNames::svgTag) || isSVGElement();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002783
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002784 return ContainerNode::childShouldCreateRenderer(child);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002785}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002786
2787void Element::webkitRequestFullscreen()
2788{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002789 FullscreenElementStack::from(&document())->requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002790}
2791
2792void Element::webkitRequestFullScreen(unsigned short flags)
2793{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002794 FullscreenElementStack::from(&document())->requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), FullscreenElementStack::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002795}
2796
2797bool Element::containsFullScreenElement() const
2798{
2799 return hasRareData() && elementRareData()->containsFullScreenElement();
2800}
2801
2802void Element::setContainsFullScreenElement(bool flag)
2803{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002804 ensureElementRareData().setContainsFullScreenElement(flag);
Ben Murdoche69819b2013-07-17 14:56:49 +01002805 setNeedsStyleRecalc(SubtreeStyleChange);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002806}
2807
2808static Element* parentCrossingFrameBoundaries(Element* element)
2809{
2810 ASSERT(element);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002811 return element->parentElement() ? element->parentElement() : element->document().ownerElement();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002812}
2813
2814void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool flag)
2815{
2816 Element* element = this;
2817 while ((element = parentCrossingFrameBoundaries(element)))
2818 element->setContainsFullScreenElement(flag);
2819}
2820
2821bool Element::isInTopLayer() const
2822{
2823 return hasRareData() && elementRareData()->isInTopLayer();
2824}
2825
2826void Element::setIsInTopLayer(bool inTopLayer)
2827{
2828 if (isInTopLayer() == inTopLayer)
2829 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01002830 ensureElementRareData().setIsInTopLayer(inTopLayer);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002831
2832 // We must ensure a reattach occurs so the renderer is inserted in the correct sibling order under RenderView according to its
2833 // top layer position, or in its usual place if not in the top layer.
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002834 lazyReattachIfAttached();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002835}
2836
2837void Element::webkitRequestPointerLock()
2838{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002839 if (document().page())
2840 document().page()->pointerLockController().requestPointerLock(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002841}
2842
2843SpellcheckAttributeState Element::spellcheckAttributeState() const
2844{
2845 const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
2846 if (value == nullAtom)
2847 return SpellcheckAttributeDefault;
2848 if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
2849 return SpellcheckAttributeTrue;
2850 if (equalIgnoringCase(value, "false"))
2851 return SpellcheckAttributeFalse;
2852
2853 return SpellcheckAttributeDefault;
2854}
2855
2856bool Element::isSpellCheckingEnabled() const
2857{
2858 for (const Element* element = this; element; element = element->parentOrShadowHostElement()) {
2859 switch (element->spellcheckAttributeState()) {
2860 case SpellcheckAttributeTrue:
2861 return true;
2862 case SpellcheckAttributeFalse:
2863 return false;
2864 case SpellcheckAttributeDefault:
2865 break;
2866 }
2867 }
2868
2869 return true;
2870}
2871
2872RenderRegion* Element::renderRegion() const
2873{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002874 if (renderer() && renderer()->isRenderNamedFlowFragmentContainer())
2875 return toRenderBlockFlow(renderer())->renderNamedFlowFragment();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002876
2877 return 0;
2878}
2879
Ben Murdoch591b9582013-07-10 11:41:44 +01002880bool Element::shouldMoveToFlowThread(RenderStyle* styleToUse) const
2881{
2882 ASSERT(styleToUse);
2883
Torne (Richard Coles)f5e4ad52013-08-05 13:57:57 +01002884 if (FullscreenElementStack::isActiveFullScreenElement(this))
Ben Murdoch591b9582013-07-10 11:41:44 +01002885 return false;
2886
2887 if (isInShadowTree())
2888 return false;
2889
2890 if (styleToUse->flowThread().isEmpty())
2891 return false;
2892
2893 return !isRegisteredWithNamedFlow();
2894}
2895
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002896const AtomicString& Element::webkitRegionOverset() const
2897{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002898 DEFINE_STATIC_LOCAL(AtomicString, undefinedState, ("undefined", AtomicString::ConstructFromLiteral));
2899 if (!RuntimeEnabledFeatures::cssRegionsEnabled())
2900 return undefinedState;
2901
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002902 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002903
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002904 if (!renderRegion())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002905 return undefinedState;
2906
Ben Murdoch591b9582013-07-10 11:41:44 +01002907 switch (renderRegion()->regionOversetState()) {
2908 case RegionFit: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002909 DEFINE_STATIC_LOCAL(AtomicString, fitState, ("fit", AtomicString::ConstructFromLiteral));
2910 return fitState;
2911 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002912 case RegionEmpty: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002913 DEFINE_STATIC_LOCAL(AtomicString, emptyState, ("empty", AtomicString::ConstructFromLiteral));
2914 return emptyState;
2915 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002916 case RegionOverset: {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002917 DEFINE_STATIC_LOCAL(AtomicString, overflowState, ("overset", AtomicString::ConstructFromLiteral));
2918 return overflowState;
2919 }
Ben Murdoch591b9582013-07-10 11:41:44 +01002920 case RegionUndefined:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002921 return undefinedState;
2922 }
2923
2924 ASSERT_NOT_REACHED();
2925 return undefinedState;
2926}
2927
2928Vector<RefPtr<Range> > Element::webkitGetRegionFlowRanges() const
2929{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002930 Vector<RefPtr<Range> > rangeObjects;
2931 if (!RuntimeEnabledFeatures::cssRegionsEnabled())
2932 return rangeObjects;
2933
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002934 document().updateLayoutIgnorePendingStylesheets();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002935
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00002936 if (renderer() && renderer()->isRenderNamedFlowFragmentContainer()) {
2937 RenderNamedFlowFragment* region = toRenderBlockFlow(renderer())->renderNamedFlowFragment();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002938 if (region->isValid())
2939 region->getRanges(rangeObjects);
2940 }
2941
2942 return rangeObjects;
2943}
2944
2945#ifndef NDEBUG
2946bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
2947{
2948 if (name == HTMLNames::styleAttr)
2949 return false;
2950
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002951 if (isSVGElement())
2952 return !static_cast<const SVGElement*>(this)->isAnimatableAttribute(name);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002953
2954 return true;
2955}
2956#endif
2957
2958#ifdef DUMP_NODE_STATISTICS
2959bool Element::hasNamedNodeMap() const
2960{
2961 return hasRareData() && elementRareData()->attributeMap();
2962}
2963#endif
2964
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002965inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002966{
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002967 if (!inDocument() || isInShadowTree())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002968 return;
2969
2970 if (oldName == newName)
2971 return;
2972
Ben Murdochdf957042013-08-06 11:01:27 +01002973 if (shouldRegisterAsNamedItem())
2974 updateNamedItemRegistration(oldName, newName);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002975}
2976
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002977inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002978{
2979 if (!isInTreeScope())
2980 return;
2981
2982 if (oldId == newId)
2983 return;
2984
Ben Murdoch00d3faa2013-08-14 11:52:03 +01002985 updateId(treeScope(), oldId, newId);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002986}
2987
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002988inline void Element::updateId(TreeScope& scope, const AtomicString& oldId, const AtomicString& newId)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002989{
2990 ASSERT(isInTreeScope());
2991 ASSERT(oldId != newId);
2992
2993 if (!oldId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002994 scope.removeElementById(oldId, this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002995 if (!newId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01002996 scope.addElementById(newId, this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002997
Ben Murdochdf957042013-08-06 11:01:27 +01002998 if (shouldRegisterAsExtraNamedItem())
2999 updateExtraNamedItemRegistration(oldId, newId);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003000}
3001
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003002void Element::updateLabel(TreeScope& scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003003{
3004 ASSERT(hasTagName(labelTag));
3005
3006 if (!inDocument())
3007 return;
3008
3009 if (oldForAttributeValue == newForAttributeValue)
3010 return;
3011
3012 if (!oldForAttributeValue.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003013 scope.removeLabel(oldForAttributeValue, toHTMLLabelElement(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003014 if (!newForAttributeValue.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003015 scope.addLabel(newForAttributeValue, toHTMLLabelElement(this));
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003016}
3017
Ben Murdoch7757ec22013-07-23 11:17:36 +01003018static bool hasSelectorForAttribute(Document* document, const AtomicString& localName)
3019{
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00003020 return document->styleResolver() && document->styleResolver()->ensureRuleFeatureSet().hasSelectorForAttribute(localName);
Ben Murdoch7757ec22013-07-23 11:17:36 +01003021}
3022
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003023void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
3024{
3025 if (isIdAttributeName(name))
3026 updateId(oldValue, newValue);
3027 else if (name == HTMLNames::nameAttr)
3028 updateName(oldValue, newValue);
3029 else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003030 TreeScope& scope = treeScope();
3031 if (scope.shouldCacheLabelsByForAttribute())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003032 updateLabel(scope, oldValue, newValue);
3033 }
3034
3035 if (oldValue != newValue) {
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003036 if (inActiveDocument() && hasSelectorForAttribute(&document(), name.localName()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003037 setNeedsStyleRecalc();
Ben Murdoche69819b2013-07-17 14:56:49 +01003038
3039 if (isUpgradedCustomElement())
Ben Murdoch83750172013-07-24 10:36:59 +01003040 CustomElement::attributeDidChange(this, name.localName(), oldValue, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003041 }
3042
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003043 if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(*this, name))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003044 recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue));
3045
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003046 InspectorInstrumentation::willModifyDOMAttr(this, oldValue, newValue);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003047}
3048
3049void Element::didAddAttribute(const QualifiedName& name, const AtomicString& value)
3050{
3051 attributeChanged(name, value);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003052 InspectorInstrumentation::didModifyDOMAttr(this, name.localName(), value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003053 dispatchSubtreeModifiedEvent();
3054}
3055
3056void Element::didModifyAttribute(const QualifiedName& name, const AtomicString& value)
3057{
3058 attributeChanged(name, value);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003059 InspectorInstrumentation::didModifyDOMAttr(this, name.localName(), value);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003060 // Do not dispatch a DOMSubtreeModified event here; see bug 81141.
3061}
3062
3063void Element::didRemoveAttribute(const QualifiedName& name)
3064{
3065 attributeChanged(name, nullAtom);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003066 InspectorInstrumentation::didRemoveDOMAttr(this, name.localName());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003067 dispatchSubtreeModifiedEvent();
3068}
3069
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01003070void Element::didMoveToNewDocument(Document& oldDocument)
Ben Murdoche69819b2013-07-17 14:56:49 +01003071{
3072 Node::didMoveToNewDocument(oldDocument);
3073
3074 // If the documents differ by quirks mode then they differ by case sensitivity
3075 // for class and id names so we need to go through the attribute change logic
3076 // to pick up the new casing in the ElementData.
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01003077 if (oldDocument.inQuirksMode() != document().inQuirksMode()) {
Ben Murdoche69819b2013-07-17 14:56:49 +01003078 if (hasID())
3079 setIdAttribute(getIdAttribute());
3080 if (hasClass())
3081 setAttribute(HTMLNames::classAttr, getClassAttribute());
3082 }
3083}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003084
Ben Murdochdf957042013-08-06 11:01:27 +01003085void Element::updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName)
3086{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003087 if (!document().isHTMLDocument())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01003088 return;
Ben Murdochdf957042013-08-06 11:01:27 +01003089
3090 if (!oldName.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003091 toHTMLDocument(document()).removeNamedItem(oldName);
Ben Murdochdf957042013-08-06 11:01:27 +01003092
3093 if (!newName.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003094 toHTMLDocument(document()).addNamedItem(newName);
Ben Murdochdf957042013-08-06 11:01:27 +01003095}
3096
3097void Element::updateExtraNamedItemRegistration(const AtomicString& oldId, const AtomicString& newId)
3098{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003099 if (!document().isHTMLDocument())
Ben Murdoch00d3faa2013-08-14 11:52:03 +01003100 return;
Ben Murdochdf957042013-08-06 11:01:27 +01003101
3102 if (!oldId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003103 toHTMLDocument(document()).removeExtraNamedItem(oldId);
Ben Murdochdf957042013-08-06 11:01:27 +01003104
3105 if (!newId.isEmpty())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003106 toHTMLDocument(document()).addExtraNamedItem(newId);
Ben Murdochdf957042013-08-06 11:01:27 +01003107}
3108
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003109PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
3110{
3111 if (HTMLCollection* collection = cachedHTMLCollection(type))
3112 return collection;
3113
3114 RefPtr<HTMLCollection> collection;
3115 if (type == TableRows) {
3116 ASSERT(hasTagName(tableTag));
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003117 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003118 } else if (type == SelectOptions) {
3119 ASSERT(hasTagName(selectTag));
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003120 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003121 } else if (type == FormControls) {
3122 ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003123 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003124 }
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003125 return ensureRareData().ensureNodeLists().addCacheWithAtomicName<HTMLCollection>(this, type);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003126}
3127
Ben Murdoch591b9582013-07-10 11:41:44 +01003128static void scheduleLayerUpdateCallback(Node* node)
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003129{
Ben Murdoche69819b2013-07-17 14:56:49 +01003130 // Notify the renderer even is the styles are identical since it may need to
3131 // create or destroy a RenderLayer.
3132 node->setNeedsStyleRecalc(LocalStyleChange, StyleChangeFromRenderer);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003133}
3134
Ben Murdoch591b9582013-07-10 11:41:44 +01003135void Element::scheduleLayerUpdate()
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003136{
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003137 if (document().inStyleRecalc())
3138 PostAttachCallbacks::queueCallback(scheduleLayerUpdateCallback, this);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003139 else
Ben Murdoche69819b2013-07-17 14:56:49 +01003140 scheduleLayerUpdateCallback(this);
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003141}
3142
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003143HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
3144{
3145 return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0;
3146}
3147
3148IntSize Element::savedLayerScrollOffset() const
3149{
3150 return hasRareData() ? elementRareData()->savedLayerScrollOffset() : IntSize();
3151}
3152
3153void Element::setSavedLayerScrollOffset(const IntSize& size)
3154{
3155 if (size.isZero() && !hasRareData())
3156 return;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003157 ensureElementRareData().setSavedLayerScrollOffset(size);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003158}
3159
3160PassRefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
3161{
3162 if (AttrNodeList* attrNodeList = attrNodeListForElement(this))
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003163 return findAttrNodeInList(*attrNodeList, name);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003164 return 0;
3165}
3166
3167PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name)
3168{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003169 AttrNodeList& attrNodeList = ensureAttrNodeListForElement(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003170 RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
3171 if (!attrNode) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003172 attrNode = Attr::create(*this, name);
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003173 treeScope().adoptIfNeeded(*attrNode);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003174 attrNodeList.append(attrNode);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003175 }
3176 return attrNode.release();
3177}
3178
3179void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value)
3180{
3181 ASSERT(hasSyntheticAttrChildNodes());
3182 attrNode->detachFromElementWithValue(value);
3183
3184 AttrNodeList* attrNodeList = attrNodeListForElement(this);
3185 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
3186 if (attrNodeList->at(i)->qualifiedName() == attrNode->qualifiedName()) {
3187 attrNodeList->remove(i);
3188 if (attrNodeList->isEmpty())
3189 removeAttrNodeListForElement(this);
3190 return;
3191 }
3192 }
3193 ASSERT_NOT_REACHED();
3194}
3195
3196void Element::detachAllAttrNodesFromElement()
3197{
3198 AttrNodeList* attrNodeList = attrNodeListForElement(this);
3199 ASSERT(attrNodeList);
3200
3201 for (unsigned i = 0; i < attributeCount(); ++i) {
3202 const Attribute* attribute = attributeItem(i);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003203 if (RefPtr<Attr> attrNode = findAttrNodeInList(*attrNodeList, attribute->name()))
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003204 attrNode->detachFromElementWithValue(attribute->value());
3205 }
3206
3207 removeAttrNodeListForElement(this);
3208}
3209
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003210void Element::willRecalcStyle(StyleRecalcChange)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003211{
3212 ASSERT(hasCustomStyleCallbacks());
3213}
3214
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003215void Element::didRecalcStyle(StyleRecalcChange)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003216{
3217 ASSERT(hasCustomStyleCallbacks());
3218}
3219
3220
3221PassRefPtr<RenderStyle> Element::customStyleForRenderer()
3222{
3223 ASSERT(hasCustomStyleCallbacks());
3224 return 0;
3225}
3226
3227void Element::cloneAttributesFromElement(const Element& other)
3228{
3229 if (hasSyntheticAttrChildNodes())
3230 detachAllAttrNodesFromElement();
3231
3232 other.synchronizeAllAttributes();
3233 if (!other.m_elementData) {
3234 m_elementData.clear();
3235 return;
3236 }
3237
3238 const AtomicString& oldID = getIdAttribute();
3239 const AtomicString& newID = other.getIdAttribute();
3240
3241 if (!oldID.isNull() || !newID.isNull())
3242 updateId(oldID, newID);
3243
3244 const AtomicString& oldName = getNameAttribute();
3245 const AtomicString& newName = other.getNameAttribute();
3246
3247 if (!oldName.isNull() || !newName.isNull())
3248 updateName(oldName, newName);
3249
Ben Murdoche69819b2013-07-17 14:56:49 +01003250 // Quirks mode makes class and id not case sensitive. We can't share the ElementData
3251 // if the idForStyleResolution and the className need different casing.
3252 bool ownerDocumentsHaveDifferentCaseSensitivity = false;
3253 if (other.hasClass() || other.hasID())
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003254 ownerDocumentsHaveDifferentCaseSensitivity = other.document().inQuirksMode() != document().inQuirksMode();
Ben Murdoche69819b2013-07-17 14:56:49 +01003255
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003256 // 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 +01003257 // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes,
3258 // and sharing the data won't result in different case sensitivity of class or id.
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003259 if (other.m_elementData->isUnique()
Ben Murdoche69819b2013-07-17 14:56:49 +01003260 && !ownerDocumentsHaveDifferentCaseSensitivity
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003261 && !other.m_elementData->presentationAttributeStyle()
3262 && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper()))
3263 const_cast<Element&>(other).m_elementData = static_cast<const UniqueElementData*>(other.m_elementData.get())->makeShareableCopy();
3264
Ben Murdoche69819b2013-07-17 14:56:49 +01003265 if (!other.m_elementData->isUnique() && !ownerDocumentsHaveDifferentCaseSensitivity)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003266 m_elementData = other.m_elementData;
3267 else
3268 m_elementData = other.m_elementData->makeUniqueCopy();
3269
3270 for (unsigned i = 0; i < m_elementData->length(); ++i) {
3271 const Attribute* attribute = const_cast<const ElementData*>(m_elementData.get())->attributeItem(i);
3272 attributeChangedFromParserOrByCloning(attribute->name(), attribute->value(), ModifiedByCloning);
3273 }
3274}
3275
3276void Element::cloneDataFromElement(const Element& other)
3277{
3278 cloneAttributesFromElement(other);
3279 copyNonAttributePropertiesFromElement(other);
3280}
3281
3282void Element::createUniqueElementData()
3283{
3284 if (!m_elementData)
3285 m_elementData = UniqueElementData::create();
3286 else {
3287 ASSERT(!m_elementData->isUnique());
3288 m_elementData = static_cast<ShareableElementData*>(m_elementData.get())->makeUniqueCopy();
3289 }
3290}
3291
Ben Murdoch1fad5ca2013-08-07 11:05:11 +01003292InputMethodContext* Element::inputMethodContext()
Torne (Richard Coles)81a51572013-05-13 16:52:28 +01003293{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003294 return ensureElementRareData().ensureInputMethodContext(toHTMLElement(this));
Torne (Richard Coles)81a51572013-05-13 16:52:28 +01003295}
3296
Torne (Richard Coles)19cde672013-11-06 12:28:04 +00003297bool Element::hasInputMethodContext() const
3298{
3299 return hasRareData() && elementRareData()->hasInputMethodContext();
3300}
3301
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003302bool Element::hasPendingResources() const
3303{
3304 return hasRareData() && elementRareData()->hasPendingResources();
3305}
3306
3307void Element::setHasPendingResources()
3308{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003309 ensureElementRareData().setHasPendingResources(true);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003310}
3311
3312void Element::clearHasPendingResources()
3313{
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003314 ensureElementRareData().setHasPendingResources(false);
Ben Murdoch591b9582013-07-10 11:41:44 +01003315}
3316
3317void Element::synchronizeStyleAttributeInternal() const
3318{
3319 ASSERT(isStyledElement());
3320 ASSERT(elementData());
3321 ASSERT(elementData()->m_styleAttributeIsDirty);
3322 elementData()->m_styleAttributeIsDirty = false;
3323 if (const StylePropertySet* inlineStyle = this->inlineStyle())
3324 const_cast<Element*>(this)->setSynchronizedLazyAttribute(styleAttr, inlineStyle->asText());
3325}
3326
3327CSSStyleDeclaration* Element::style()
3328{
3329 if (!isStyledElement())
3330 return 0;
3331 return ensureMutableInlineStyle()->ensureInlineCSSStyleDeclaration(this);
3332}
3333
3334MutableStylePropertySet* Element::ensureMutableInlineStyle()
3335{
3336 ASSERT(isStyledElement());
3337 RefPtr<StylePropertySet>& inlineStyle = ensureUniqueElementData()->m_inlineStyle;
Torne (Richard Coles)f79f16f2013-10-31 11:16:44 +00003338 if (!inlineStyle) {
3339 CSSParserMode mode = (!isHTMLElement() || document().inQuirksMode()) ? HTMLQuirksMode : HTMLStandardMode;
3340 inlineStyle = MutableStylePropertySet::create(mode);
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00003341 } else if (!inlineStyle->isMutable()) {
Ben Murdoch591b9582013-07-10 11:41:44 +01003342 inlineStyle = inlineStyle->mutableCopy();
Torne (Richard Coles)51b29062013-11-28 11:56:03 +00003343 }
3344 return toMutableStylePropertySet(inlineStyle);
Ben Murdoch591b9582013-07-10 11:41:44 +01003345}
3346
3347PropertySetCSSStyleDeclaration* Element::inlineStyleCSSOMWrapper()
3348{
3349 if (!inlineStyle() || !inlineStyle()->hasCSSOMWrapper())
3350 return 0;
3351 PropertySetCSSStyleDeclaration* cssomWrapper = ensureMutableInlineStyle()->cssStyleDeclaration();
3352 ASSERT(cssomWrapper && cssomWrapper->parentElement() == this);
3353 return cssomWrapper;
3354}
3355
3356inline void Element::setInlineStyleFromString(const AtomicString& newStyleString)
3357{
3358 ASSERT(isStyledElement());
3359 RefPtr<StylePropertySet>& inlineStyle = elementData()->m_inlineStyle;
3360
3361 // Avoid redundant work if we're using shared attribute data with already parsed inline style.
3362 if (inlineStyle && !elementData()->isUnique())
3363 return;
3364
3365 // We reconstruct the property set instead of mutating if there is no CSSOM wrapper.
3366 // This makes wrapperless property sets immutable and so cacheable.
3367 if (inlineStyle && !inlineStyle->isMutable())
3368 inlineStyle.clear();
3369
3370 if (!inlineStyle) {
3371 inlineStyle = CSSParser::parseInlineStyleDeclaration(newStyleString, this);
3372 } else {
3373 ASSERT(inlineStyle->isMutable());
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003374 static_pointer_cast<MutableStylePropertySet>(inlineStyle)->parseDeclaration(newStyleString, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003375 }
3376}
3377
3378void Element::styleAttributeChanged(const AtomicString& newStyleString, AttributeModificationReason modificationReason)
3379{
3380 ASSERT(isStyledElement());
3381 WTF::OrdinalNumber startLineNumber = WTF::OrdinalNumber::beforeFirst();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003382 if (document().scriptableDocumentParser() && !document().isInDocumentWrite())
3383 startLineNumber = document().scriptableDocumentParser()->lineNumber();
Ben Murdoch591b9582013-07-10 11:41:44 +01003384
3385 if (newStyleString.isNull()) {
3386 if (PropertySetCSSStyleDeclaration* cssomWrapper = inlineStyleCSSOMWrapper())
3387 cssomWrapper->clearParentElement();
3388 ensureUniqueElementData()->m_inlineStyle.clear();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003389 } else if (modificationReason == ModifiedByCloning || document().contentSecurityPolicy()->allowInlineStyle(document().url(), startLineNumber)) {
Ben Murdoch591b9582013-07-10 11:41:44 +01003390 setInlineStyleFromString(newStyleString);
3391 }
3392
3393 elementData()->m_styleAttributeIsDirty = false;
3394
Ben Murdoche69819b2013-07-17 14:56:49 +01003395 setNeedsStyleRecalc(LocalStyleChange);
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003396 InspectorInstrumentation::didInvalidateStyleAttr(this);
Ben Murdoch591b9582013-07-10 11:41:44 +01003397}
3398
3399void Element::inlineStyleChanged()
3400{
3401 ASSERT(isStyledElement());
Ben Murdoche69819b2013-07-17 14:56:49 +01003402 setNeedsStyleRecalc(LocalStyleChange);
Ben Murdoch591b9582013-07-10 11:41:44 +01003403 ASSERT(elementData());
3404 elementData()->m_styleAttributeIsDirty = true;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003405 InspectorInstrumentation::didInvalidateStyleAttr(this);
Ben Murdoch591b9582013-07-10 11:41:44 +01003406}
3407
3408bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSValueID identifier, bool important)
3409{
3410 ASSERT(isStyledElement());
3411 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
3412 inlineStyleChanged();
3413 return true;
3414}
3415
3416bool Element::setInlineStyleProperty(CSSPropertyID propertyID, CSSPropertyID identifier, bool important)
3417{
3418 ASSERT(isStyledElement());
3419 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier), important);
3420 inlineStyleChanged();
3421 return true;
3422}
3423
3424bool Element::setInlineStyleProperty(CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit, bool important)
3425{
3426 ASSERT(isStyledElement());
3427 ensureMutableInlineStyle()->setProperty(propertyID, cssValuePool().createValue(value, unit), important);
3428 inlineStyleChanged();
3429 return true;
3430}
3431
3432bool Element::setInlineStyleProperty(CSSPropertyID propertyID, const String& value, bool important)
3433{
3434 ASSERT(isStyledElement());
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003435 bool changes = ensureMutableInlineStyle()->setProperty(propertyID, value, important, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003436 if (changes)
3437 inlineStyleChanged();
3438 return changes;
3439}
3440
3441bool Element::removeInlineStyleProperty(CSSPropertyID propertyID)
3442{
3443 ASSERT(isStyledElement());
3444 if (!inlineStyle())
3445 return false;
3446 bool changes = ensureMutableInlineStyle()->removeProperty(propertyID);
3447 if (changes)
3448 inlineStyleChanged();
3449 return changes;
3450}
3451
3452void Element::removeAllInlineStyleProperties()
3453{
3454 ASSERT(isStyledElement());
3455 if (!inlineStyle() || inlineStyle()->isEmpty())
3456 return;
3457 ensureMutableInlineStyle()->clear();
3458 inlineStyleChanged();
3459}
3460
3461void Element::addSubresourceAttributeURLs(ListHashSet<KURL>& urls) const
3462{
3463 ASSERT(isStyledElement());
3464 if (const StylePropertySet* inlineStyle = elementData() ? elementData()->inlineStyle() : 0)
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01003465 inlineStyle->addSubresourceStyleURLs(urls, document().elementSheet()->contents());
Ben Murdoch591b9582013-07-10 11:41:44 +01003466}
3467
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003468void Element::updatePresentationAttributeStyle()
Ben Murdoch591b9582013-07-10 11:41:44 +01003469{
Ben Murdoch591b9582013-07-10 11:41:44 +01003470 // ShareableElementData doesn't store presentation attribute style, so make sure we have a UniqueElementData.
3471 UniqueElementData* elementData = ensureUniqueElementData();
Ben Murdoch591b9582013-07-10 11:41:44 +01003472 elementData->m_presentationAttributeStyleIsDirty = false;
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003473 elementData->m_presentationAttributeStyle = computePresentationAttributeStyle(*this);
Ben Murdoch591b9582013-07-10 11:41:44 +01003474}
3475
3476void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, CSSValueID identifier)
3477{
3478 ASSERT(isStyledElement());
3479 style->setProperty(propertyID, cssValuePool().createIdentifierValue(identifier));
3480}
3481
3482void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, double value, CSSPrimitiveValue::UnitTypes unit)
3483{
3484 ASSERT(isStyledElement());
3485 style->setProperty(propertyID, cssValuePool().createValue(value, unit));
3486}
3487
3488void Element::addPropertyToPresentationAttributeStyle(MutableStylePropertySet* style, CSSPropertyID propertyID, const String& value)
3489{
3490 ASSERT(isStyledElement());
Torne (Richard Coles)1e202182013-10-18 15:46:42 +01003491 style->setProperty(propertyID, value, false);
Ben Murdoch591b9582013-07-10 11:41:44 +01003492}
3493
Torne (Richard Coles)bfe35902013-10-22 16:41:51 +01003494bool Element::supportsStyleSharing() const
3495{
3496 if (!isStyledElement() || !parentElement())
3497 return false;
3498 // If the element has inline style it is probably unique.
3499 if (inlineStyle())
3500 return false;
3501 if (isSVGElement() && toSVGElement(this)->animatedSMILStyleProperties())
3502 return false;
3503 // Ids stop style sharing if they show up in the stylesheets.
3504 if (hasID() && document().styleResolver()->hasRulesForId(idForStyleResolution()))
3505 return false;
3506 // Active and hovered elements always make a chain towards the document node
3507 // and no siblings or cousins will have the same state.
3508 if (hovered())
3509 return false;
3510 if (active())
3511 return false;
3512 if (focused())
3513 return false;
3514 if (!parentElement()->childrenSupportStyleSharing())
3515 return false;
3516 if (hasScopedHTMLStyleChild())
3517 return false;
3518 if (this == document().cssTarget())
3519 return false;
3520 if (isHTMLElement() && toHTMLElement(this)->hasDirectionAuto())
3521 return false;
3522 if (hasActiveAnimations())
3523 return false;
3524 if (shadow() && shadow()->containsActiveStyles())
3525 return false;
3526 // Turn off style sharing for elements that can gain layers for reasons outside of the style system.
3527 // See comments in RenderObject::setStyle().
3528 // FIXME: Why does gaining a layer from outside the style system require disabling sharing?
3529 if (hasTagName(iframeTag)
3530 || hasTagName(frameTag)
3531 || hasTagName(embedTag)
3532 || hasTagName(objectTag)
3533 || hasTagName(appletTag)
3534 || hasTagName(canvasTag))
3535 return false;
3536 // FIXME: We should share style for option and optgroup whenever possible.
3537 // Before doing so, we need to resolve issues in HTMLSelectElement::recalcListItems
3538 // and RenderMenuList::setText. See also https://bugs.webkit.org/show_bug.cgi?id=88405
3539 if (hasTagName(optionTag) || hasTagName(optgroupTag))
3540 return false;
3541 if (FullscreenElementStack::isActiveFullScreenElement(this))
3542 return false;
3543 return true;
3544}
3545
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003546} // namespace WebCore