blob: bf2c5fcee479e35591e415c264c45e514a49ddf0 [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
29#include "HTMLNames.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010030#include "SVGNames.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010031#include "XMLNames.h"
32#include "core/accessibility/AXObjectCache.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010033#include "core/css/StylePropertySet.h"
Torne (Richard Coles)81a51572013-05-13 16:52:28 +010034#include "core/css/resolver/StyleResolver.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010035#include "core/dom/Attr.h"
36#include "core/dom/ClientRect.h"
37#include "core/dom/ClientRectList.h"
38#include "core/dom/CustomElementRegistry.h"
39#include "core/dom/DatasetDOMStringMap.h"
40#include "core/dom/Document.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010041#include "core/dom/DocumentSharedObjectPool.h"
42#include "core/dom/ElementRareData.h"
43#include "core/dom/ExceptionCode.h"
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +010044#include "core/dom/FullscreenController.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010045#include "core/dom/MutationObserverInterestGroup.h"
46#include "core/dom/MutationRecord.h"
47#include "core/dom/NamedNodeMap.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010048#include "core/dom/NodeRenderStyle.h"
49#include "core/dom/NodeRenderingContext.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010050#include "core/dom/PseudoElement.h"
51#include "core/dom/SelectorQuery.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010052#include "core/dom/Text.h"
53#include "core/dom/WebCoreMemoryInstrumentation.h"
Torne (Richard Coles)e5249552013-05-15 11:35:13 +010054#include "core/dom/shadow/InsertionPoint.h"
55#include "core/dom/shadow/ShadowRoot.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010056#include "core/editing/FrameSelection.h"
57#include "core/editing/TextIterator.h"
58#include "core/editing/htmlediting.h"
59#include "core/html/ClassList.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010060#include "core/html/HTMLCollection.h"
61#include "core/html/HTMLDocument.h"
62#include "core/html/HTMLElement.h"
63#include "core/html/HTMLFormControlsCollection.h"
64#include "core/html/HTMLFrameOwnerElement.h"
65#include "core/html/HTMLLabelElement.h"
66#include "core/html/HTMLOptionsCollection.h"
67#include "core/html/HTMLTableRowsCollection.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010068#include "core/html/parser/HTMLParserIdioms.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010069#include "core/page/FocusController.h"
70#include "core/page/Frame.h"
71#include "core/page/FrameView.h"
72#include "core/page/Page.h"
73#include "core/page/PointerLockController.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010074#include "core/rendering/FlowThreadController.h"
75#include "core/rendering/RenderRegion.h"
76#include "core/rendering/RenderView.h"
77#include "core/rendering/RenderWidget.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010078#include "core/svg/SVGDocumentExtensions.h"
79#include "core/svg/SVGElement.h"
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +010080#include "wtf/BitVector.h"
81#include "wtf/MemoryInstrumentationVector.h"
82#include "wtf/text/CString.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010083
84namespace WebCore {
85
86using namespace HTMLNames;
87using namespace XMLNames;
88
89static inline bool shouldIgnoreAttributeCase(const Element* e)
90{
91 return e && e->document()->isHTMLDocument() && e->isHTMLElement();
92}
93
94class StyleResolverParentPusher {
95public:
96 StyleResolverParentPusher(Element* parent)
97 : m_parent(parent)
98 , m_pushedStyleResolver(0)
99 {
100 }
101 void push()
102 {
103 if (m_pushedStyleResolver)
104 return;
105 m_pushedStyleResolver = m_parent->document()->styleResolver();
106 m_pushedStyleResolver->pushParentElement(m_parent);
107 }
108 ~StyleResolverParentPusher()
109 {
110
111 if (!m_pushedStyleResolver)
112 return;
113
114 // This tells us that our pushed style selector is in a bad state,
115 // so we should just bail out in that scenario.
116 ASSERT(m_pushedStyleResolver == m_parent->document()->styleResolver());
117 if (m_pushedStyleResolver != m_parent->document()->styleResolver())
118 return;
119
120 m_pushedStyleResolver->popParentElement(m_parent);
121 }
122
123private:
124 Element* m_parent;
125 StyleResolver* m_pushedStyleResolver;
126};
127
128typedef Vector<RefPtr<Attr> > AttrNodeList;
129typedef HashMap<Element*, OwnPtr<AttrNodeList> > AttrNodeListMap;
130
131static AttrNodeListMap& attrNodeListMap()
132{
133 DEFINE_STATIC_LOCAL(AttrNodeListMap, map, ());
134 return map;
135}
136
137static AttrNodeList* attrNodeListForElement(Element* element)
138{
139 if (!element->hasSyntheticAttrChildNodes())
140 return 0;
141 ASSERT(attrNodeListMap().contains(element));
142 return attrNodeListMap().get(element);
143}
144
145static AttrNodeList* ensureAttrNodeListForElement(Element* element)
146{
147 if (element->hasSyntheticAttrChildNodes()) {
148 ASSERT(attrNodeListMap().contains(element));
149 return attrNodeListMap().get(element);
150 }
151 ASSERT(!attrNodeListMap().contains(element));
152 element->setHasSyntheticAttrChildNodes(true);
153 AttrNodeListMap::AddResult result = attrNodeListMap().add(element, adoptPtr(new AttrNodeList));
154 return result.iterator->value.get();
155}
156
157static void removeAttrNodeListForElement(Element* element)
158{
159 ASSERT(element->hasSyntheticAttrChildNodes());
160 ASSERT(attrNodeListMap().contains(element));
161 attrNodeListMap().remove(element);
162 element->setHasSyntheticAttrChildNodes(false);
163}
164
165static Attr* findAttrNodeInList(AttrNodeList* attrNodeList, const QualifiedName& name)
166{
167 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
168 if (attrNodeList->at(i)->qualifiedName() == name)
169 return attrNodeList->at(i).get();
170 }
171 return 0;
172}
173
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100174PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document)
175{
176 return adoptRef(new Element(tagName, document, CreateElement));
177}
178
179Element::~Element()
180{
181#ifndef NDEBUG
182 if (document() && document()->renderer()) {
183 // When the document is not destroyed, an element that was part of a named flow
184 // content nodes should have been removed from the content nodes collection
185 // and the inNamedFlow flag reset.
186 ASSERT(!inNamedFlow());
187 }
188#endif
189
190 if (hasRareData()) {
191 ElementRareData* data = elementRareData();
192 data->setPseudoElement(BEFORE, 0);
193 data->setPseudoElement(AFTER, 0);
194 data->clearShadow();
195 }
196
197 if (isCustomElement() && document() && document()->registry()) {
198 document()->registry()->customElementWasDestroyed(this);
199 }
200
201 if (hasSyntheticAttrChildNodes())
202 detachAllAttrNodesFromElement();
203
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100204 if (hasPendingResources()) {
205 document()->accessSVGExtensions()->removeElementFromPendingResources(this);
206 ASSERT(!hasPendingResources());
207 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100208}
209
210inline ElementRareData* Element::elementRareData() const
211{
212 ASSERT(hasRareData());
213 return static_cast<ElementRareData*>(rareData());
214}
215
216inline ElementRareData* Element::ensureElementRareData()
217{
218 return static_cast<ElementRareData*>(ensureRareData());
219}
220
221void Element::clearTabIndexExplicitlyIfNeeded()
222{
223 if (hasRareData())
224 elementRareData()->clearTabIndexExplicitly();
225}
226
227void Element::setTabIndexExplicitly(short tabIndex)
228{
229 ensureElementRareData()->setTabIndexExplicitly(tabIndex);
230}
231
232bool Element::supportsFocus() const
233{
234 return hasRareData() && elementRareData()->tabIndexSetExplicitly();
235}
236
237short Element::tabIndex() const
238{
239 return hasRareData() ? elementRareData()->tabIndex() : 0;
240}
241
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100242bool Element::rendererIsFocusable() const
243{
244 // Elements in canvas fallback content are not rendered, but they are allowed to be
245 // focusable as long as their canvas is displayed and visible.
246 if (isInCanvasSubtree()) {
247 const Element* e = this;
248 while (e && !e->hasLocalName(canvasTag))
249 e = e->parentElement();
250 ASSERT(e);
251 return e->renderer() && e->renderer()->style()->visibility() == VISIBLE;
252 }
253
254 // FIXME: These asserts should be in Node::isFocusable, but there are some
255 // callsites like Document::setFocusedNode that would currently fail on
256 // them. See crbug.com/251163
257 if (renderer()) {
258 ASSERT(!renderer()->needsLayout());
259 } else {
260 // We can't just use needsStyleRecalc() because if the node is in a
261 // display:none tree it might say it needs style recalc but the whole
262 // document is actually up to date.
263 ASSERT(!document()->childNeedsStyleRecalc());
264 }
265
266 // FIXME: Even if we are not visible, we might have a child that is visible.
267 // Hyatt wants to fix that some day with a "has visible content" flag or the like.
268 if (!renderer() || renderer()->style()->visibility() != VISIBLE)
269 return false;
270
271 return true;
272}
273
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100274DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, blur);
275DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, error);
276DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, focus);
277DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, load);
278
279PassRefPtr<Node> Element::cloneNode(bool deep)
280{
281 return deep ? cloneElementWithChildren() : cloneElementWithoutChildren();
282}
283
284PassRefPtr<Element> Element::cloneElementWithChildren()
285{
286 RefPtr<Element> clone = cloneElementWithoutChildren();
287 cloneChildNodes(clone.get());
288 return clone.release();
289}
290
291PassRefPtr<Element> Element::cloneElementWithoutChildren()
292{
293 RefPtr<Element> clone = cloneElementWithoutAttributesAndChildren();
294 // This will catch HTML elements in the wrong namespace that are not correctly copied.
295 // This is a sanity check as HTML overloads some of the DOM methods.
296 ASSERT(isHTMLElement() == clone->isHTMLElement());
297
298 clone->cloneDataFromElement(*this);
299 return clone.release();
300}
301
302PassRefPtr<Element> Element::cloneElementWithoutAttributesAndChildren()
303{
304 return document()->createElement(tagQName(), false);
305}
306
307PassRefPtr<Attr> Element::detachAttribute(size_t index)
308{
309 ASSERT(elementData());
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100310 const Attribute* attribute = elementData()->attributeItem(index);
311 RefPtr<Attr> attrNode = attrIfExists(attribute->name());
312 if (attrNode)
313 detachAttrNodeAtIndex(attrNode.get(), index);
314 else {
315 attrNode = Attr::create(document(), attribute->name(), attribute->value());
316 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
317 }
318 return attrNode.release();
319}
320
321void Element::detachAttrNodeAtIndex(Attr* attr, size_t index)
322{
323 ASSERT(attr);
324 ASSERT(elementData());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100325
326 const Attribute* attribute = elementData()->attributeItem(index);
327 ASSERT(attribute);
Torne (Richard Coles)e5249552013-05-15 11:35:13 +0100328 ASSERT(attribute->name() == attr->qualifiedName());
329 detachAttrNodeFromElementWithValue(attr, attribute->value());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100330 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100331}
332
333void Element::removeAttribute(const QualifiedName& name)
334{
335 if (!elementData())
336 return;
337
338 size_t index = elementData()->getAttributeItemIndex(name);
339 if (index == notFound)
340 return;
341
342 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
343}
344
345void Element::setBooleanAttribute(const QualifiedName& name, bool value)
346{
347 if (value)
348 setAttribute(name, emptyAtom);
349 else
350 removeAttribute(name);
351}
352
353NamedNodeMap* Element::attributes() const
354{
355 ElementRareData* rareData = const_cast<Element*>(this)->ensureElementRareData();
356 if (NamedNodeMap* attributeMap = rareData->attributeMap())
357 return attributeMap;
358
359 rareData->setAttributeMap(NamedNodeMap::create(const_cast<Element*>(this)));
360 return rareData->attributeMap();
361}
362
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100363void Element::addActiveAnimation(Animation* animation)
364{
365 ElementRareData* rareData = ensureElementRareData();
366 if (!rareData->activeAnimations())
367 rareData->setActiveAnimations(adoptPtr(new Vector<Animation*>));
368 rareData->activeAnimations()->append(animation);
369}
370
371void Element::removeActiveAnimation(Animation* animation)
372{
373 ElementRareData* rareData = elementRareData();
374 ASSERT(rareData);
375 size_t position = rareData->activeAnimations()->find(animation);
376 ASSERT(position != notFound);
377 rareData->activeAnimations()->remove(position);
378}
379
380bool Element::hasActiveAnimations() const
381{
382 return hasRareData() && elementRareData()->activeAnimations()
383 && elementRareData()->activeAnimations()->size();
384}
385
386Vector<Animation*>* Element::activeAnimations() const
387{
388 if (!elementRareData())
389 return 0;
390 return elementRareData()->activeAnimations();
391}
392
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100393Node::NodeType Element::nodeType() const
394{
395 return ELEMENT_NODE;
396}
397
398bool Element::hasAttribute(const QualifiedName& name) const
399{
400 return hasAttributeNS(name.namespaceURI(), name.localName());
401}
402
403void Element::synchronizeAllAttributes() const
404{
405 if (!elementData())
406 return;
407 if (elementData()->m_styleAttributeIsDirty) {
408 ASSERT(isStyledElement());
409 static_cast<const StyledElement*>(this)->synchronizeStyleAttributeInternal();
410 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100411 if (elementData()->m_animatedSVGAttributesAreDirty) {
412 ASSERT(isSVGElement());
413 toSVGElement(this)->synchronizeAnimatedSVGAttribute(anyQName());
414 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100415}
416
417inline void Element::synchronizeAttribute(const QualifiedName& name) const
418{
419 if (!elementData())
420 return;
421 if (UNLIKELY(name == styleAttr && elementData()->m_styleAttributeIsDirty)) {
422 ASSERT(isStyledElement());
423 static_cast<const StyledElement*>(this)->synchronizeStyleAttributeInternal();
424 return;
425 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100426 if (UNLIKELY(elementData()->m_animatedSVGAttributesAreDirty)) {
427 ASSERT(isSVGElement());
428 toSVGElement(this)->synchronizeAnimatedSVGAttribute(name);
429 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100430}
431
432inline void Element::synchronizeAttribute(const AtomicString& localName) const
433{
434 // This version of synchronizeAttribute() is streamlined for the case where you don't have a full QualifiedName,
435 // e.g when called from DOM API.
436 if (!elementData())
437 return;
438 if (elementData()->m_styleAttributeIsDirty && equalPossiblyIgnoringCase(localName, styleAttr.localName(), shouldIgnoreAttributeCase(this))) {
439 ASSERT(isStyledElement());
440 static_cast<const StyledElement*>(this)->synchronizeStyleAttributeInternal();
441 return;
442 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100443 if (elementData()->m_animatedSVGAttributesAreDirty) {
444 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
445 ASSERT(isSVGElement());
446 static_cast<const SVGElement*>(this)->synchronizeAnimatedSVGAttribute(QualifiedName(nullAtom, localName, nullAtom));
447 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100448}
449
450const AtomicString& Element::getAttribute(const QualifiedName& name) const
451{
452 if (!elementData())
453 return nullAtom;
454 synchronizeAttribute(name);
455 if (const Attribute* attribute = getAttributeItem(name))
456 return attribute->value();
457 return nullAtom;
458}
459
460void Element::scrollIntoView(bool alignToTop)
461{
462 document()->updateLayoutIgnorePendingStylesheets();
463
464 if (!renderer())
465 return;
466
467 LayoutRect bounds = boundingBox();
468 // Align to the top / bottom and to the closest edge.
469 if (alignToTop)
470 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
471 else
472 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
473}
474
475void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
476{
477 document()->updateLayoutIgnorePendingStylesheets();
478
479 if (!renderer())
480 return;
481
482 LayoutRect bounds = boundingBox();
483 if (centerIfNeeded)
484 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
485 else
486 renderer()->scrollRectToVisible(bounds, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
487}
488
489void Element::scrollByUnits(int units, ScrollGranularity granularity)
490{
491 document()->updateLayoutIgnorePendingStylesheets();
492
493 if (!renderer())
494 return;
495
496 if (!renderer()->hasOverflowClip())
497 return;
498
499 ScrollDirection direction = ScrollDown;
500 if (units < 0) {
501 direction = ScrollUp;
502 units = -units;
503 }
504 Node* stopNode = this;
505 toRenderBox(renderer())->scroll(direction, granularity, units, &stopNode);
506}
507
508void Element::scrollByLines(int lines)
509{
510 scrollByUnits(lines, ScrollByLine);
511}
512
513void Element::scrollByPages(int pages)
514{
515 scrollByUnits(pages, ScrollByPage);
516}
517
518static float localZoomForRenderer(RenderObject* renderer)
519{
520 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
521 // other out, but the alternative is that we'd have to crawl up the whole render tree every
522 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
523 float zoomFactor = 1;
524 if (renderer->style()->effectiveZoom() != 1) {
525 // Need to find the nearest enclosing RenderObject that set up
526 // a differing zoom, and then we divide our result by it to eliminate the zoom.
527 RenderObject* prev = renderer;
528 for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) {
529 if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) {
530 zoomFactor = prev->style()->zoom();
531 break;
532 }
533 prev = curr;
534 }
535 if (prev->isRenderView())
536 zoomFactor = prev->style()->zoom();
537 }
538 return zoomFactor;
539}
540
541static int adjustForLocalZoom(LayoutUnit value, RenderObject* renderer)
542{
543 float zoomFactor = localZoomForRenderer(renderer);
544 if (zoomFactor == 1)
545 return value;
546 return lroundf(value / zoomFactor);
547}
548
549int Element::offsetLeft()
550{
551 document()->updateLayoutIgnorePendingStylesheets();
552 if (RenderBoxModelObject* renderer = renderBoxModelObject())
553 return adjustForLocalZoom(renderer->pixelSnappedOffsetLeft(), renderer);
554 return 0;
555}
556
557int Element::offsetTop()
558{
559 document()->updateLayoutIgnorePendingStylesheets();
560 if (RenderBoxModelObject* renderer = renderBoxModelObject())
561 return adjustForLocalZoom(renderer->pixelSnappedOffsetTop(), renderer);
562 return 0;
563}
564
565int Element::offsetWidth()
566{
567 document()->updateLayoutIgnorePendingStylesheets();
568 if (RenderBoxModelObject* renderer = renderBoxModelObject())
569 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetWidth(), renderer).round();
570 return 0;
571}
572
573int Element::offsetHeight()
574{
575 document()->updateLayoutIgnorePendingStylesheets();
576 if (RenderBoxModelObject* renderer = renderBoxModelObject())
577 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedOffsetHeight(), renderer).round();
578 return 0;
579}
580
581Element* Element::bindingsOffsetParent()
582{
583 Element* element = offsetParent();
584 if (!element || !element->isInShadowTree())
585 return element;
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +0100586 return element->containingShadowRoot()->shouldExposeToBindings() ? element : 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100587}
588
589Element* Element::offsetParent()
590{
591 document()->updateLayoutIgnorePendingStylesheets();
592 if (RenderObject* renderer = this->renderer())
593 return renderer->offsetParent();
594 return 0;
595}
596
597int Element::clientLeft()
598{
599 document()->updateLayoutIgnorePendingStylesheets();
600
601 if (RenderBox* renderer = renderBox())
602 return adjustForAbsoluteZoom(roundToInt(renderer->clientLeft()), renderer);
603 return 0;
604}
605
606int Element::clientTop()
607{
608 document()->updateLayoutIgnorePendingStylesheets();
609
610 if (RenderBox* renderer = renderBox())
611 return adjustForAbsoluteZoom(roundToInt(renderer->clientTop()), renderer);
612 return 0;
613}
614
615int Element::clientWidth()
616{
617 document()->updateLayoutIgnorePendingStylesheets();
618
619 // When in strict mode, clientWidth for the document element should return the width of the containing frame.
620 // When in quirks mode, clientWidth for the body element should return the width of the containing frame.
621 bool inQuirksMode = document()->inQuirksMode();
622 if ((!inQuirksMode && document()->documentElement() == this) ||
623 (inQuirksMode && isHTMLElement() && document()->body() == this)) {
624 if (FrameView* view = document()->view()) {
625 if (RenderView* renderView = document()->renderView())
626 return adjustForAbsoluteZoom(view->layoutWidth(), renderView);
627 }
628 }
629
630 if (RenderBox* renderer = renderBox())
631 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientWidth(), renderer).round();
632 return 0;
633}
634
635int Element::clientHeight()
636{
637 document()->updateLayoutIgnorePendingStylesheets();
638
639 // When in strict mode, clientHeight for the document element should return the height of the containing frame.
640 // When in quirks mode, clientHeight for the body element should return the height of the containing frame.
641 bool inQuirksMode = document()->inQuirksMode();
642
643 if ((!inQuirksMode && document()->documentElement() == this) ||
644 (inQuirksMode && isHTMLElement() && document()->body() == this)) {
645 if (FrameView* view = document()->view()) {
646 if (RenderView* renderView = document()->renderView())
647 return adjustForAbsoluteZoom(view->layoutHeight(), renderView);
648 }
649 }
650
651 if (RenderBox* renderer = renderBox())
652 return adjustLayoutUnitForAbsoluteZoom(renderer->pixelSnappedClientHeight(), renderer).round();
653 return 0;
654}
655
656int Element::scrollLeft()
657{
658 document()->updateLayoutIgnorePendingStylesheets();
659 if (RenderBox* rend = renderBox())
660 return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
661 return 0;
662}
663
664int Element::scrollTop()
665{
666 document()->updateLayoutIgnorePendingStylesheets();
667 if (RenderBox* rend = renderBox())
668 return adjustForAbsoluteZoom(rend->scrollTop(), rend);
669 return 0;
670}
671
672void Element::setScrollLeft(int newLeft)
673{
674 document()->updateLayoutIgnorePendingStylesheets();
675 if (RenderBox* rend = renderBox())
676 rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
677}
678
679void Element::setScrollTop(int newTop)
680{
681 document()->updateLayoutIgnorePendingStylesheets();
682 if (RenderBox* rend = renderBox())
683 rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
684}
685
686int Element::scrollWidth()
687{
688 document()->updateLayoutIgnorePendingStylesheets();
689 if (RenderBox* rend = renderBox())
690 return adjustForAbsoluteZoom(rend->scrollWidth(), rend);
691 return 0;
692}
693
694int Element::scrollHeight()
695{
696 document()->updateLayoutIgnorePendingStylesheets();
697 if (RenderBox* rend = renderBox())
698 return adjustForAbsoluteZoom(rend->scrollHeight(), rend);
699 return 0;
700}
701
702IntRect Element::boundsInRootViewSpace()
703{
704 document()->updateLayoutIgnorePendingStylesheets();
705
706 FrameView* view = document()->view();
707 if (!view)
708 return IntRect();
709
710 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100711 if (isSVGElement() && renderer()) {
712 // Get the bounding rectangle from the SVG model.
713 SVGElement* svgElement = toSVGElement(this);
714 FloatRect localRect;
715 if (svgElement->getBoundingBox(localRect))
716 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100717 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100718 // Get the bounding rectangle from the box model.
719 if (renderBoxModelObject())
720 renderBoxModelObject()->absoluteQuads(quads);
721 }
722
723 if (quads.isEmpty())
724 return IntRect();
725
726 IntRect result = quads[0].enclosingBoundingBox();
727 for (size_t i = 1; i < quads.size(); ++i)
728 result.unite(quads[i].enclosingBoundingBox());
729
730 result = view->contentsToRootView(result);
731 return result;
732}
733
734PassRefPtr<ClientRectList> Element::getClientRects()
735{
736 document()->updateLayoutIgnorePendingStylesheets();
737
738 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject();
739 if (!renderBoxModelObject)
740 return ClientRectList::create();
741
742 // FIXME: Handle SVG elements.
743 // FIXME: Handle table/inline-table with a caption.
744
745 Vector<FloatQuad> quads;
746 renderBoxModelObject->absoluteQuads(quads);
747 document()->adjustFloatQuadsForScrollAndAbsoluteZoom(quads, renderBoxModelObject);
748 return ClientRectList::create(quads);
749}
750
751PassRefPtr<ClientRect> Element::getBoundingClientRect()
752{
753 document()->updateLayoutIgnorePendingStylesheets();
754
755 Vector<FloatQuad> quads;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100756 if (isSVGElement() && renderer() && !renderer()->isSVGRoot()) {
757 // Get the bounding rectangle from the SVG model.
758 SVGElement* svgElement = toSVGElement(this);
759 FloatRect localRect;
760 if (svgElement->getBoundingBox(localRect))
761 quads.append(renderer()->localToAbsoluteQuad(localRect));
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +0100762 } else {
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100763 // Get the bounding rectangle from the box model.
764 if (renderBoxModelObject())
765 renderBoxModelObject()->absoluteQuads(quads);
766 }
767
768 if (quads.isEmpty())
769 return ClientRect::create();
770
771 FloatRect result = quads[0].boundingBox();
772 for (size_t i = 1; i < quads.size(); ++i)
773 result.unite(quads[i].boundingBox());
774
775 document()->adjustFloatRectForScrollAndAbsoluteZoom(result, renderer());
776 return ClientRect::create(result);
777}
778
779IntRect Element::screenRect() const
780{
781 if (!renderer())
782 return IntRect();
783 // FIXME: this should probably respect transforms
784 return document()->view()->contentsToScreen(renderer()->absoluteBoundingBoxRectIgnoringTransforms());
785}
786
787const AtomicString& Element::getAttribute(const AtomicString& localName) const
788{
789 if (!elementData())
790 return nullAtom;
791 synchronizeAttribute(localName);
792 if (const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase(this)))
793 return attribute->value();
794 return nullAtom;
795}
796
797const AtomicString& Element::getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
798{
799 return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
800}
801
802void Element::setAttribute(const AtomicString& localName, const AtomicString& value, ExceptionCode& ec)
803{
804 if (!Document::isValidName(localName)) {
805 ec = INVALID_CHARACTER_ERR;
806 return;
807 }
808
809 synchronizeAttribute(localName);
810 const AtomicString& caseAdjustedLocalName = shouldIgnoreAttributeCase(this) ? localName.lower() : localName;
811
812 size_t index = elementData() ? elementData()->getAttributeItemIndex(caseAdjustedLocalName, false) : notFound;
813 const QualifiedName& qName = index != notFound ? attributeItem(index)->name() : QualifiedName(nullAtom, caseAdjustedLocalName, nullAtom);
814 setAttributeInternal(index, qName, value, NotInSynchronizationOfLazyAttribute);
815}
816
817void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
818{
819 synchronizeAttribute(name);
820 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : notFound;
821 setAttributeInternal(index, name, value, NotInSynchronizationOfLazyAttribute);
822}
823
824void Element::setSynchronizedLazyAttribute(const QualifiedName& name, const AtomicString& value)
825{
826 size_t index = elementData() ? elementData()->getAttributeItemIndex(name) : notFound;
827 setAttributeInternal(index, name, value, InSynchronizationOfLazyAttribute);
828}
829
830inline void Element::setAttributeInternal(size_t index, const QualifiedName& name, const AtomicString& newValue, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
831{
832 if (newValue.isNull()) {
833 if (index != notFound)
834 removeAttributeInternal(index, inSynchronizationOfLazyAttribute);
835 return;
836 }
837
838 if (index == notFound) {
839 addAttributeInternal(name, newValue, inSynchronizationOfLazyAttribute);
840 return;
841 }
842
843 if (!inSynchronizationOfLazyAttribute)
844 willModifyAttribute(name, attributeItem(index)->value(), newValue);
845
846 if (newValue != attributeItem(index)->value()) {
847 // If there is an Attr node hooked to this attribute, the Attr::setValue() call below
848 // will write into the ElementData.
849 // FIXME: Refactor this so it makes some sense.
850 if (RefPtr<Attr> attrNode = inSynchronizationOfLazyAttribute ? 0 : attrIfExists(name))
851 attrNode->setValue(newValue);
852 else
853 ensureUniqueElementData()->attributeItem(index)->setValue(newValue);
854 }
855
856 if (!inSynchronizationOfLazyAttribute)
857 didModifyAttribute(name, newValue);
858}
859
860static inline AtomicString makeIdForStyleResolution(const AtomicString& value, bool inQuirksMode)
861{
862 if (inQuirksMode)
863 return value.lower();
864 return value;
865}
866
867static bool checkNeedsStyleInvalidationForIdChange(const AtomicString& oldId, const AtomicString& newId, StyleResolver* styleResolver)
868{
869 ASSERT(newId != oldId);
870 if (!oldId.isEmpty() && styleResolver->hasSelectorForId(oldId))
871 return true;
872 if (!newId.isEmpty() && styleResolver->hasSelectorForId(newId))
873 return true;
874 return false;
875}
876
877void Element::attributeChanged(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason)
878{
879 if (ElementShadow* parentElementShadow = shadowOfParentForDistribution(this)) {
880 if (shouldInvalidateDistributionWhenAttributeChanged(parentElementShadow, name, newValue))
881 parentElementShadow->invalidateDistribution();
882 }
883
884 parseAttribute(name, newValue);
885
886 document()->incDOMTreeVersion();
887
888 StyleResolver* styleResolver = document()->styleResolverIfExists();
889 bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < FullStyleChange;
890 bool shouldInvalidateStyle = false;
891
892 if (isIdAttributeName(name)) {
893 AtomicString oldId = elementData()->idForStyleResolution();
894 AtomicString newId = makeIdForStyleResolution(newValue, document()->inQuirksMode());
895 if (newId != oldId) {
896 elementData()->setIdForStyleResolution(newId);
897 shouldInvalidateStyle = testShouldInvalidateStyle && checkNeedsStyleInvalidationForIdChange(oldId, newId, styleResolver);
898 }
899 } else if (name == classAttr)
900 classAttributeChanged(newValue);
901 else if (name == HTMLNames::nameAttr)
902 setHasName(!newValue.isNull());
903 else if (name == HTMLNames::pseudoAttr)
904 shouldInvalidateStyle |= testShouldInvalidateStyle && isInShadowTree();
905
906 invalidateNodeListCachesInAncestors(&name, this);
907
908 // If there is currently no StyleResolver, we can't be sure that this attribute change won't affect style.
909 shouldInvalidateStyle |= !styleResolver;
910
911 if (shouldInvalidateStyle)
912 setNeedsStyleRecalc();
913
914 if (AXObjectCache* cache = document()->existingAXObjectCache())
915 cache->handleAttributeChanged(name, this);
916}
917
918inline void Element::attributeChangedFromParserOrByCloning(const QualifiedName& name, const AtomicString& newValue, AttributeModificationReason reason)
919{
920 if (RuntimeEnabledFeatures::customDOMElementsEnabled() && name == isAttr) {
921 document()->ensureCustomElementRegistry()->didGiveTypeExtension(this, newValue);
922 }
923 attributeChanged(name, newValue, reason);
924}
925
926template <typename CharacterType>
927static inline bool classStringHasClassName(const CharacterType* characters, unsigned length)
928{
929 ASSERT(length > 0);
930
931 unsigned i = 0;
932 do {
933 if (isNotHTMLSpace(characters[i]))
934 break;
935 ++i;
936 } while (i < length);
937
938 return i < length;
939}
940
941static inline bool classStringHasClassName(const AtomicString& newClassString)
942{
943 unsigned length = newClassString.length();
944
945 if (!length)
946 return false;
947
948 if (newClassString.is8Bit())
949 return classStringHasClassName(newClassString.characters8(), length);
950 return classStringHasClassName(newClassString.characters16(), length);
951}
952
953template<typename Checker>
954static bool checkSelectorForClassChange(const SpaceSplitString& changedClasses, const Checker& checker)
955{
956 unsigned changedSize = changedClasses.size();
957 for (unsigned i = 0; i < changedSize; ++i) {
958 if (checker.hasSelectorForClass(changedClasses[i]))
959 return true;
960 }
961 return false;
962}
963
964template<typename Checker>
965static bool checkSelectorForClassChange(const SpaceSplitString& oldClasses, const SpaceSplitString& newClasses, const Checker& checker)
966{
967 unsigned oldSize = oldClasses.size();
968 if (!oldSize)
969 return checkSelectorForClassChange(newClasses, checker);
970 BitVector remainingClassBits;
971 remainingClassBits.ensureSize(oldSize);
972 // Class vectors tend to be very short. This is faster than using a hash table.
973 unsigned newSize = newClasses.size();
974 for (unsigned i = 0; i < newSize; ++i) {
975 for (unsigned j = 0; j < oldSize; ++j) {
976 if (newClasses[i] == oldClasses[j]) {
977 remainingClassBits.quickSet(j);
978 continue;
979 }
980 }
981 if (checker.hasSelectorForClass(newClasses[i]))
982 return true;
983 }
984 for (unsigned i = 0; i < oldSize; ++i) {
985 // If the bit is not set the the corresponding class has been removed.
986 if (remainingClassBits.quickGet(i))
987 continue;
988 if (checker.hasSelectorForClass(oldClasses[i]))
989 return true;
990 }
991 return false;
992}
993
994void Element::classAttributeChanged(const AtomicString& newClassString)
995{
996 StyleResolver* styleResolver = document()->styleResolverIfExists();
997 bool testShouldInvalidateStyle = attached() && styleResolver && styleChangeType() < FullStyleChange;
998 bool shouldInvalidateStyle = false;
999
1000 if (classStringHasClassName(newClassString)) {
1001 const bool shouldFoldCase = document()->inQuirksMode();
1002 const SpaceSplitString oldClasses = elementData()->classNames();
1003 elementData()->setClass(newClassString, shouldFoldCase);
1004 const SpaceSplitString& newClasses = elementData()->classNames();
1005 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, newClasses, *styleResolver);
1006 } else {
1007 const SpaceSplitString& oldClasses = elementData()->classNames();
1008 shouldInvalidateStyle = testShouldInvalidateStyle && checkSelectorForClassChange(oldClasses, *styleResolver);
1009 elementData()->clearClass();
1010 }
1011
1012 if (hasRareData())
1013 elementRareData()->clearClassListValueForQuirksMode();
1014
1015 if (shouldInvalidateStyle)
1016 setNeedsStyleRecalc();
1017}
1018
1019bool Element::shouldInvalidateDistributionWhenAttributeChanged(ElementShadow* elementShadow, const QualifiedName& name, const AtomicString& newValue)
1020{
1021 ASSERT(elementShadow);
1022 const SelectRuleFeatureSet& featureSet = elementShadow->distributor().ensureSelectFeatureSet(elementShadow);
1023
1024 if (isIdAttributeName(name)) {
1025 AtomicString oldId = elementData()->idForStyleResolution();
1026 AtomicString newId = makeIdForStyleResolution(newValue, document()->inQuirksMode());
1027 if (newId != oldId) {
1028 if (!oldId.isEmpty() && featureSet.hasSelectorForId(oldId))
1029 return true;
1030 if (!newId.isEmpty() && featureSet.hasSelectorForId(newId))
1031 return true;
1032 }
1033 }
1034
1035 if (name == HTMLNames::classAttr) {
1036 const AtomicString& newClassString = newValue;
1037 if (classStringHasClassName(newClassString)) {
1038 const bool shouldFoldCase = document()->inQuirksMode();
1039 const SpaceSplitString& oldClasses = elementData()->classNames();
1040 const SpaceSplitString newClasses(newClassString, shouldFoldCase);
1041 if (checkSelectorForClassChange(oldClasses, newClasses, featureSet))
1042 return true;
1043 } else {
1044 const SpaceSplitString& oldClasses = elementData()->classNames();
1045 if (checkSelectorForClassChange(oldClasses, featureSet))
1046 return true;
1047 }
1048 }
1049
1050 return featureSet.hasSelectorForAttribute(name.localName());
1051}
1052
1053// Returns true is the given attribute is an event handler.
1054// We consider an event handler any attribute that begins with "on".
1055// It is a simple solution that has the advantage of not requiring any
1056// code or configuration change if a new event handler is defined.
1057
1058static inline bool isEventHandlerAttribute(const Attribute& attribute)
1059{
1060 return attribute.name().namespaceURI().isNull() && attribute.name().localName().startsWith("on");
1061}
1062
1063bool Element::isJavaScriptURLAttribute(const Attribute& attribute) const
1064{
1065 return isURLAttribute(attribute) && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(attribute.value()));
1066}
1067
1068void Element::stripScriptingAttributes(Vector<Attribute>& attributeVector) const
1069{
1070 size_t destination = 0;
1071 for (size_t source = 0; source < attributeVector.size(); ++source) {
1072 if (isEventHandlerAttribute(attributeVector[source])
1073 || isJavaScriptURLAttribute(attributeVector[source])
1074 || isHTMLContentAttribute(attributeVector[source]))
1075 continue;
1076
1077 if (source != destination)
1078 attributeVector[destination] = attributeVector[source];
1079
1080 ++destination;
1081 }
1082 attributeVector.shrink(destination);
1083}
1084
1085void Element::parserSetAttributes(const Vector<Attribute>& attributeVector)
1086{
1087 ASSERT(!inDocument());
1088 ASSERT(!parentNode());
1089 ASSERT(!m_elementData);
1090
1091 if (attributeVector.isEmpty())
1092 return;
1093
1094 if (document() && document()->sharedObjectPool())
1095 m_elementData = document()->sharedObjectPool()->cachedShareableElementDataWithAttributes(attributeVector);
1096 else
1097 m_elementData = ShareableElementData::createWithAttributes(attributeVector);
1098
1099 // Use attributeVector instead of m_elementData because attributeChanged might modify m_elementData.
1100 for (unsigned i = 0; i < attributeVector.size(); ++i)
1101 attributeChangedFromParserOrByCloning(attributeVector[i].name(), attributeVector[i].value(), ModifiedDirectly);
1102}
1103
1104bool Element::hasAttributes() const
1105{
1106 synchronizeAllAttributes();
1107 return elementData() && elementData()->length();
1108}
1109
1110bool Element::hasEquivalentAttributes(const Element* other) const
1111{
1112 synchronizeAllAttributes();
1113 other->synchronizeAllAttributes();
1114 if (elementData() == other->elementData())
1115 return true;
1116 if (elementData())
1117 return elementData()->isEquivalent(other->elementData());
1118 if (other->elementData())
1119 return other->elementData()->isEquivalent(elementData());
1120 return true;
1121}
1122
1123String Element::nodeName() const
1124{
1125 return m_tagName.toString();
1126}
1127
1128String Element::nodeNamePreservingCase() const
1129{
1130 return m_tagName.toString();
1131}
1132
1133void Element::setPrefix(const AtomicString& prefix, ExceptionCode& ec)
1134{
1135 ec = 0;
1136 checkSetPrefix(prefix, ec);
1137 if (ec)
1138 return;
1139
1140 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
1141}
1142
1143KURL Element::baseURI() const
1144{
1145 const AtomicString& baseAttribute = getAttribute(baseAttr);
1146 KURL base(KURL(), baseAttribute);
1147 if (!base.protocol().isEmpty())
1148 return base;
1149
1150 ContainerNode* parent = parentNode();
1151 if (!parent)
1152 return base;
1153
1154 const KURL& parentBase = parent->baseURI();
1155 if (parentBase.isNull())
1156 return base;
1157
1158 return KURL(parentBase, baseAttribute);
1159}
1160
1161const AtomicString& Element::imageSourceURL() const
1162{
1163 return getAttribute(srcAttr);
1164}
1165
1166bool Element::rendererIsNeeded(const NodeRenderingContext& context)
1167{
1168 return context.style()->display() != NONE;
1169}
1170
1171RenderObject* Element::createRenderer(RenderArena*, RenderStyle* style)
1172{
1173 return RenderObject::createObject(this, style);
1174}
1175
1176#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001177bool Element::isDateTimeEditElement() const
1178{
1179 return false;
1180}
1181
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001182bool Element::isDateTimeFieldElement() const
1183{
1184 return false;
1185}
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001186
1187bool Element::isPickerIndicatorElement() const
1188{
1189 return false;
1190}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001191#endif
1192
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001193bool Element::isClearButtonElement() const
1194{
1195 return false;
1196}
1197
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001198bool Element::wasChangedSinceLastFormControlChangeEvent() const
1199{
1200 return false;
1201}
1202
1203void Element::setChangedSinceLastFormControlChangeEvent(bool)
1204{
1205}
1206
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001207bool Element::isInert() const
1208{
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001209 const Element* dialog = document()->activeModalDialog();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001210 return dialog && !containsIncludingShadowDOM(dialog) && !dialog->containsIncludingShadowDOM(this);
1211}
1212
1213Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertionPoint)
1214{
1215 // need to do superclass processing first so inDocument() is true
1216 // by the time we reach updateId
1217 ContainerNode::insertedInto(insertionPoint);
1218
1219 if (containsFullScreenElement() && parentElement() && !parentElement()->containsFullScreenElement())
1220 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
1221
1222 if (Element* before = pseudoElement(BEFORE))
1223 before->insertedInto(insertionPoint);
1224
1225 if (Element* after = pseudoElement(AFTER))
1226 after->insertedInto(insertionPoint);
1227
1228 if (!insertionPoint->isInTreeScope())
1229 return InsertionDone;
1230
1231 if (hasRareData())
1232 elementRareData()->clearClassListValueForQuirksMode();
1233
1234 TreeScope* scope = insertionPoint->treeScope();
1235 if (scope != treeScope())
1236 return InsertionDone;
1237
1238 const AtomicString& idValue = getIdAttribute();
1239 if (!idValue.isNull())
1240 updateId(scope, nullAtom, idValue);
1241
1242 const AtomicString& nameValue = getNameAttribute();
1243 if (!nameValue.isNull())
1244 updateName(nullAtom, nameValue);
1245
1246 if (hasTagName(labelTag)) {
1247 if (scope->shouldCacheLabelsByForAttribute())
1248 updateLabel(scope, nullAtom, fastGetAttribute(forAttr));
1249 }
1250
1251 return InsertionDone;
1252}
1253
1254void Element::removedFrom(ContainerNode* insertionPoint)
1255{
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001256 bool wasInDocument = insertionPoint->document();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001257
1258 if (Element* before = pseudoElement(BEFORE))
1259 before->removedFrom(insertionPoint);
1260
1261 if (Element* after = pseudoElement(AFTER))
1262 after->removedFrom(insertionPoint);
1263
1264 document()->removeFromTopLayer(this);
1265 if (containsFullScreenElement())
1266 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
1267
1268 if (document()->page())
1269 document()->page()->pointerLockController()->elementRemoved(this);
1270
1271 setSavedLayerScrollOffset(IntSize());
1272
1273 if (insertionPoint->isInTreeScope() && treeScope() == document()) {
1274 const AtomicString& idValue = getIdAttribute();
1275 if (!idValue.isNull())
1276 updateId(insertionPoint->treeScope(), idValue, nullAtom);
1277
1278 const AtomicString& nameValue = getNameAttribute();
1279 if (!nameValue.isNull())
1280 updateName(nameValue, nullAtom);
1281
1282 if (hasTagName(labelTag)) {
1283 TreeScope* treeScope = insertionPoint->treeScope();
1284 if (treeScope->shouldCacheLabelsByForAttribute())
1285 updateLabel(treeScope, fastGetAttribute(forAttr), nullAtom);
1286 }
1287 }
1288
1289 ContainerNode::removedFrom(insertionPoint);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001290 if (wasInDocument && hasPendingResources())
1291 document()->accessSVGExtensions()->removeElementFromPendingResources(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001292}
1293
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001294void Element::createRendererIfNeeded(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001295{
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001296 NodeRenderingContext(this, context).createRendererForElementIfNeeded();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001297}
1298
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001299void Element::attach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001300{
1301 PostAttachCallbackDisabler callbackDisabler(this);
1302 StyleResolverParentPusher parentPusher(this);
1303 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1304
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001305 createRendererIfNeeded(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001306
1307 if (parentElement() && parentElement()->isInCanvasSubtree())
1308 setIsInCanvasSubtree(true);
1309
1310 createPseudoElementIfNeeded(BEFORE);
1311
1312 // When a shadow root exists, it does the work of attaching the children.
1313 if (ElementShadow* shadow = this->shadow()) {
1314 parentPusher.push();
1315 shadow->attach();
1316 } else if (firstChild())
1317 parentPusher.push();
1318
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001319 ContainerNode::attach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001320
1321 createPseudoElementIfNeeded(AFTER);
1322
1323 if (hasRareData()) {
1324 ElementRareData* data = elementRareData();
1325 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
1326 if (isFocusable() && document()->focusedNode() == this)
1327 document()->updateFocusAppearanceSoon(false /* don't restore selection */);
1328 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1329 }
1330 }
1331}
1332
1333void Element::unregisterNamedFlowContentNode()
1334{
1335 if (RuntimeEnabledFeatures::cssRegionsEnabled() && inNamedFlow() && document()->renderView())
1336 document()->renderView()->flowThreadController()->unregisterNamedFlowContentNode(this);
1337}
1338
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001339void Element::detach(const AttachContext& context)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001340{
1341 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1342 unregisterNamedFlowContentNode();
1343 cancelFocusAppearanceUpdate();
1344 if (hasRareData()) {
1345 ElementRareData* data = elementRareData();
1346 data->setPseudoElement(BEFORE, 0);
1347 data->setPseudoElement(AFTER, 0);
1348 data->setIsInCanvasSubtree(false);
1349 data->resetComputedStyle();
1350 data->resetDynamicRestyleObservations();
1351 }
1352
1353 if (ElementShadow* shadow = this->shadow()) {
1354 detachChildrenIfNeeded();
1355 shadow->detach();
1356 }
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001357 ContainerNode::detach(context);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001358}
1359
1360bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle)
1361{
1362 ASSERT(currentStyle == renderStyle());
1363 ASSERT(renderer());
1364
1365 if (!currentStyle)
1366 return false;
1367
1368 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles();
1369 if (!pseudoStyleCache)
1370 return false;
1371
1372 size_t cacheSize = pseudoStyleCache->size();
1373 for (size_t i = 0; i < cacheSize; ++i) {
1374 RefPtr<RenderStyle> newPseudoStyle;
1375 PseudoId pseudoId = pseudoStyleCache->at(i)->styleType();
1376 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
1377 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle);
1378 else
1379 newPseudoStyle = renderer()->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
1380 if (!newPseudoStyle)
1381 return true;
1382 if (*newPseudoStyle != *pseudoStyleCache->at(i)) {
1383 if (pseudoId < FIRST_INTERNAL_PSEUDOID)
1384 newStyle->setHasPseudoStyle(pseudoId);
1385 newStyle->addCachedPseudoStyle(newPseudoStyle);
1386 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
1387 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
1388 // is needed, but for now just assume a layout will be required. The diff code
1389 // in RenderObject::setStyle would need to be factored out so that it could be reused.
1390 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
1391 }
1392 return true;
1393 }
1394 }
1395 return false;
1396}
1397
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001398PassRefPtr<RenderStyle> Element::styleForRenderer()
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001399{
1400 if (hasCustomStyleCallbacks()) {
1401 if (RefPtr<RenderStyle> style = customStyleForRenderer())
1402 return style.release();
1403 }
1404
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001405 return originalStyleForRenderer();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001406}
1407
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001408PassRefPtr<RenderStyle> Element::originalStyleForRenderer()
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001409{
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001410 return document()->styleResolver()->styleForElement(this);
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001411}
1412
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001413void Element::recalcStyle(StyleChange change)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001414{
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001415 ASSERT(document()->inStyleRecalc());
1416
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001417 if (hasCustomStyleCallbacks())
1418 willRecalcStyle(change);
1419
1420 // Ref currentStyle in case it would otherwise be deleted when setting the new style in the renderer.
1421 RefPtr<RenderStyle> currentStyle(renderStyle());
1422 bool hasParentStyle = parentNodeForRenderingAndStyle() ? static_cast<bool>(parentNodeForRenderingAndStyle()->renderStyle()) : false;
1423 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
1424 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
1425
1426 if ((change > NoChange || needsStyleRecalc())) {
1427 if (hasRareData())
1428 elementRareData()->resetComputedStyle();
1429 }
1430 if (hasParentStyle && (change >= Inherit || needsStyleRecalc())) {
1431 StyleChange localChange = Detach;
1432 RefPtr<RenderStyle> newStyle;
1433 if (currentStyle) {
1434 // FIXME: This still recalcs style twice when changing display types, but saves
1435 // us from recalcing twice when going from none -> anything else which is more
1436 // common, especially during lazy attach.
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001437 newStyle = styleForRenderer();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001438 localChange = Node::diff(currentStyle.get(), newStyle.get(), document());
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001439 } else if (attached() && isActiveInsertionPoint(this)) {
1440 // Active InsertionPoints will never have renderers so there's no reason to
1441 // reattach them repeatedly once they're already attached.
1442 localChange = change;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001443 }
1444 if (localChange == Detach) {
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001445 AttachContext reattachContext;
1446 reattachContext.resolvedStyle = newStyle.get();
1447 reattach(reattachContext);
1448
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001449 // attach recalculates the style for all children. No need to do it twice.
1450 clearNeedsStyleRecalc();
1451 clearChildNeedsStyleRecalc();
1452
1453 if (hasCustomStyleCallbacks())
1454 didRecalcStyle(change);
1455 return;
1456 }
1457
1458 if (RenderObject* renderer = this->renderer()) {
1459 if (localChange != NoChange || pseudoStyleCacheIsInvalid(currentStyle.get(), newStyle.get()) || (change == Force && renderer->requiresForcedStyleRecalcPropagation()) || styleChangeType() == SyntheticStyleChange)
1460 renderer->setAnimatableStyle(newStyle.get());
1461 else if (needsStyleRecalc()) {
1462 // Although no change occurred, we use the new style so that the cousin style sharing code won't get
1463 // fooled into believing this style is the same.
1464 renderer->setStyleInternal(newStyle.get());
1465 }
1466 }
1467
1468 // 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
1469 // 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).
1470 if (document()->styleSheetCollection()->usesRemUnits() && document()->documentElement() == this && localChange != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize()) {
1471 // Cached RenderStyles may depend on the re units.
1472 document()->styleResolver()->invalidateMatchedPropertiesCache();
1473 change = Force;
1474 }
1475
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001476 if (styleChangeType() == FullStyleChange)
1477 change = Force;
1478 else if (change != Force)
1479 change = localChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001480 }
1481 StyleResolverParentPusher parentPusher(this);
1482
1483 // FIXME: This does not care about sibling combinators. Will be necessary in XBL2 world.
1484 if (ElementShadow* shadow = this->shadow()) {
1485 if (shouldRecalcStyle(change, shadow)) {
1486 parentPusher.push();
1487 shadow->recalcStyle(change);
1488 }
1489 }
1490
1491 if (shouldRecalcStyle(change, this))
1492 updatePseudoElement(BEFORE, change);
1493
1494 // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
1495 // For now we will just worry about the common case, since it's a lot trickier to get the second case right
1496 // without doing way too much re-resolution.
1497 bool forceCheckOfNextElementSibling = false;
1498 bool forceCheckOfAnyElementSibling = false;
1499 for (Node *n = firstChild(); n; n = n->nextSibling()) {
1500 if (n->isTextNode()) {
1501 toText(n)->recalcTextStyle(change);
1502 continue;
1503 }
1504 if (!n->isElementNode())
1505 continue;
1506 Element* element = toElement(n);
1507 bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() == FullStyleChange;
1508 if ((forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling))
1509 element->setNeedsStyleRecalc();
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001510 if (shouldRecalcStyle(change, element)) {
1511 parentPusher.push();
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001512 element->recalcStyle(change);
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001513 }
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01001514 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
1515 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001516 }
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001517
1518 if (shouldRecalcStyle(change, this))
1519 updatePseudoElement(AFTER, change);
1520
1521 clearNeedsStyleRecalc();
1522 clearChildNeedsStyleRecalc();
Torne (Richard Coles)5267f702013-06-11 10:57:24 +01001523
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001524 if (hasCustomStyleCallbacks())
1525 didRecalcStyle(change);
1526 InspectorInstrumentation::didRecalculateStyleForElement(this);
1527}
1528
1529ElementShadow* Element::shadow() const
1530{
1531 return hasRareData() ? elementRareData()->shadow() : 0;
1532}
1533
1534ElementShadow* Element::ensureShadow()
1535{
1536 return ensureElementRareData()->ensureShadow();
1537}
1538
1539void Element::didAffectSelector(AffectedSelectorMask mask)
1540{
1541 setNeedsStyleRecalc();
1542 if (ElementShadow* elementShadow = shadowOfParentForDistribution(this))
1543 elementShadow->didAffectSelector(mask);
1544}
1545
1546PassRefPtr<ShadowRoot> Element::createShadowRoot(ExceptionCode& ec)
1547{
1548 if (alwaysCreateUserAgentShadowRoot())
1549 ensureUserAgentShadowRoot();
1550
1551 if (RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled())
1552 return ensureShadow()->addShadowRoot(this, ShadowRoot::AuthorShadowRoot);
1553
1554 // Since some elements recreates shadow root dynamically, multiple shadow
1555 // subtrees won't work well in that element. Until they are fixed, we disable
1556 // adding author shadow root for them.
1557 if (!areAuthorShadowsAllowed()) {
1558 ec = HIERARCHY_REQUEST_ERR;
1559 return 0;
1560 }
1561 return ensureShadow()->addShadowRoot(this, ShadowRoot::AuthorShadowRoot);
1562}
1563
1564ShadowRoot* Element::shadowRoot() const
1565{
1566 ElementShadow* elementShadow = shadow();
1567 if (!elementShadow)
1568 return 0;
1569 ShadowRoot* shadowRoot = elementShadow->youngestShadowRoot();
1570 if (shadowRoot->type() == ShadowRoot::AuthorShadowRoot)
1571 return shadowRoot;
1572 return 0;
1573}
1574
1575ShadowRoot* Element::userAgentShadowRoot() const
1576{
1577 if (ElementShadow* elementShadow = shadow()) {
1578 if (ShadowRoot* shadowRoot = elementShadow->oldestShadowRoot()) {
1579 ASSERT(shadowRoot->type() == ShadowRoot::UserAgentShadowRoot);
1580 return shadowRoot;
1581 }
1582 }
1583
1584 return 0;
1585}
1586
1587ShadowRoot* Element::ensureUserAgentShadowRoot()
1588{
1589 if (ShadowRoot* shadowRoot = userAgentShadowRoot())
1590 return shadowRoot;
1591 ShadowRoot* shadowRoot = ensureShadow()->addShadowRoot(this, ShadowRoot::UserAgentShadowRoot);
1592 didAddUserAgentShadowRoot(shadowRoot);
1593 return shadowRoot;
1594}
1595
1596const AtomicString& Element::shadowPseudoId() const
1597{
1598 return pseudo();
1599}
1600
1601bool Element::childTypeAllowed(NodeType type) const
1602{
1603 switch (type) {
1604 case ELEMENT_NODE:
1605 case TEXT_NODE:
1606 case COMMENT_NODE:
1607 case PROCESSING_INSTRUCTION_NODE:
1608 case CDATA_SECTION_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001609 return true;
1610 default:
1611 break;
1612 }
1613 return false;
1614}
1615
1616static void checkForEmptyStyleChange(Element* element, RenderStyle* style)
1617{
1618 if (!style && !element->styleAffectedByEmpty())
1619 return;
1620
1621 if (!style || (element->styleAffectedByEmpty() && (!style->emptyState() || element->hasChildNodes())))
1622 element->setNeedsStyleRecalc();
1623}
1624
1625static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
1626 Node* beforeChange, Node* afterChange, int childCountDelta)
1627{
1628 // :empty selector.
1629 checkForEmptyStyleChange(e, style);
1630
1631 if (!style || (e->needsStyleRecalc() && e->childrenAffectedByPositionalRules()))
1632 return;
1633
1634 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1635 // In the DOM case, we only need to do something if |afterChange| is not 0.
1636 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
1637 if (e->childrenAffectedByFirstChildRules() && afterChange) {
1638 // Find our new first child.
1639 Node* newFirstChild = 0;
1640 for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {};
1641
1642 // Find the first element node following |afterChange|
1643 Node* firstElementAfterInsertion = 0;
1644 for (firstElementAfterInsertion = afterChange;
1645 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
1646 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
1647
1648 // This is the insert/append case.
1649 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertion && firstElementAfterInsertion->attached() &&
1650 firstElementAfterInsertion->renderStyle() && firstElementAfterInsertion->renderStyle()->firstChildState())
1651 firstElementAfterInsertion->setNeedsStyleRecalc();
1652
1653 // We also have to handle node removal.
1654 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChild->renderStyle() || !newFirstChild->renderStyle()->firstChildState()))
1655 newFirstChild->setNeedsStyleRecalc();
1656 }
1657
1658 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1659 // In the DOM case, we only need to do something if |afterChange| is not 0.
1660 if (e->childrenAffectedByLastChildRules() && beforeChange) {
1661 // Find our new last child.
1662 Node* newLastChild = 0;
1663 for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {};
1664
1665 // Find the last element node going backwards from |beforeChange|
1666 Node* lastElementBeforeInsertion = 0;
1667 for (lastElementBeforeInsertion = beforeChange;
1668 lastElementBeforeInsertion && !lastElementBeforeInsertion->isElementNode();
1669 lastElementBeforeInsertion = lastElementBeforeInsertion->previousSibling()) {};
1670
1671 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertion && lastElementBeforeInsertion->attached() &&
1672 lastElementBeforeInsertion->renderStyle() && lastElementBeforeInsertion->renderStyle()->lastChildState())
1673 lastElementBeforeInsertion->setNeedsStyleRecalc();
1674
1675 // 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
1676 // to match now.
1677 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChild->renderStyle() || !newLastChild->renderStyle()->lastChildState()))
1678 newLastChild->setNeedsStyleRecalc();
1679 }
1680
1681 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
1682 // that could be affected by this DOM change.
1683 if (e->childrenAffectedByDirectAdjacentRules() && afterChange) {
1684 Node* firstElementAfterInsertion = 0;
1685 for (firstElementAfterInsertion = afterChange;
1686 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
1687 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
1688 if (firstElementAfterInsertion && firstElementAfterInsertion->attached())
1689 firstElementAfterInsertion->setNeedsStyleRecalc();
1690 }
1691
1692 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
1693 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1694 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
1695 // backward case.
1696 // |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.
1697 // 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
1698 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
1699 if ((e->childrenAffectedByForwardPositionalRules() && afterChange)
1700 || (e->childrenAffectedByBackwardPositionalRules() && beforeChange))
1701 e->setNeedsStyleRecalc();
1702}
1703
1704void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
1705{
1706 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
1707 if (changedByParser)
1708 checkForEmptyStyleChange(this, renderStyle());
1709 else
1710 checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
1711
1712 if (ElementShadow * shadow = this->shadow())
1713 shadow->invalidateDistribution();
1714}
1715
1716void Element::removeAllEventListeners()
1717{
1718 ContainerNode::removeAllEventListeners();
1719 if (ElementShadow* shadow = this->shadow())
1720 shadow->removeAllEventListeners();
1721}
1722
1723void Element::beginParsingChildren()
1724{
1725 clearIsParsingChildrenFinished();
1726 StyleResolver* styleResolver = document()->styleResolverIfExists();
1727 if (styleResolver && attached())
1728 styleResolver->pushParentElement(this);
1729}
1730
1731void Element::finishParsingChildren()
1732{
1733 ContainerNode::finishParsingChildren();
1734 setIsParsingChildrenFinished();
1735 checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
1736 if (StyleResolver* styleResolver = document()->styleResolverIfExists())
1737 styleResolver->popParentElement(this);
1738}
1739
1740#ifndef NDEBUG
1741void Element::formatForDebugger(char* buffer, unsigned length) const
1742{
1743 StringBuilder result;
1744 String s;
1745
1746 result.append(nodeName());
1747
1748 s = getIdAttribute();
1749 if (s.length() > 0) {
1750 if (result.length() > 0)
1751 result.appendLiteral("; ");
1752 result.appendLiteral("id=");
1753 result.append(s);
1754 }
1755
1756 s = getAttribute(classAttr);
1757 if (s.length() > 0) {
1758 if (result.length() > 0)
1759 result.appendLiteral("; ");
1760 result.appendLiteral("class=");
1761 result.append(s);
1762 }
1763
1764 strncpy(buffer, result.toString().utf8().data(), length - 1);
1765}
1766#endif
1767
1768const Vector<RefPtr<Attr> >& Element::attrNodeList()
1769{
1770 ASSERT(hasSyntheticAttrChildNodes());
1771 return *attrNodeListForElement(this);
1772}
1773
1774PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionCode& ec)
1775{
1776 if (!attrNode) {
1777 ec = TYPE_MISMATCH_ERR;
1778 return 0;
1779 }
1780
1781 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName());
1782 if (oldAttrNode.get() == attrNode)
1783 return attrNode; // This Attr is already attached to the element.
1784
1785 // INUSE_ATTRIBUTE_ERR: Raised if node is an Attr that is already an attribute of another Element object.
1786 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
1787 if (attrNode->ownerElement()) {
1788 ec = INUSE_ATTRIBUTE_ERR;
1789 return 0;
1790 }
1791
1792 synchronizeAllAttributes();
1793 UniqueElementData* elementData = ensureUniqueElementData();
1794
1795 size_t index = elementData->getAttributeItemIndex(attrNode->qualifiedName());
1796 if (index != notFound) {
1797 if (oldAttrNode)
1798 detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData->attributeItem(index)->value());
1799 else
1800 oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), elementData->attributeItem(index)->value());
1801 }
1802
1803 setAttributeInternal(index, attrNode->qualifiedName(), attrNode->value(), NotInSynchronizationOfLazyAttribute);
1804
1805 attrNode->attachToElement(this);
1806 ensureAttrNodeListForElement(this)->append(attrNode);
1807
1808 return oldAttrNode.release();
1809}
1810
1811PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionCode& ec)
1812{
1813 return setAttributeNode(attr, ec);
1814}
1815
1816PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec)
1817{
1818 if (!attr) {
1819 ec = TYPE_MISMATCH_ERR;
1820 return 0;
1821 }
1822 if (attr->ownerElement() != this) {
1823 ec = NOT_FOUND_ERR;
1824 return 0;
1825 }
1826
1827 ASSERT(document() == attr->document());
1828
1829 synchronizeAttribute(attr->qualifiedName());
1830
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001831 size_t index = elementData()->getAttrIndex(attr);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001832 if (index == notFound) {
1833 ec = NOT_FOUND_ERR;
1834 return 0;
1835 }
1836
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001837 RefPtr<Attr> guard(attr);
1838 detachAttrNodeAtIndex(attr, index);
1839 return guard.release();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001840}
1841
1842bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionCode& ec)
1843{
1844 String prefix, localName;
1845 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec))
1846 return false;
1847 ASSERT(!ec);
1848
1849 QualifiedName qName(prefix, localName, namespaceURI);
1850
1851 if (!Document::hasValidNamespaceForAttributes(qName)) {
1852 ec = NAMESPACE_ERR;
1853 return false;
1854 }
1855
1856 out = qName;
1857 return true;
1858}
1859
1860void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode& ec)
1861{
1862 QualifiedName parsedName = anyName;
1863 if (!parseAttributeName(parsedName, namespaceURI, qualifiedName, ec))
1864 return;
1865 setAttribute(parsedName, value);
1866}
1867
1868void Element::removeAttributeInternal(size_t index, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1869{
1870 ASSERT_WITH_SECURITY_IMPLICATION(index < attributeCount());
1871
1872 UniqueElementData* elementData = ensureUniqueElementData();
1873
1874 QualifiedName name = elementData->attributeItem(index)->name();
1875 AtomicString valueBeingRemoved = elementData->attributeItem(index)->value();
1876
1877 if (!inSynchronizationOfLazyAttribute) {
1878 if (!valueBeingRemoved.isNull())
1879 willModifyAttribute(name, valueBeingRemoved, nullAtom);
1880 }
1881
1882 if (RefPtr<Attr> attrNode = attrIfExists(name))
1883 detachAttrNodeFromElementWithValue(attrNode.get(), elementData->attributeItem(index)->value());
1884
1885 elementData->removeAttribute(index);
1886
1887 if (!inSynchronizationOfLazyAttribute)
1888 didRemoveAttribute(name);
1889}
1890
1891void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1892{
1893 if (!inSynchronizationOfLazyAttribute)
1894 willModifyAttribute(name, nullAtom, value);
1895 ensureUniqueElementData()->addAttribute(name, value);
1896 if (!inSynchronizationOfLazyAttribute)
1897 didAddAttribute(name, value);
1898}
1899
1900void Element::removeAttribute(const AtomicString& name)
1901{
1902 if (!elementData())
1903 return;
1904
1905 AtomicString localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1906 size_t index = elementData()->getAttributeItemIndex(localName, false);
1907 if (index == notFound) {
1908 if (UNLIKELY(localName == styleAttr) && elementData()->m_styleAttributeIsDirty && isStyledElement())
1909 static_cast<StyledElement*>(this)->removeAllInlineStyleProperties();
1910 return;
1911 }
1912
1913 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
1914}
1915
1916void Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName)
1917{
1918 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI));
1919}
1920
1921PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& localName)
1922{
1923 if (!elementData())
1924 return 0;
1925 synchronizeAttribute(localName);
1926 const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase(this));
1927 if (!attribute)
1928 return 0;
1929 return ensureAttr(attribute->name());
1930}
1931
1932PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
1933{
1934 if (!elementData())
1935 return 0;
1936 QualifiedName qName(nullAtom, localName, namespaceURI);
1937 synchronizeAttribute(qName);
1938 const Attribute* attribute = elementData()->getAttributeItem(qName);
1939 if (!attribute)
1940 return 0;
1941 return ensureAttr(attribute->name());
1942}
1943
1944bool Element::hasAttribute(const AtomicString& localName) const
1945{
1946 if (!elementData())
1947 return false;
1948 synchronizeAttribute(localName);
1949 return elementData()->getAttributeItem(shouldIgnoreAttributeCase(this) ? localName.lower() : localName, false);
1950}
1951
1952bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
1953{
1954 if (!elementData())
1955 return false;
1956 QualifiedName qName(nullAtom, localName, namespaceURI);
1957 synchronizeAttribute(qName);
1958 return elementData()->getAttributeItem(qName);
1959}
1960
1961CSSStyleDeclaration *Element::style()
1962{
1963 return 0;
1964}
1965
1966void Element::focus(bool restorePreviousSelection, FocusDirection direction)
1967{
1968 if (!inDocument())
1969 return;
1970
1971 Document* doc = document();
1972 if (doc->focusedNode() == this)
1973 return;
1974
1975 // If the stylesheets have already been loaded we can reliably check isFocusable.
1976 // If not, we continue and set the focused node on the focus controller below so
1977 // that it can be updated soon after attach.
1978 if (doc->haveStylesheetsLoaded()) {
1979 doc->updateLayoutIgnorePendingStylesheets();
1980 if (!isFocusable())
1981 return;
1982 }
1983
1984 if (!supportsFocus())
1985 return;
1986
1987 RefPtr<Node> protect;
1988 if (Page* page = doc->page()) {
1989 // Focus and change event handlers can cause us to lose our last ref.
1990 // If a focus event handler changes the focus to a different node it
1991 // does not make sense to continue and update appearence.
1992 protect = this;
1993 if (!page->focusController()->setFocusedNode(this, doc->frame(), direction))
1994 return;
1995 }
1996
1997 // Setting the focused node above might have invalidated the layout due to scripts.
1998 doc->updateLayoutIgnorePendingStylesheets();
1999
2000 if (!isFocusable()) {
2001 ensureElementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
2002 return;
2003 }
2004
2005 cancelFocusAppearanceUpdate();
2006 updateFocusAppearance(restorePreviousSelection);
2007}
2008
2009void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
2010{
2011 if (isRootEditableElement()) {
2012 Frame* frame = document()->frame();
2013 if (!frame)
2014 return;
2015
2016 // When focusing an editable element in an iframe, don't reset the selection if it already contains a selection.
2017 if (this == frame->selection()->rootEditableElement())
2018 return;
2019
2020 // FIXME: We should restore the previous selection if there is one.
2021 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
2022
2023 if (frame->selection()->shouldChangeSelection(newSelection)) {
2024 frame->selection()->setSelection(newSelection);
2025 frame->selection()->revealSelection();
2026 }
2027 } else if (renderer() && !renderer()->isWidget())
2028 renderer()->scrollRectToVisible(boundingBox());
2029}
2030
2031void Element::blur()
2032{
2033 cancelFocusAppearanceUpdate();
2034 Document* doc = document();
2035 if (treeScope()->focusedNode() == this) {
2036 if (doc->frame())
2037 doc->frame()->page()->focusController()->setFocusedNode(0, doc->frame());
2038 else
2039 doc->setFocusedNode(0);
2040 }
2041}
2042
2043String Element::innerText()
2044{
2045 // We need to update layout, since plainText uses line boxes in the render tree.
2046 document()->updateLayoutIgnorePendingStylesheets();
2047
2048 if (!renderer())
2049 return textContent(true);
2050
2051 return plainText(rangeOfContents(const_cast<Element*>(this)).get());
2052}
2053
2054String Element::outerText()
2055{
2056 // Getting outerText is the same as getting innerText, only
2057 // setting is different. You would think this should get the plain
2058 // text for the outer range, but this is wrong, <br> for instance
2059 // would return different values for inner and outer text by such
2060 // a rule, but it doesn't in WinIE, and we want to match that.
2061 return innerText();
2062}
2063
2064String Element::title() const
2065{
2066 return String();
2067}
2068
2069const AtomicString& Element::pseudo() const
2070{
2071 return getAttribute(pseudoAttr);
2072}
2073
2074void Element::setPseudo(const AtomicString& value)
2075{
2076 setAttribute(pseudoAttr, value);
2077}
2078
2079LayoutSize Element::minimumSizeForResizing() const
2080{
2081 return hasRareData() ? elementRareData()->minimumSizeForResizing() : defaultMinimumSizeForResizing();
2082}
2083
2084void Element::setMinimumSizeForResizing(const LayoutSize& size)
2085{
2086 if (!hasRareData() && size == defaultMinimumSizeForResizing())
2087 return;
2088 ensureElementRareData()->setMinimumSizeForResizing(size);
2089}
2090
2091RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
2092{
2093 if (PseudoElement* element = pseudoElement(pseudoElementSpecifier))
2094 return element->computedStyle();
2095
2096 // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
2097 // properties, which are only known by the renderer because it did the layout, will be correct and so that the
2098 // values returned for the ":selection" pseudo-element will be correct.
2099 if (RenderStyle* usedStyle = renderStyle()) {
2100 if (pseudoElementSpecifier) {
2101 RenderStyle* cachedPseudoStyle = usedStyle->getCachedPseudoStyle(pseudoElementSpecifier);
2102 return cachedPseudoStyle ? cachedPseudoStyle : usedStyle;
2103 } else
2104 return usedStyle;
2105 }
2106
2107 if (!attached())
2108 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
2109 // document tree and figure out when to destroy the computed style for such elements.
2110 return 0;
2111
2112 ElementRareData* data = ensureElementRareData();
2113 if (!data->computedStyle())
2114 data->setComputedStyle(document()->styleForElementIgnoringPendingStylesheets(this));
2115 return pseudoElementSpecifier ? data->computedStyle()->getCachedPseudoStyle(pseudoElementSpecifier) : data->computedStyle();
2116}
2117
2118void Element::setStyleAffectedByEmpty()
2119{
2120 ensureElementRareData()->setStyleAffectedByEmpty(true);
2121}
2122
2123void Element::setChildrenAffectedByHover(bool value)
2124{
2125 if (value || hasRareData())
2126 ensureElementRareData()->setChildrenAffectedByHover(value);
2127}
2128
2129void Element::setChildrenAffectedByActive(bool value)
2130{
2131 if (value || hasRareData())
2132 ensureElementRareData()->setChildrenAffectedByActive(value);
2133}
2134
2135void Element::setChildrenAffectedByDrag(bool value)
2136{
2137 if (value || hasRareData())
2138 ensureElementRareData()->setChildrenAffectedByDrag(value);
2139}
2140
2141void Element::setChildrenAffectedByFirstChildRules()
2142{
2143 ensureElementRareData()->setChildrenAffectedByFirstChildRules(true);
2144}
2145
2146void Element::setChildrenAffectedByLastChildRules()
2147{
2148 ensureElementRareData()->setChildrenAffectedByLastChildRules(true);
2149}
2150
2151void Element::setChildrenAffectedByDirectAdjacentRules()
2152{
2153 ensureElementRareData()->setChildrenAffectedByDirectAdjacentRules(true);
2154}
2155
2156void Element::setChildrenAffectedByForwardPositionalRules()
2157{
2158 ensureElementRareData()->setChildrenAffectedByForwardPositionalRules(true);
2159}
2160
2161void Element::setChildrenAffectedByBackwardPositionalRules()
2162{
2163 ensureElementRareData()->setChildrenAffectedByBackwardPositionalRules(true);
2164}
2165
2166void Element::setChildIndex(unsigned index)
2167{
2168 ElementRareData* rareData = ensureElementRareData();
2169 if (RenderStyle* style = renderStyle())
2170 style->setUnique();
2171 rareData->setChildIndex(index);
2172}
2173
2174bool Element::hasFlagsSetDuringStylingOfChildren() const
2175{
2176 if (!hasRareData())
2177 return false;
2178 return rareDataChildrenAffectedByHover()
2179 || rareDataChildrenAffectedByActive()
2180 || rareDataChildrenAffectedByDrag()
2181 || rareDataChildrenAffectedByFirstChildRules()
2182 || rareDataChildrenAffectedByLastChildRules()
2183 || rareDataChildrenAffectedByDirectAdjacentRules()
2184 || rareDataChildrenAffectedByForwardPositionalRules()
2185 || rareDataChildrenAffectedByBackwardPositionalRules();
2186}
2187
2188bool Element::rareDataStyleAffectedByEmpty() const
2189{
2190 ASSERT(hasRareData());
2191 return elementRareData()->styleAffectedByEmpty();
2192}
2193
2194bool Element::rareDataChildrenAffectedByHover() const
2195{
2196 ASSERT(hasRareData());
2197 return elementRareData()->childrenAffectedByHover();
2198}
2199
2200bool Element::rareDataChildrenAffectedByActive() const
2201{
2202 ASSERT(hasRareData());
2203 return elementRareData()->childrenAffectedByActive();
2204}
2205
2206bool Element::rareDataChildrenAffectedByDrag() const
2207{
2208 ASSERT(hasRareData());
2209 return elementRareData()->childrenAffectedByDrag();
2210}
2211
2212bool Element::rareDataChildrenAffectedByFirstChildRules() const
2213{
2214 ASSERT(hasRareData());
2215 return elementRareData()->childrenAffectedByFirstChildRules();
2216}
2217
2218bool Element::rareDataChildrenAffectedByLastChildRules() const
2219{
2220 ASSERT(hasRareData());
2221 return elementRareData()->childrenAffectedByLastChildRules();
2222}
2223
2224bool Element::rareDataChildrenAffectedByDirectAdjacentRules() const
2225{
2226 ASSERT(hasRareData());
2227 return elementRareData()->childrenAffectedByDirectAdjacentRules();
2228}
2229
2230bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
2231{
2232 ASSERT(hasRareData());
2233 return elementRareData()->childrenAffectedByForwardPositionalRules();
2234}
2235
2236bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
2237{
2238 ASSERT(hasRareData());
2239 return elementRareData()->childrenAffectedByBackwardPositionalRules();
2240}
2241
2242unsigned Element::rareDataChildIndex() const
2243{
2244 ASSERT(hasRareData());
2245 return elementRareData()->childIndex();
2246}
2247
2248void Element::setIsInCanvasSubtree(bool isInCanvasSubtree)
2249{
2250 ensureElementRareData()->setIsInCanvasSubtree(isInCanvasSubtree);
2251}
2252
2253bool Element::isInCanvasSubtree() const
2254{
2255 return hasRareData() && elementRareData()->isInCanvasSubtree();
2256}
2257
2258bool Element::isUnresolvedCustomElement()
2259{
2260 return isCustomElement() && document()->registry()->isUnresolved(this);
2261}
2262
2263AtomicString Element::computeInheritedLanguage() const
2264{
2265 const Node* n = this;
2266 AtomicString value;
2267 // The language property is inherited, so we iterate over the parents to find the first language.
2268 do {
2269 if (n->isElementNode()) {
2270 if (const ElementData* elementData = toElement(n)->elementData()) {
2271 // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7
2272 if (const Attribute* attribute = elementData->getAttributeItem(XMLNames::langAttr))
2273 value = attribute->value();
2274 else if (const Attribute* attribute = elementData->getAttributeItem(HTMLNames::langAttr))
2275 value = attribute->value();
2276 }
2277 } else if (n->isDocumentNode()) {
2278 // checking the MIME content-language
2279 value = toDocument(n)->contentLanguage();
2280 }
2281
2282 n = n->parentNode();
2283 } while (n && value.isNull());
2284
2285 return value;
2286}
2287
2288Locale& Element::locale() const
2289{
2290 return document()->getCachedLocale(computeInheritedLanguage());
2291}
2292
2293void Element::cancelFocusAppearanceUpdate()
2294{
2295 if (hasRareData())
2296 elementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
2297 if (document()->focusedNode() == this)
2298 document()->cancelFocusAppearanceUpdate();
2299}
2300
2301void Element::normalizeAttributes()
2302{
2303 if (!hasAttributes())
2304 return;
2305 for (unsigned i = 0; i < attributeCount(); ++i) {
2306 if (RefPtr<Attr> attr = attrIfExists(attributeItem(i)->name()))
2307 attr->normalize();
2308 }
2309}
2310
2311void Element::updatePseudoElement(PseudoId pseudoId, StyleChange change)
2312{
2313 PseudoElement* element = pseudoElement(pseudoId);
2314 if (element && (needsStyleRecalc() || shouldRecalcStyle(change, element))) {
2315 // PseudoElement styles hang off their parent element's style so if we needed
2316 // a style recalc we should Force one on the pseudo.
2317 element->recalcStyle(needsStyleRecalc() ? Force : change);
2318
2319 // Wait until our parent is not displayed or pseudoElementRendererIsNeeded
2320 // is false, otherwise we could continously create and destroy PseudoElements
2321 // when RenderObject::isChildAllowed on our parent returns false for the
2322 // PseudoElement's renderer for each style recalc.
2323 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01002324 elementRareData()->setPseudoElement(pseudoId, 0);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002325 } else if (change >= Inherit || needsStyleRecalc())
2326 createPseudoElementIfNeeded(pseudoId);
2327}
2328
2329void Element::createPseudoElementIfNeeded(PseudoId pseudoId)
2330{
2331 if (!document()->styleSheetCollection()->usesBeforeAfterRules())
2332 return;
2333
2334 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
2335 return;
2336
2337 if (!renderer()->canHaveGeneratedChildren())
2338 return;
2339
2340 ASSERT(!isPseudoElement());
2341 RefPtr<PseudoElement> element = PseudoElement::create(this, pseudoId);
2342 element->attach();
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01002343 ensureElementRareData()->setPseudoElement(pseudoId, element.release());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002344}
2345
2346PseudoElement* Element::pseudoElement(PseudoId pseudoId) const
2347{
2348 return hasRareData() ? elementRareData()->pseudoElement(pseudoId) : 0;
2349}
2350
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002351RenderObject* Element::pseudoElementRenderer(PseudoId pseudoId) const
2352{
2353 if (PseudoElement* element = pseudoElement(pseudoId))
2354 return element->renderer();
2355 return 0;
2356}
2357
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002358bool Element::matchesReadOnlyPseudoClass() const
2359{
2360 return false;
2361}
2362
2363bool Element::matchesReadWritePseudoClass() const
2364{
2365 return false;
2366}
2367
2368bool Element::webkitMatchesSelector(const String& selector, ExceptionCode& ec)
2369{
2370 if (selector.isEmpty()) {
2371 ec = SYNTAX_ERR;
2372 return false;
2373 }
2374
2375 SelectorQuery* selectorQuery = document()->selectorQueryCache()->add(selector, document(), ec);
2376 if (!selectorQuery)
2377 return false;
2378 return selectorQuery->matches(this);
2379}
2380
2381bool Element::shouldAppearIndeterminate() const
2382{
2383 return false;
2384}
2385
2386DOMTokenList* Element::classList()
2387{
2388 ElementRareData* data = ensureElementRareData();
2389 if (!data->classList())
2390 data->setClassList(ClassList::create(this));
2391 return data->classList();
2392}
2393
2394DOMStringMap* Element::dataset()
2395{
2396 ElementRareData* data = ensureElementRareData();
2397 if (!data->dataset())
2398 data->setDataset(DatasetDOMStringMap::create(this));
2399 return data->dataset();
2400}
2401
2402KURL Element::getURLAttribute(const QualifiedName& name) const
2403{
2404#if !ASSERT_DISABLED
2405 if (elementData()) {
2406 if (const Attribute* attribute = getAttributeItem(name))
2407 ASSERT(isURLAttribute(*attribute));
2408 }
2409#endif
2410 return document()->completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
2411}
2412
2413KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
2414{
2415#if !ASSERT_DISABLED
2416 if (elementData()) {
2417 if (const Attribute* attribute = getAttributeItem(name))
2418 ASSERT(isURLAttribute(*attribute));
2419 }
2420#endif
2421 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
2422 if (value.isEmpty())
2423 return KURL();
2424 return document()->completeURL(value);
2425}
2426
2427int Element::getIntegralAttribute(const QualifiedName& attributeName) const
2428{
2429 return getAttribute(attributeName).string().toInt();
2430}
2431
2432void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
2433{
2434 // FIXME: Need an AtomicString version of String::number.
2435 setAttribute(attributeName, String::number(value));
2436}
2437
2438unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
2439{
2440 return getAttribute(attributeName).string().toUInt();
2441}
2442
2443void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
2444{
2445 // FIXME: Need an AtomicString version of String::number.
2446 setAttribute(attributeName, String::number(value));
2447}
2448
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002449bool Element::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
2450{
2451 // Only create renderers for SVG elements whose parents are SVG elements, or for proper <svg xmlns="svgNS"> subdocuments.
2452 if (childContext.node()->isSVGElement())
2453 return childContext.node()->hasTagName(SVGNames::svgTag) || isSVGElement();
2454
2455 return ContainerNode::childShouldCreateRenderer(childContext);
2456}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002457
2458void Element::webkitRequestFullscreen()
2459{
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01002460 FullscreenController::from(document())->requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, FullscreenController::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002461}
2462
2463void Element::webkitRequestFullScreen(unsigned short flags)
2464{
Torne (Richard Coles)521d96e2013-06-19 11:58:24 +01002465 FullscreenController::from(document())->requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), FullscreenController::EnforceIFrameAllowFullScreenRequirement);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002466}
2467
2468bool Element::containsFullScreenElement() const
2469{
2470 return hasRareData() && elementRareData()->containsFullScreenElement();
2471}
2472
2473void Element::setContainsFullScreenElement(bool flag)
2474{
2475 ensureElementRareData()->setContainsFullScreenElement(flag);
2476 setNeedsStyleRecalc(SyntheticStyleChange);
2477}
2478
2479static Element* parentCrossingFrameBoundaries(Element* element)
2480{
2481 ASSERT(element);
2482 return element->parentElement() ? element->parentElement() : element->document()->ownerElement();
2483}
2484
2485void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool flag)
2486{
2487 Element* element = this;
2488 while ((element = parentCrossingFrameBoundaries(element)))
2489 element->setContainsFullScreenElement(flag);
2490}
2491
2492bool Element::isInTopLayer() const
2493{
2494 return hasRareData() && elementRareData()->isInTopLayer();
2495}
2496
2497void Element::setIsInTopLayer(bool inTopLayer)
2498{
2499 if (isInTopLayer() == inTopLayer)
2500 return;
2501 ensureElementRareData()->setIsInTopLayer(inTopLayer);
2502
2503 // We must ensure a reattach occurs so the renderer is inserted in the correct sibling order under RenderView according to its
2504 // top layer position, or in its usual place if not in the top layer.
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002505 lazyReattachIfAttached();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002506}
2507
2508void Element::webkitRequestPointerLock()
2509{
2510 if (document()->page())
2511 document()->page()->pointerLockController()->requestPointerLock(this);
2512}
2513
2514SpellcheckAttributeState Element::spellcheckAttributeState() const
2515{
2516 const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
2517 if (value == nullAtom)
2518 return SpellcheckAttributeDefault;
2519 if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
2520 return SpellcheckAttributeTrue;
2521 if (equalIgnoringCase(value, "false"))
2522 return SpellcheckAttributeFalse;
2523
2524 return SpellcheckAttributeDefault;
2525}
2526
2527bool Element::isSpellCheckingEnabled() const
2528{
2529 for (const Element* element = this; element; element = element->parentOrShadowHostElement()) {
2530 switch (element->spellcheckAttributeState()) {
2531 case SpellcheckAttributeTrue:
2532 return true;
2533 case SpellcheckAttributeFalse:
2534 return false;
2535 case SpellcheckAttributeDefault:
2536 break;
2537 }
2538 }
2539
2540 return true;
2541}
2542
2543RenderRegion* Element::renderRegion() const
2544{
2545 if (renderer() && renderer()->isRenderRegion())
2546 return toRenderRegion(renderer());
2547
2548 return 0;
2549}
2550
2551const AtomicString& Element::webkitRegionOverset() const
2552{
2553 document()->updateLayoutIgnorePendingStylesheets();
2554
2555 DEFINE_STATIC_LOCAL(AtomicString, undefinedState, ("undefined", AtomicString::ConstructFromLiteral));
2556 if (!RuntimeEnabledFeatures::cssRegionsEnabled() || !renderRegion())
2557 return undefinedState;
2558
2559 switch (renderRegion()->regionState()) {
2560 case RenderRegion::RegionFit: {
2561 DEFINE_STATIC_LOCAL(AtomicString, fitState, ("fit", AtomicString::ConstructFromLiteral));
2562 return fitState;
2563 }
2564 case RenderRegion::RegionEmpty: {
2565 DEFINE_STATIC_LOCAL(AtomicString, emptyState, ("empty", AtomicString::ConstructFromLiteral));
2566 return emptyState;
2567 }
2568 case RenderRegion::RegionOverset: {
2569 DEFINE_STATIC_LOCAL(AtomicString, overflowState, ("overset", AtomicString::ConstructFromLiteral));
2570 return overflowState;
2571 }
2572 case RenderRegion::RegionUndefined:
2573 return undefinedState;
2574 }
2575
2576 ASSERT_NOT_REACHED();
2577 return undefinedState;
2578}
2579
2580Vector<RefPtr<Range> > Element::webkitGetRegionFlowRanges() const
2581{
2582 document()->updateLayoutIgnorePendingStylesheets();
2583
2584 Vector<RefPtr<Range> > rangeObjects;
2585 if (RuntimeEnabledFeatures::cssRegionsEnabled() && renderer() && renderer()->isRenderRegion()) {
2586 RenderRegion* region = toRenderRegion(renderer());
2587 if (region->isValid())
2588 region->getRanges(rangeObjects);
2589 }
2590
2591 return rangeObjects;
2592}
2593
2594#ifndef NDEBUG
2595bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
2596{
2597 if (name == HTMLNames::styleAttr)
2598 return false;
2599
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002600 if (isSVGElement())
2601 return !static_cast<const SVGElement*>(this)->isAnimatableAttribute(name);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002602
2603 return true;
2604}
2605#endif
2606
2607#ifdef DUMP_NODE_STATISTICS
2608bool Element::hasNamedNodeMap() const
2609{
2610 return hasRareData() && elementRareData()->attributeMap();
2611}
2612#endif
2613
2614inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName)
2615{
2616 if (!inDocument() || isInShadowTree())
2617 return;
2618
2619 if (oldName == newName)
2620 return;
2621
2622 if (shouldRegisterAsNamedItem())
2623 updateNamedItemRegistration(oldName, newName);
2624}
2625
2626inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
2627{
2628 if (!isInTreeScope())
2629 return;
2630
2631 if (oldId == newId)
2632 return;
2633
2634 updateId(treeScope(), oldId, newId);
2635}
2636
2637inline void Element::updateId(TreeScope* scope, const AtomicString& oldId, const AtomicString& newId)
2638{
2639 ASSERT(isInTreeScope());
2640 ASSERT(oldId != newId);
2641
2642 if (!oldId.isEmpty())
2643 scope->removeElementById(oldId, this);
2644 if (!newId.isEmpty())
2645 scope->addElementById(newId, this);
2646
2647 if (shouldRegisterAsExtraNamedItem())
2648 updateExtraNamedItemRegistration(oldId, newId);
2649}
2650
2651void Element::updateLabel(TreeScope* scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
2652{
2653 ASSERT(hasTagName(labelTag));
2654
2655 if (!inDocument())
2656 return;
2657
2658 if (oldForAttributeValue == newForAttributeValue)
2659 return;
2660
2661 if (!oldForAttributeValue.isEmpty())
2662 scope->removeLabel(oldForAttributeValue, static_cast<HTMLLabelElement*>(this));
2663 if (!newForAttributeValue.isEmpty())
2664 scope->addLabel(newForAttributeValue, static_cast<HTMLLabelElement*>(this));
2665}
2666
2667void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
2668{
2669 if (isIdAttributeName(name))
2670 updateId(oldValue, newValue);
2671 else if (name == HTMLNames::nameAttr)
2672 updateName(oldValue, newValue);
2673 else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
2674 TreeScope* scope = treeScope();
2675 if (scope->shouldCacheLabelsByForAttribute())
2676 updateLabel(scope, oldValue, newValue);
2677 }
2678
2679 if (oldValue != newValue) {
2680 if (attached() && document()->styleResolver() && document()->styleResolver()->hasSelectorForAttribute(name.localName()))
2681 setNeedsStyleRecalc();
2682 }
2683
2684 if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(this, name))
2685 recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue));
2686
2687 InspectorInstrumentation::willModifyDOMAttr(document(), this, oldValue, newValue);
2688}
2689
2690void Element::didAddAttribute(const QualifiedName& name, const AtomicString& value)
2691{
2692 attributeChanged(name, value);
2693 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value);
2694 dispatchSubtreeModifiedEvent();
2695}
2696
2697void Element::didModifyAttribute(const QualifiedName& name, const AtomicString& value)
2698{
2699 attributeChanged(name, value);
2700 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value);
2701 // Do not dispatch a DOMSubtreeModified event here; see bug 81141.
2702}
2703
2704void Element::didRemoveAttribute(const QualifiedName& name)
2705{
2706 attributeChanged(name, nullAtom);
2707 InspectorInstrumentation::didRemoveDOMAttr(document(), this, name.localName());
2708 dispatchSubtreeModifiedEvent();
2709}
2710
2711
2712void Element::updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName)
2713{
2714 if (!document()->isHTMLDocument())
2715 return;
2716
2717 if (!oldName.isEmpty())
2718 toHTMLDocument(document())->removeNamedItem(oldName);
2719
2720 if (!newName.isEmpty())
2721 toHTMLDocument(document())->addNamedItem(newName);
2722}
2723
2724void Element::updateExtraNamedItemRegistration(const AtomicString& oldId, const AtomicString& newId)
2725{
2726 if (!document()->isHTMLDocument())
2727 return;
2728
2729 if (!oldId.isEmpty())
2730 toHTMLDocument(document())->removeExtraNamedItem(oldId);
2731
2732 if (!newId.isEmpty())
2733 toHTMLDocument(document())->addExtraNamedItem(newId);
2734}
2735
2736PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
2737{
2738 if (HTMLCollection* collection = cachedHTMLCollection(type))
2739 return collection;
2740
2741 RefPtr<HTMLCollection> collection;
2742 if (type == TableRows) {
2743 ASSERT(hasTagName(tableTag));
2744 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
2745 } else if (type == SelectOptions) {
2746 ASSERT(hasTagName(selectTag));
2747 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
2748 } else if (type == FormControls) {
2749 ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
2750 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
2751 }
2752 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLCollection>(this, type);
2753}
2754
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002755static void needsSyntheticStyleChangeCallback(Node* node)
2756{
2757 node->setNeedsStyleRecalc(SyntheticStyleChange);
2758}
2759
2760void Element::scheduleSyntheticStyleChange()
2761{
2762 if (postAttachCallbacksAreSuspended())
2763 queuePostAttachCallback(needsSyntheticStyleChangeCallback, this);
2764 else
2765 setNeedsStyleRecalc(SyntheticStyleChange);
2766}
2767
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002768HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
2769{
2770 return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0;
2771}
2772
2773IntSize Element::savedLayerScrollOffset() const
2774{
2775 return hasRareData() ? elementRareData()->savedLayerScrollOffset() : IntSize();
2776}
2777
2778void Element::setSavedLayerScrollOffset(const IntSize& size)
2779{
2780 if (size.isZero() && !hasRareData())
2781 return;
2782 ensureElementRareData()->setSavedLayerScrollOffset(size);
2783}
2784
2785PassRefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
2786{
2787 if (AttrNodeList* attrNodeList = attrNodeListForElement(this))
2788 return findAttrNodeInList(attrNodeList, name);
2789 return 0;
2790}
2791
2792PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name)
2793{
2794 AttrNodeList* attrNodeList = ensureAttrNodeListForElement(this);
2795 RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
2796 if (!attrNode) {
2797 attrNode = Attr::create(this, name);
2798 treeScope()->adoptIfNeeded(attrNode.get());
2799 attrNodeList->append(attrNode);
2800 }
2801 return attrNode.release();
2802}
2803
2804void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value)
2805{
2806 ASSERT(hasSyntheticAttrChildNodes());
2807 attrNode->detachFromElementWithValue(value);
2808
2809 AttrNodeList* attrNodeList = attrNodeListForElement(this);
2810 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
2811 if (attrNodeList->at(i)->qualifiedName() == attrNode->qualifiedName()) {
2812 attrNodeList->remove(i);
2813 if (attrNodeList->isEmpty())
2814 removeAttrNodeListForElement(this);
2815 return;
2816 }
2817 }
2818 ASSERT_NOT_REACHED();
2819}
2820
2821void Element::detachAllAttrNodesFromElement()
2822{
2823 AttrNodeList* attrNodeList = attrNodeListForElement(this);
2824 ASSERT(attrNodeList);
2825
2826 for (unsigned i = 0; i < attributeCount(); ++i) {
2827 const Attribute* attribute = attributeItem(i);
2828 if (RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, attribute->name()))
2829 attrNode->detachFromElementWithValue(attribute->value());
2830 }
2831
2832 removeAttrNodeListForElement(this);
2833}
2834
2835void Element::willRecalcStyle(StyleChange)
2836{
2837 ASSERT(hasCustomStyleCallbacks());
2838}
2839
2840void Element::didRecalcStyle(StyleChange)
2841{
2842 ASSERT(hasCustomStyleCallbacks());
2843}
2844
2845
2846PassRefPtr<RenderStyle> Element::customStyleForRenderer()
2847{
2848 ASSERT(hasCustomStyleCallbacks());
2849 return 0;
2850}
2851
2852void Element::cloneAttributesFromElement(const Element& other)
2853{
2854 if (hasSyntheticAttrChildNodes())
2855 detachAllAttrNodesFromElement();
2856
2857 other.synchronizeAllAttributes();
2858 if (!other.m_elementData) {
2859 m_elementData.clear();
2860 return;
2861 }
2862
2863 const AtomicString& oldID = getIdAttribute();
2864 const AtomicString& newID = other.getIdAttribute();
2865
2866 if (!oldID.isNull() || !newID.isNull())
2867 updateId(oldID, newID);
2868
2869 const AtomicString& oldName = getNameAttribute();
2870 const AtomicString& newName = other.getNameAttribute();
2871
2872 if (!oldName.isNull() || !newName.isNull())
2873 updateName(oldName, newName);
2874
2875 // If 'other' has a mutable ElementData, convert it to an immutable one so we can share it between both elements.
2876 // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes.
2877 if (other.m_elementData->isUnique()
2878 && !other.m_elementData->presentationAttributeStyle()
2879 && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper()))
2880 const_cast<Element&>(other).m_elementData = static_cast<const UniqueElementData*>(other.m_elementData.get())->makeShareableCopy();
2881
2882 if (!other.m_elementData->isUnique())
2883 m_elementData = other.m_elementData;
2884 else
2885 m_elementData = other.m_elementData->makeUniqueCopy();
2886
2887 for (unsigned i = 0; i < m_elementData->length(); ++i) {
2888 const Attribute* attribute = const_cast<const ElementData*>(m_elementData.get())->attributeItem(i);
2889 attributeChangedFromParserOrByCloning(attribute->name(), attribute->value(), ModifiedByCloning);
2890 }
2891}
2892
2893void Element::cloneDataFromElement(const Element& other)
2894{
2895 cloneAttributesFromElement(other);
2896 copyNonAttributePropertiesFromElement(other);
2897}
2898
2899void Element::createUniqueElementData()
2900{
2901 if (!m_elementData)
2902 m_elementData = UniqueElementData::create();
2903 else {
2904 ASSERT(!m_elementData->isUnique());
2905 m_elementData = static_cast<ShareableElementData*>(m_elementData.get())->makeUniqueCopy();
2906 }
2907}
2908
2909void Element::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
2910{
2911 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
2912 ContainerNode::reportMemoryUsage(memoryObjectInfo);
2913 info.addMember(m_tagName, "tagName");
2914 info.addMember(m_elementData, "elementData");
2915}
2916
Torne (Richard Coles)81a51572013-05-13 16:52:28 +01002917InputMethodContext* Element::getInputContext()
2918{
2919 return ensureElementRareData()->ensureInputMethodContext(toHTMLElement(this));
2920}
2921
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002922bool Element::hasPendingResources() const
2923{
2924 return hasRareData() && elementRareData()->hasPendingResources();
2925}
2926
2927void Element::setHasPendingResources()
2928{
2929 ensureElementRareData()->setHasPendingResources(true);
2930}
2931
2932void Element::clearHasPendingResources()
2933{
2934 ensureElementRareData()->setHasPendingResources(false);
2935}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002936
2937void ElementData::deref()
2938{
2939 if (!derefBase())
2940 return;
2941
2942 if (m_isUnique)
2943 delete static_cast<UniqueElementData*>(this);
2944 else
2945 delete static_cast<ShareableElementData*>(this);
2946}
2947
2948ElementData::ElementData()
2949 : m_isUnique(true)
2950 , m_arraySize(0)
2951 , m_presentationAttributeStyleIsDirty(false)
2952 , m_styleAttributeIsDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002953 , m_animatedSVGAttributesAreDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002954{
2955}
2956
2957ElementData::ElementData(unsigned arraySize)
2958 : m_isUnique(false)
2959 , m_arraySize(arraySize)
2960 , m_presentationAttributeStyleIsDirty(false)
2961 , m_styleAttributeIsDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002962 , m_animatedSVGAttributesAreDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002963{
2964}
2965
2966struct SameSizeAsElementData : public RefCounted<SameSizeAsElementData> {
2967 unsigned bitfield;
2968 void* refPtrs[3];
2969};
2970
2971COMPILE_ASSERT(sizeof(ElementData) == sizeof(SameSizeAsElementData), element_attribute_data_should_stay_small);
2972
2973static size_t sizeForShareableElementDataWithAttributeCount(unsigned count)
2974{
2975 return sizeof(ShareableElementData) + sizeof(Attribute) * count;
2976}
2977
2978PassRefPtr<ShareableElementData> ShareableElementData::createWithAttributes(const Vector<Attribute>& attributes)
2979{
2980 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(attributes.size()));
2981 return adoptRef(new (slot) ShareableElementData(attributes));
2982}
2983
2984PassRefPtr<UniqueElementData> UniqueElementData::create()
2985{
2986 return adoptRef(new UniqueElementData);
2987}
2988
2989ShareableElementData::ShareableElementData(const Vector<Attribute>& attributes)
2990 : ElementData(attributes.size())
2991{
2992 for (unsigned i = 0; i < m_arraySize; ++i)
2993 new (&m_attributeArray[i]) Attribute(attributes[i]);
2994}
2995
2996ShareableElementData::~ShareableElementData()
2997{
2998 for (unsigned i = 0; i < m_arraySize; ++i)
2999 m_attributeArray[i].~Attribute();
3000}
3001
3002ShareableElementData::ShareableElementData(const UniqueElementData& other)
3003 : ElementData(other, false)
3004{
3005 ASSERT(!other.m_presentationAttributeStyle);
3006
3007 if (other.m_inlineStyle) {
3008 ASSERT(!other.m_inlineStyle->hasCSSOMWrapper());
3009 m_inlineStyle = other.m_inlineStyle->immutableCopyIfNeeded();
3010 }
3011
3012 for (unsigned i = 0; i < m_arraySize; ++i)
3013 new (&m_attributeArray[i]) Attribute(other.m_attributeVector.at(i));
3014}
3015
3016ElementData::ElementData(const ElementData& other, bool isUnique)
3017 : m_isUnique(isUnique)
3018 , m_arraySize(isUnique ? 0 : other.length())
3019 , m_presentationAttributeStyleIsDirty(other.m_presentationAttributeStyleIsDirty)
3020 , m_styleAttributeIsDirty(other.m_styleAttributeIsDirty)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003021 , m_animatedSVGAttributesAreDirty(other.m_animatedSVGAttributesAreDirty)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003022 , m_classNames(other.m_classNames)
3023 , m_idForStyleResolution(other.m_idForStyleResolution)
3024{
3025 // NOTE: The inline style is copied by the subclass copy constructor since we don't know what to do with it here.
3026}
3027
3028UniqueElementData::UniqueElementData()
3029{
3030}
3031
3032UniqueElementData::UniqueElementData(const UniqueElementData& other)
3033 : ElementData(other, true)
3034 , m_presentationAttributeStyle(other.m_presentationAttributeStyle)
3035 , m_attributeVector(other.m_attributeVector)
3036{
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01003037 m_inlineStyle = other.m_inlineStyle ? other.m_inlineStyle->mutableCopy() : 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003038}
3039
3040UniqueElementData::UniqueElementData(const ShareableElementData& other)
3041 : ElementData(other, true)
3042{
3043 // An ShareableElementData should never have a mutable inline StylePropertySet attached.
3044 ASSERT(!other.m_inlineStyle || !other.m_inlineStyle->isMutable());
3045 m_inlineStyle = other.m_inlineStyle;
3046
3047 m_attributeVector.reserveCapacity(other.length());
3048 for (unsigned i = 0; i < other.length(); ++i)
3049 m_attributeVector.uncheckedAppend(other.m_attributeArray[i]);
3050}
3051
3052PassRefPtr<UniqueElementData> ElementData::makeUniqueCopy() const
3053{
3054 if (isUnique())
3055 return adoptRef(new UniqueElementData(static_cast<const UniqueElementData&>(*this)));
3056 return adoptRef(new UniqueElementData(static_cast<const ShareableElementData&>(*this)));
3057}
3058
3059PassRefPtr<ShareableElementData> UniqueElementData::makeShareableCopy() const
3060{
3061 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(m_attributeVector.size()));
3062 return adoptRef(new (slot) ShareableElementData(*this));
3063}
3064
3065void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value)
3066{
3067 m_attributeVector.append(Attribute(attributeName, value));
3068}
3069
3070void UniqueElementData::removeAttribute(size_t index)
3071{
3072 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
3073 m_attributeVector.remove(index);
3074}
3075
3076bool ElementData::isEquivalent(const ElementData* other) const
3077{
3078 if (!other)
3079 return isEmpty();
3080
3081 unsigned len = length();
3082 if (len != other->length())
3083 return false;
3084
3085 for (unsigned i = 0; i < len; i++) {
3086 const Attribute* attribute = attributeItem(i);
3087 const Attribute* otherAttr = other->getAttributeItem(attribute->name());
3088 if (!otherAttr || attribute->value() != otherAttr->value())
3089 return false;
3090 }
3091
3092 return true;
3093}
3094
3095void ElementData::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
3096{
3097 size_t actualSize = m_isUnique ? sizeof(ElementData) : sizeForShareableElementDataWithAttributeCount(m_arraySize);
3098 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM, actualSize);
3099 info.addMember(m_inlineStyle, "inlineStyle");
3100 info.addMember(m_classNames, "classNames");
3101 info.addMember(m_idForStyleResolution, "idForStyleResolution");
3102 if (m_isUnique) {
3103 const UniqueElementData* uniqueThis = static_cast<const UniqueElementData*>(this);
3104 info.addMember(uniqueThis->m_presentationAttributeStyle, "presentationAttributeStyle");
3105 info.addMember(uniqueThis->m_attributeVector, "attributeVector");
3106 }
3107 for (unsigned i = 0, len = length(); i < len; i++)
3108 info.addMember(*attributeItem(i), "*attributeItem");
3109}
3110
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01003111size_t ElementData::getAttrIndex(Attr* attr) const
3112{
3113 // This relies on the fact that Attr's QualifiedName == the Attribute's name.
3114 for (unsigned i = 0; i < length(); ++i) {
3115 if (attributeItem(i)->name() == attr->qualifiedName())
3116 return i;
3117 }
3118 return notFound;
3119}
3120
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003121size_t ElementData::getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const
3122{
3123 // Continue to checking case-insensitively and/or full namespaced names if necessary:
3124 for (unsigned i = 0; i < length(); ++i) {
3125 const Attribute* attribute = attributeItem(i);
3126 if (!attribute->name().hasPrefix()) {
3127 if (shouldIgnoreAttributeCase && equalIgnoringCase(name, attribute->localName()))
3128 return i;
3129 } else {
3130 // FIXME: Would be faster to do this comparison without calling toString, which
3131 // generates a temporary string by concatenation. But this branch is only reached
3132 // if the attribute name has a prefix, which is rare in HTML.
3133 if (equalPossiblyIgnoringCase(name, attribute->name().toString(), shouldIgnoreAttributeCase))
3134 return i;
3135 }
3136 }
3137 return notFound;
3138}
3139
3140Attribute* UniqueElementData::getAttributeItem(const QualifiedName& name)
3141{
3142 for (unsigned i = 0; i < length(); ++i) {
3143 if (m_attributeVector.at(i).name().matches(name))
3144 return &m_attributeVector.at(i);
3145 }
3146 return 0;
3147}
3148
3149Attribute* UniqueElementData::attributeItem(unsigned index)
3150{
3151 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
3152 return &m_attributeVector.at(index);
3153}
3154
3155} // namespace WebCore