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