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