blob: 1f96a0e356a8e2a03fc3bb2e678720f2bf425fcb [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)
1144bool Element::isDateTimeFieldElement() const
1145{
1146 return false;
1147}
1148#endif
1149
1150bool Element::wasChangedSinceLastFormControlChangeEvent() const
1151{
1152 return false;
1153}
1154
1155void Element::setChangedSinceLastFormControlChangeEvent(bool)
1156{
1157}
1158
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001159bool Element::isInert() const
1160{
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001161 const Element* dialog = document()->activeModalDialog();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001162 return dialog && !containsIncludingShadowDOM(dialog) && !dialog->containsIncludingShadowDOM(this);
1163}
1164
1165Node::InsertionNotificationRequest Element::insertedInto(ContainerNode* insertionPoint)
1166{
1167 // need to do superclass processing first so inDocument() is true
1168 // by the time we reach updateId
1169 ContainerNode::insertedInto(insertionPoint);
1170
1171 if (containsFullScreenElement() && parentElement() && !parentElement()->containsFullScreenElement())
1172 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(true);
1173
1174 if (Element* before = pseudoElement(BEFORE))
1175 before->insertedInto(insertionPoint);
1176
1177 if (Element* after = pseudoElement(AFTER))
1178 after->insertedInto(insertionPoint);
1179
1180 if (!insertionPoint->isInTreeScope())
1181 return InsertionDone;
1182
1183 if (hasRareData())
1184 elementRareData()->clearClassListValueForQuirksMode();
1185
1186 TreeScope* scope = insertionPoint->treeScope();
1187 if (scope != treeScope())
1188 return InsertionDone;
1189
1190 const AtomicString& idValue = getIdAttribute();
1191 if (!idValue.isNull())
1192 updateId(scope, nullAtom, idValue);
1193
1194 const AtomicString& nameValue = getNameAttribute();
1195 if (!nameValue.isNull())
1196 updateName(nullAtom, nameValue);
1197
1198 if (hasTagName(labelTag)) {
1199 if (scope->shouldCacheLabelsByForAttribute())
1200 updateLabel(scope, nullAtom, fastGetAttribute(forAttr));
1201 }
1202
1203 return InsertionDone;
1204}
1205
1206void Element::removedFrom(ContainerNode* insertionPoint)
1207{
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001208 bool wasInDocument = insertionPoint->document();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001209
1210 if (Element* before = pseudoElement(BEFORE))
1211 before->removedFrom(insertionPoint);
1212
1213 if (Element* after = pseudoElement(AFTER))
1214 after->removedFrom(insertionPoint);
1215
1216 document()->removeFromTopLayer(this);
1217 if (containsFullScreenElement())
1218 setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(false);
1219
1220 if (document()->page())
1221 document()->page()->pointerLockController()->elementRemoved(this);
1222
1223 setSavedLayerScrollOffset(IntSize());
1224
1225 if (insertionPoint->isInTreeScope() && treeScope() == document()) {
1226 const AtomicString& idValue = getIdAttribute();
1227 if (!idValue.isNull())
1228 updateId(insertionPoint->treeScope(), idValue, nullAtom);
1229
1230 const AtomicString& nameValue = getNameAttribute();
1231 if (!nameValue.isNull())
1232 updateName(nameValue, nullAtom);
1233
1234 if (hasTagName(labelTag)) {
1235 TreeScope* treeScope = insertionPoint->treeScope();
1236 if (treeScope->shouldCacheLabelsByForAttribute())
1237 updateLabel(treeScope, fastGetAttribute(forAttr), nullAtom);
1238 }
1239 }
1240
1241 ContainerNode::removedFrom(insertionPoint);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001242 if (wasInDocument && hasPendingResources())
1243 document()->accessSVGExtensions()->removeElementFromPendingResources(this);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001244}
1245
1246void Element::createRendererIfNeeded()
1247{
1248 NodeRenderingContext(this).createRendererForElementIfNeeded();
1249}
1250
1251void Element::attach()
1252{
1253 PostAttachCallbackDisabler callbackDisabler(this);
1254 StyleResolverParentPusher parentPusher(this);
1255 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1256
1257 createRendererIfNeeded();
1258
1259 if (parentElement() && parentElement()->isInCanvasSubtree())
1260 setIsInCanvasSubtree(true);
1261
1262 createPseudoElementIfNeeded(BEFORE);
1263
1264 // When a shadow root exists, it does the work of attaching the children.
1265 if (ElementShadow* shadow = this->shadow()) {
1266 parentPusher.push();
1267 shadow->attach();
1268 } else if (firstChild())
1269 parentPusher.push();
1270
1271 ContainerNode::attach();
1272
1273 createPseudoElementIfNeeded(AFTER);
1274
1275 if (hasRareData()) {
1276 ElementRareData* data = elementRareData();
1277 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
1278 if (isFocusable() && document()->focusedNode() == this)
1279 document()->updateFocusAppearanceSoon(false /* don't restore selection */);
1280 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1281 }
1282 }
1283}
1284
1285void Element::unregisterNamedFlowContentNode()
1286{
1287 if (RuntimeEnabledFeatures::cssRegionsEnabled() && inNamedFlow() && document()->renderView())
1288 document()->renderView()->flowThreadController()->unregisterNamedFlowContentNode(this);
1289}
1290
1291void Element::detach()
1292{
1293 WidgetHierarchyUpdatesSuspensionScope suspendWidgetHierarchyUpdates;
1294 unregisterNamedFlowContentNode();
1295 cancelFocusAppearanceUpdate();
1296 if (hasRareData()) {
1297 ElementRareData* data = elementRareData();
1298 data->setPseudoElement(BEFORE, 0);
1299 data->setPseudoElement(AFTER, 0);
1300 data->setIsInCanvasSubtree(false);
1301 data->resetComputedStyle();
1302 data->resetDynamicRestyleObservations();
1303 }
1304
1305 if (ElementShadow* shadow = this->shadow()) {
1306 detachChildrenIfNeeded();
1307 shadow->detach();
1308 }
1309 ContainerNode::detach();
1310}
1311
1312bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle)
1313{
1314 ASSERT(currentStyle == renderStyle());
1315 ASSERT(renderer());
1316
1317 if (!currentStyle)
1318 return false;
1319
1320 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles();
1321 if (!pseudoStyleCache)
1322 return false;
1323
1324 size_t cacheSize = pseudoStyleCache->size();
1325 for (size_t i = 0; i < cacheSize; ++i) {
1326 RefPtr<RenderStyle> newPseudoStyle;
1327 PseudoId pseudoId = pseudoStyleCache->at(i)->styleType();
1328 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
1329 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle);
1330 else
1331 newPseudoStyle = renderer()->getUncachedPseudoStyle(PseudoStyleRequest(pseudoId), newStyle, newStyle);
1332 if (!newPseudoStyle)
1333 return true;
1334 if (*newPseudoStyle != *pseudoStyleCache->at(i)) {
1335 if (pseudoId < FIRST_INTERNAL_PSEUDOID)
1336 newStyle->setHasPseudoStyle(pseudoId);
1337 newStyle->addCachedPseudoStyle(newPseudoStyle);
1338 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
1339 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
1340 // is needed, but for now just assume a layout will be required. The diff code
1341 // in RenderObject::setStyle would need to be factored out so that it could be reused.
1342 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
1343 }
1344 return true;
1345 }
1346 }
1347 return false;
1348}
1349
1350PassRefPtr<RenderStyle> Element::styleForRenderer()
1351{
1352 if (hasCustomStyleCallbacks()) {
1353 if (RefPtr<RenderStyle> style = customStyleForRenderer())
1354 return style.release();
1355 }
1356
1357 return document()->styleResolver()->styleForElement(this);
1358}
1359
1360void Element::recalcStyle(StyleChange change)
1361{
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001362 ASSERT(document()->inStyleRecalc());
1363
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001364 if (hasCustomStyleCallbacks())
1365 willRecalcStyle(change);
1366
1367 // Ref currentStyle in case it would otherwise be deleted when setting the new style in the renderer.
1368 RefPtr<RenderStyle> currentStyle(renderStyle());
1369 bool hasParentStyle = parentNodeForRenderingAndStyle() ? static_cast<bool>(parentNodeForRenderingAndStyle()->renderStyle()) : false;
1370 bool hasDirectAdjacentRules = childrenAffectedByDirectAdjacentRules();
1371 bool hasIndirectAdjacentRules = childrenAffectedByForwardPositionalRules();
1372
1373 if ((change > NoChange || needsStyleRecalc())) {
1374 if (hasRareData())
1375 elementRareData()->resetComputedStyle();
1376 }
1377 if (hasParentStyle && (change >= Inherit || needsStyleRecalc())) {
1378 StyleChange localChange = Detach;
1379 RefPtr<RenderStyle> newStyle;
1380 if (currentStyle) {
1381 // FIXME: This still recalcs style twice when changing display types, but saves
1382 // us from recalcing twice when going from none -> anything else which is more
1383 // common, especially during lazy attach.
1384 newStyle = styleForRenderer();
1385 localChange = Node::diff(currentStyle.get(), newStyle.get(), document());
1386 }
1387 if (localChange == Detach) {
1388 // FIXME: The style gets computed twice by calling attach. We could do better if we passed the style along.
1389 reattach();
1390 // attach recalculates the style for all children. No need to do it twice.
1391 clearNeedsStyleRecalc();
1392 clearChildNeedsStyleRecalc();
1393
1394 if (hasCustomStyleCallbacks())
1395 didRecalcStyle(change);
1396 return;
1397 }
1398
1399 if (RenderObject* renderer = this->renderer()) {
1400 if (localChange != NoChange || pseudoStyleCacheIsInvalid(currentStyle.get(), newStyle.get()) || (change == Force && renderer->requiresForcedStyleRecalcPropagation()) || styleChangeType() == SyntheticStyleChange)
1401 renderer->setAnimatableStyle(newStyle.get());
1402 else if (needsStyleRecalc()) {
1403 // Although no change occurred, we use the new style so that the cousin style sharing code won't get
1404 // fooled into believing this style is the same.
1405 renderer->setStyleInternal(newStyle.get());
1406 }
1407 }
1408
1409 // 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
1410 // 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).
1411 if (document()->styleSheetCollection()->usesRemUnits() && document()->documentElement() == this && localChange != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize()) {
1412 // Cached RenderStyles may depend on the re units.
1413 document()->styleResolver()->invalidateMatchedPropertiesCache();
1414 change = Force;
1415 }
1416
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001417 if (styleChangeType() == FullStyleChange)
1418 change = Force;
1419 else if (change != Force)
1420 change = localChange;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001421 }
1422 StyleResolverParentPusher parentPusher(this);
1423
1424 // FIXME: This does not care about sibling combinators. Will be necessary in XBL2 world.
1425 if (ElementShadow* shadow = this->shadow()) {
1426 if (shouldRecalcStyle(change, shadow)) {
1427 parentPusher.push();
1428 shadow->recalcStyle(change);
1429 }
1430 }
1431
1432 if (shouldRecalcStyle(change, this))
1433 updatePseudoElement(BEFORE, change);
1434
1435 // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
1436 // For now we will just worry about the common case, since it's a lot trickier to get the second case right
1437 // without doing way too much re-resolution.
1438 bool forceCheckOfNextElementSibling = false;
1439 bool forceCheckOfAnyElementSibling = false;
1440 for (Node *n = firstChild(); n; n = n->nextSibling()) {
1441 if (n->isTextNode()) {
1442 toText(n)->recalcTextStyle(change);
1443 continue;
1444 }
1445 if (!n->isElementNode())
1446 continue;
1447 Element* element = toElement(n);
1448 bool childRulesChanged = element->needsStyleRecalc() && element->styleChangeType() == FullStyleChange;
1449 if ((forceCheckOfNextElementSibling || forceCheckOfAnyElementSibling))
1450 element->setNeedsStyleRecalc();
1451 if (shouldRecalcStyle(change, element)) {
1452 parentPusher.push();
1453 element->recalcStyle(change);
1454 }
1455 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
1456 forceCheckOfAnyElementSibling = forceCheckOfAnyElementSibling || (childRulesChanged && hasIndirectAdjacentRules);
1457 }
1458
1459 if (shouldRecalcStyle(change, this))
1460 updatePseudoElement(AFTER, change);
1461
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001462 setAttached();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001463 clearNeedsStyleRecalc();
1464 clearChildNeedsStyleRecalc();
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01001465
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001466 if (hasCustomStyleCallbacks())
1467 didRecalcStyle(change);
1468 InspectorInstrumentation::didRecalculateStyleForElement(this);
1469}
1470
1471ElementShadow* Element::shadow() const
1472{
1473 return hasRareData() ? elementRareData()->shadow() : 0;
1474}
1475
1476ElementShadow* Element::ensureShadow()
1477{
1478 return ensureElementRareData()->ensureShadow();
1479}
1480
1481void Element::didAffectSelector(AffectedSelectorMask mask)
1482{
1483 setNeedsStyleRecalc();
1484 if (ElementShadow* elementShadow = shadowOfParentForDistribution(this))
1485 elementShadow->didAffectSelector(mask);
1486}
1487
1488PassRefPtr<ShadowRoot> Element::createShadowRoot(ExceptionCode& ec)
1489{
1490 if (alwaysCreateUserAgentShadowRoot())
1491 ensureUserAgentShadowRoot();
1492
1493 if (RuntimeEnabledFeatures::authorShadowDOMForAnyElementEnabled())
1494 return ensureShadow()->addShadowRoot(this, ShadowRoot::AuthorShadowRoot);
1495
1496 // Since some elements recreates shadow root dynamically, multiple shadow
1497 // subtrees won't work well in that element. Until they are fixed, we disable
1498 // adding author shadow root for them.
1499 if (!areAuthorShadowsAllowed()) {
1500 ec = HIERARCHY_REQUEST_ERR;
1501 return 0;
1502 }
1503 return ensureShadow()->addShadowRoot(this, ShadowRoot::AuthorShadowRoot);
1504}
1505
1506ShadowRoot* Element::shadowRoot() const
1507{
1508 ElementShadow* elementShadow = shadow();
1509 if (!elementShadow)
1510 return 0;
1511 ShadowRoot* shadowRoot = elementShadow->youngestShadowRoot();
1512 if (shadowRoot->type() == ShadowRoot::AuthorShadowRoot)
1513 return shadowRoot;
1514 return 0;
1515}
1516
1517ShadowRoot* Element::userAgentShadowRoot() const
1518{
1519 if (ElementShadow* elementShadow = shadow()) {
1520 if (ShadowRoot* shadowRoot = elementShadow->oldestShadowRoot()) {
1521 ASSERT(shadowRoot->type() == ShadowRoot::UserAgentShadowRoot);
1522 return shadowRoot;
1523 }
1524 }
1525
1526 return 0;
1527}
1528
1529ShadowRoot* Element::ensureUserAgentShadowRoot()
1530{
1531 if (ShadowRoot* shadowRoot = userAgentShadowRoot())
1532 return shadowRoot;
1533 ShadowRoot* shadowRoot = ensureShadow()->addShadowRoot(this, ShadowRoot::UserAgentShadowRoot);
1534 didAddUserAgentShadowRoot(shadowRoot);
1535 return shadowRoot;
1536}
1537
1538const AtomicString& Element::shadowPseudoId() const
1539{
1540 return pseudo();
1541}
1542
1543bool Element::childTypeAllowed(NodeType type) const
1544{
1545 switch (type) {
1546 case ELEMENT_NODE:
1547 case TEXT_NODE:
1548 case COMMENT_NODE:
1549 case PROCESSING_INSTRUCTION_NODE:
1550 case CDATA_SECTION_NODE:
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001551 return true;
1552 default:
1553 break;
1554 }
1555 return false;
1556}
1557
1558static void checkForEmptyStyleChange(Element* element, RenderStyle* style)
1559{
1560 if (!style && !element->styleAffectedByEmpty())
1561 return;
1562
1563 if (!style || (element->styleAffectedByEmpty() && (!style->emptyState() || element->hasChildNodes())))
1564 element->setNeedsStyleRecalc();
1565}
1566
1567static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
1568 Node* beforeChange, Node* afterChange, int childCountDelta)
1569{
1570 // :empty selector.
1571 checkForEmptyStyleChange(e, style);
1572
1573 if (!style || (e->needsStyleRecalc() && e->childrenAffectedByPositionalRules()))
1574 return;
1575
1576 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1577 // In the DOM case, we only need to do something if |afterChange| is not 0.
1578 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
1579 if (e->childrenAffectedByFirstChildRules() && afterChange) {
1580 // Find our new first child.
1581 Node* newFirstChild = 0;
1582 for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {};
1583
1584 // Find the first element node following |afterChange|
1585 Node* firstElementAfterInsertion = 0;
1586 for (firstElementAfterInsertion = afterChange;
1587 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
1588 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
1589
1590 // This is the insert/append case.
1591 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertion && firstElementAfterInsertion->attached() &&
1592 firstElementAfterInsertion->renderStyle() && firstElementAfterInsertion->renderStyle()->firstChildState())
1593 firstElementAfterInsertion->setNeedsStyleRecalc();
1594
1595 // We also have to handle node removal.
1596 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && (!newFirstChild->renderStyle() || !newFirstChild->renderStyle()->firstChildState()))
1597 newFirstChild->setNeedsStyleRecalc();
1598 }
1599
1600 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1601 // In the DOM case, we only need to do something if |afterChange| is not 0.
1602 if (e->childrenAffectedByLastChildRules() && beforeChange) {
1603 // Find our new last child.
1604 Node* newLastChild = 0;
1605 for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {};
1606
1607 // Find the last element node going backwards from |beforeChange|
1608 Node* lastElementBeforeInsertion = 0;
1609 for (lastElementBeforeInsertion = beforeChange;
1610 lastElementBeforeInsertion && !lastElementBeforeInsertion->isElementNode();
1611 lastElementBeforeInsertion = lastElementBeforeInsertion->previousSibling()) {};
1612
1613 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertion && lastElementBeforeInsertion->attached() &&
1614 lastElementBeforeInsertion->renderStyle() && lastElementBeforeInsertion->renderStyle()->lastChildState())
1615 lastElementBeforeInsertion->setNeedsStyleRecalc();
1616
1617 // 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
1618 // to match now.
1619 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && (!newLastChild->renderStyle() || !newLastChild->renderStyle()->lastChildState()))
1620 newLastChild->setNeedsStyleRecalc();
1621 }
1622
1623 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
1624 // that could be affected by this DOM change.
1625 if (e->childrenAffectedByDirectAdjacentRules() && afterChange) {
1626 Node* firstElementAfterInsertion = 0;
1627 for (firstElementAfterInsertion = afterChange;
1628 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
1629 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
1630 if (firstElementAfterInsertion && firstElementAfterInsertion->attached())
1631 firstElementAfterInsertion->setNeedsStyleRecalc();
1632 }
1633
1634 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
1635 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1636 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
1637 // backward case.
1638 // |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.
1639 // 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
1640 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
1641 if ((e->childrenAffectedByForwardPositionalRules() && afterChange)
1642 || (e->childrenAffectedByBackwardPositionalRules() && beforeChange))
1643 e->setNeedsStyleRecalc();
1644}
1645
1646void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
1647{
1648 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
1649 if (changedByParser)
1650 checkForEmptyStyleChange(this, renderStyle());
1651 else
1652 checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
1653
1654 if (ElementShadow * shadow = this->shadow())
1655 shadow->invalidateDistribution();
1656}
1657
1658void Element::removeAllEventListeners()
1659{
1660 ContainerNode::removeAllEventListeners();
1661 if (ElementShadow* shadow = this->shadow())
1662 shadow->removeAllEventListeners();
1663}
1664
1665void Element::beginParsingChildren()
1666{
1667 clearIsParsingChildrenFinished();
1668 StyleResolver* styleResolver = document()->styleResolverIfExists();
1669 if (styleResolver && attached())
1670 styleResolver->pushParentElement(this);
1671}
1672
1673void Element::finishParsingChildren()
1674{
1675 ContainerNode::finishParsingChildren();
1676 setIsParsingChildrenFinished();
1677 checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
1678 if (StyleResolver* styleResolver = document()->styleResolverIfExists())
1679 styleResolver->popParentElement(this);
1680}
1681
1682#ifndef NDEBUG
1683void Element::formatForDebugger(char* buffer, unsigned length) const
1684{
1685 StringBuilder result;
1686 String s;
1687
1688 result.append(nodeName());
1689
1690 s = getIdAttribute();
1691 if (s.length() > 0) {
1692 if (result.length() > 0)
1693 result.appendLiteral("; ");
1694 result.appendLiteral("id=");
1695 result.append(s);
1696 }
1697
1698 s = getAttribute(classAttr);
1699 if (s.length() > 0) {
1700 if (result.length() > 0)
1701 result.appendLiteral("; ");
1702 result.appendLiteral("class=");
1703 result.append(s);
1704 }
1705
1706 strncpy(buffer, result.toString().utf8().data(), length - 1);
1707}
1708#endif
1709
1710const Vector<RefPtr<Attr> >& Element::attrNodeList()
1711{
1712 ASSERT(hasSyntheticAttrChildNodes());
1713 return *attrNodeListForElement(this);
1714}
1715
1716PassRefPtr<Attr> Element::setAttributeNode(Attr* attrNode, ExceptionCode& ec)
1717{
1718 if (!attrNode) {
1719 ec = TYPE_MISMATCH_ERR;
1720 return 0;
1721 }
1722
1723 RefPtr<Attr> oldAttrNode = attrIfExists(attrNode->qualifiedName());
1724 if (oldAttrNode.get() == attrNode)
1725 return attrNode; // This Attr is already attached to the element.
1726
1727 // INUSE_ATTRIBUTE_ERR: Raised if node is an Attr that is already an attribute of another Element object.
1728 // The DOM user must explicitly clone Attr nodes to re-use them in other elements.
1729 if (attrNode->ownerElement()) {
1730 ec = INUSE_ATTRIBUTE_ERR;
1731 return 0;
1732 }
1733
1734 synchronizeAllAttributes();
1735 UniqueElementData* elementData = ensureUniqueElementData();
1736
1737 size_t index = elementData->getAttributeItemIndex(attrNode->qualifiedName());
1738 if (index != notFound) {
1739 if (oldAttrNode)
1740 detachAttrNodeFromElementWithValue(oldAttrNode.get(), elementData->attributeItem(index)->value());
1741 else
1742 oldAttrNode = Attr::create(document(), attrNode->qualifiedName(), elementData->attributeItem(index)->value());
1743 }
1744
1745 setAttributeInternal(index, attrNode->qualifiedName(), attrNode->value(), NotInSynchronizationOfLazyAttribute);
1746
1747 attrNode->attachToElement(this);
1748 ensureAttrNodeListForElement(this)->append(attrNode);
1749
1750 return oldAttrNode.release();
1751}
1752
1753PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionCode& ec)
1754{
1755 return setAttributeNode(attr, ec);
1756}
1757
1758PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec)
1759{
1760 if (!attr) {
1761 ec = TYPE_MISMATCH_ERR;
1762 return 0;
1763 }
1764 if (attr->ownerElement() != this) {
1765 ec = NOT_FOUND_ERR;
1766 return 0;
1767 }
1768
1769 ASSERT(document() == attr->document());
1770
1771 synchronizeAttribute(attr->qualifiedName());
1772
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001773 size_t index = elementData()->getAttrIndex(attr);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001774 if (index == notFound) {
1775 ec = NOT_FOUND_ERR;
1776 return 0;
1777 }
1778
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01001779 RefPtr<Attr> guard(attr);
1780 detachAttrNodeAtIndex(attr, index);
1781 return guard.release();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001782}
1783
1784bool Element::parseAttributeName(QualifiedName& out, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionCode& ec)
1785{
1786 String prefix, localName;
1787 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec))
1788 return false;
1789 ASSERT(!ec);
1790
1791 QualifiedName qName(prefix, localName, namespaceURI);
1792
1793 if (!Document::hasValidNamespaceForAttributes(qName)) {
1794 ec = NAMESPACE_ERR;
1795 return false;
1796 }
1797
1798 out = qName;
1799 return true;
1800}
1801
1802void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode& ec)
1803{
1804 QualifiedName parsedName = anyName;
1805 if (!parseAttributeName(parsedName, namespaceURI, qualifiedName, ec))
1806 return;
1807 setAttribute(parsedName, value);
1808}
1809
1810void Element::removeAttributeInternal(size_t index, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1811{
1812 ASSERT_WITH_SECURITY_IMPLICATION(index < attributeCount());
1813
1814 UniqueElementData* elementData = ensureUniqueElementData();
1815
1816 QualifiedName name = elementData->attributeItem(index)->name();
1817 AtomicString valueBeingRemoved = elementData->attributeItem(index)->value();
1818
1819 if (!inSynchronizationOfLazyAttribute) {
1820 if (!valueBeingRemoved.isNull())
1821 willModifyAttribute(name, valueBeingRemoved, nullAtom);
1822 }
1823
1824 if (RefPtr<Attr> attrNode = attrIfExists(name))
1825 detachAttrNodeFromElementWithValue(attrNode.get(), elementData->attributeItem(index)->value());
1826
1827 elementData->removeAttribute(index);
1828
1829 if (!inSynchronizationOfLazyAttribute)
1830 didRemoveAttribute(name);
1831}
1832
1833void Element::addAttributeInternal(const QualifiedName& name, const AtomicString& value, SynchronizationOfLazyAttribute inSynchronizationOfLazyAttribute)
1834{
1835 if (!inSynchronizationOfLazyAttribute)
1836 willModifyAttribute(name, nullAtom, value);
1837 ensureUniqueElementData()->addAttribute(name, value);
1838 if (!inSynchronizationOfLazyAttribute)
1839 didAddAttribute(name, value);
1840}
1841
1842void Element::removeAttribute(const AtomicString& name)
1843{
1844 if (!elementData())
1845 return;
1846
1847 AtomicString localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1848 size_t index = elementData()->getAttributeItemIndex(localName, false);
1849 if (index == notFound) {
1850 if (UNLIKELY(localName == styleAttr) && elementData()->m_styleAttributeIsDirty && isStyledElement())
1851 static_cast<StyledElement*>(this)->removeAllInlineStyleProperties();
1852 return;
1853 }
1854
1855 removeAttributeInternal(index, NotInSynchronizationOfLazyAttribute);
1856}
1857
1858void Element::removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName)
1859{
1860 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI));
1861}
1862
1863PassRefPtr<Attr> Element::getAttributeNode(const AtomicString& localName)
1864{
1865 if (!elementData())
1866 return 0;
1867 synchronizeAttribute(localName);
1868 const Attribute* attribute = elementData()->getAttributeItem(localName, shouldIgnoreAttributeCase(this));
1869 if (!attribute)
1870 return 0;
1871 return ensureAttr(attribute->name());
1872}
1873
1874PassRefPtr<Attr> Element::getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName)
1875{
1876 if (!elementData())
1877 return 0;
1878 QualifiedName qName(nullAtom, localName, namespaceURI);
1879 synchronizeAttribute(qName);
1880 const Attribute* attribute = elementData()->getAttributeItem(qName);
1881 if (!attribute)
1882 return 0;
1883 return ensureAttr(attribute->name());
1884}
1885
1886bool Element::hasAttribute(const AtomicString& localName) const
1887{
1888 if (!elementData())
1889 return false;
1890 synchronizeAttribute(localName);
1891 return elementData()->getAttributeItem(shouldIgnoreAttributeCase(this) ? localName.lower() : localName, false);
1892}
1893
1894bool Element::hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const
1895{
1896 if (!elementData())
1897 return false;
1898 QualifiedName qName(nullAtom, localName, namespaceURI);
1899 synchronizeAttribute(qName);
1900 return elementData()->getAttributeItem(qName);
1901}
1902
1903CSSStyleDeclaration *Element::style()
1904{
1905 return 0;
1906}
1907
1908void Element::focus(bool restorePreviousSelection, FocusDirection direction)
1909{
1910 if (!inDocument())
1911 return;
1912
1913 Document* doc = document();
1914 if (doc->focusedNode() == this)
1915 return;
1916
1917 // If the stylesheets have already been loaded we can reliably check isFocusable.
1918 // If not, we continue and set the focused node on the focus controller below so
1919 // that it can be updated soon after attach.
1920 if (doc->haveStylesheetsLoaded()) {
1921 doc->updateLayoutIgnorePendingStylesheets();
1922 if (!isFocusable())
1923 return;
1924 }
1925
1926 if (!supportsFocus())
1927 return;
1928
1929 RefPtr<Node> protect;
1930 if (Page* page = doc->page()) {
1931 // Focus and change event handlers can cause us to lose our last ref.
1932 // If a focus event handler changes the focus to a different node it
1933 // does not make sense to continue and update appearence.
1934 protect = this;
1935 if (!page->focusController()->setFocusedNode(this, doc->frame(), direction))
1936 return;
1937 }
1938
1939 // Setting the focused node above might have invalidated the layout due to scripts.
1940 doc->updateLayoutIgnorePendingStylesheets();
1941
1942 if (!isFocusable()) {
1943 ensureElementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
1944 return;
1945 }
1946
1947 cancelFocusAppearanceUpdate();
1948 updateFocusAppearance(restorePreviousSelection);
1949}
1950
1951void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
1952{
1953 if (isRootEditableElement()) {
1954 Frame* frame = document()->frame();
1955 if (!frame)
1956 return;
1957
1958 // When focusing an editable element in an iframe, don't reset the selection if it already contains a selection.
1959 if (this == frame->selection()->rootEditableElement())
1960 return;
1961
1962 // FIXME: We should restore the previous selection if there is one.
1963 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
1964
1965 if (frame->selection()->shouldChangeSelection(newSelection)) {
1966 frame->selection()->setSelection(newSelection);
1967 frame->selection()->revealSelection();
1968 }
1969 } else if (renderer() && !renderer()->isWidget())
1970 renderer()->scrollRectToVisible(boundingBox());
1971}
1972
1973void Element::blur()
1974{
1975 cancelFocusAppearanceUpdate();
1976 Document* doc = document();
1977 if (treeScope()->focusedNode() == this) {
1978 if (doc->frame())
1979 doc->frame()->page()->focusController()->setFocusedNode(0, doc->frame());
1980 else
1981 doc->setFocusedNode(0);
1982 }
1983}
1984
1985String Element::innerText()
1986{
1987 // We need to update layout, since plainText uses line boxes in the render tree.
1988 document()->updateLayoutIgnorePendingStylesheets();
1989
1990 if (!renderer())
1991 return textContent(true);
1992
1993 return plainText(rangeOfContents(const_cast<Element*>(this)).get());
1994}
1995
1996String Element::outerText()
1997{
1998 // Getting outerText is the same as getting innerText, only
1999 // setting is different. You would think this should get the plain
2000 // text for the outer range, but this is wrong, <br> for instance
2001 // would return different values for inner and outer text by such
2002 // a rule, but it doesn't in WinIE, and we want to match that.
2003 return innerText();
2004}
2005
2006String Element::title() const
2007{
2008 return String();
2009}
2010
2011const AtomicString& Element::pseudo() const
2012{
2013 return getAttribute(pseudoAttr);
2014}
2015
2016void Element::setPseudo(const AtomicString& value)
2017{
2018 setAttribute(pseudoAttr, value);
2019}
2020
2021LayoutSize Element::minimumSizeForResizing() const
2022{
2023 return hasRareData() ? elementRareData()->minimumSizeForResizing() : defaultMinimumSizeForResizing();
2024}
2025
2026void Element::setMinimumSizeForResizing(const LayoutSize& size)
2027{
2028 if (!hasRareData() && size == defaultMinimumSizeForResizing())
2029 return;
2030 ensureElementRareData()->setMinimumSizeForResizing(size);
2031}
2032
2033RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
2034{
2035 if (PseudoElement* element = pseudoElement(pseudoElementSpecifier))
2036 return element->computedStyle();
2037
2038 // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
2039 // properties, which are only known by the renderer because it did the layout, will be correct and so that the
2040 // values returned for the ":selection" pseudo-element will be correct.
2041 if (RenderStyle* usedStyle = renderStyle()) {
2042 if (pseudoElementSpecifier) {
2043 RenderStyle* cachedPseudoStyle = usedStyle->getCachedPseudoStyle(pseudoElementSpecifier);
2044 return cachedPseudoStyle ? cachedPseudoStyle : usedStyle;
2045 } else
2046 return usedStyle;
2047 }
2048
2049 if (!attached())
2050 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
2051 // document tree and figure out when to destroy the computed style for such elements.
2052 return 0;
2053
2054 ElementRareData* data = ensureElementRareData();
2055 if (!data->computedStyle())
2056 data->setComputedStyle(document()->styleForElementIgnoringPendingStylesheets(this));
2057 return pseudoElementSpecifier ? data->computedStyle()->getCachedPseudoStyle(pseudoElementSpecifier) : data->computedStyle();
2058}
2059
2060void Element::setStyleAffectedByEmpty()
2061{
2062 ensureElementRareData()->setStyleAffectedByEmpty(true);
2063}
2064
2065void Element::setChildrenAffectedByHover(bool value)
2066{
2067 if (value || hasRareData())
2068 ensureElementRareData()->setChildrenAffectedByHover(value);
2069}
2070
2071void Element::setChildrenAffectedByActive(bool value)
2072{
2073 if (value || hasRareData())
2074 ensureElementRareData()->setChildrenAffectedByActive(value);
2075}
2076
2077void Element::setChildrenAffectedByDrag(bool value)
2078{
2079 if (value || hasRareData())
2080 ensureElementRareData()->setChildrenAffectedByDrag(value);
2081}
2082
2083void Element::setChildrenAffectedByFirstChildRules()
2084{
2085 ensureElementRareData()->setChildrenAffectedByFirstChildRules(true);
2086}
2087
2088void Element::setChildrenAffectedByLastChildRules()
2089{
2090 ensureElementRareData()->setChildrenAffectedByLastChildRules(true);
2091}
2092
2093void Element::setChildrenAffectedByDirectAdjacentRules()
2094{
2095 ensureElementRareData()->setChildrenAffectedByDirectAdjacentRules(true);
2096}
2097
2098void Element::setChildrenAffectedByForwardPositionalRules()
2099{
2100 ensureElementRareData()->setChildrenAffectedByForwardPositionalRules(true);
2101}
2102
2103void Element::setChildrenAffectedByBackwardPositionalRules()
2104{
2105 ensureElementRareData()->setChildrenAffectedByBackwardPositionalRules(true);
2106}
2107
2108void Element::setChildIndex(unsigned index)
2109{
2110 ElementRareData* rareData = ensureElementRareData();
2111 if (RenderStyle* style = renderStyle())
2112 style->setUnique();
2113 rareData->setChildIndex(index);
2114}
2115
2116bool Element::hasFlagsSetDuringStylingOfChildren() const
2117{
2118 if (!hasRareData())
2119 return false;
2120 return rareDataChildrenAffectedByHover()
2121 || rareDataChildrenAffectedByActive()
2122 || rareDataChildrenAffectedByDrag()
2123 || rareDataChildrenAffectedByFirstChildRules()
2124 || rareDataChildrenAffectedByLastChildRules()
2125 || rareDataChildrenAffectedByDirectAdjacentRules()
2126 || rareDataChildrenAffectedByForwardPositionalRules()
2127 || rareDataChildrenAffectedByBackwardPositionalRules();
2128}
2129
2130bool Element::rareDataStyleAffectedByEmpty() const
2131{
2132 ASSERT(hasRareData());
2133 return elementRareData()->styleAffectedByEmpty();
2134}
2135
2136bool Element::rareDataChildrenAffectedByHover() const
2137{
2138 ASSERT(hasRareData());
2139 return elementRareData()->childrenAffectedByHover();
2140}
2141
2142bool Element::rareDataChildrenAffectedByActive() const
2143{
2144 ASSERT(hasRareData());
2145 return elementRareData()->childrenAffectedByActive();
2146}
2147
2148bool Element::rareDataChildrenAffectedByDrag() const
2149{
2150 ASSERT(hasRareData());
2151 return elementRareData()->childrenAffectedByDrag();
2152}
2153
2154bool Element::rareDataChildrenAffectedByFirstChildRules() const
2155{
2156 ASSERT(hasRareData());
2157 return elementRareData()->childrenAffectedByFirstChildRules();
2158}
2159
2160bool Element::rareDataChildrenAffectedByLastChildRules() const
2161{
2162 ASSERT(hasRareData());
2163 return elementRareData()->childrenAffectedByLastChildRules();
2164}
2165
2166bool Element::rareDataChildrenAffectedByDirectAdjacentRules() const
2167{
2168 ASSERT(hasRareData());
2169 return elementRareData()->childrenAffectedByDirectAdjacentRules();
2170}
2171
2172bool Element::rareDataChildrenAffectedByForwardPositionalRules() const
2173{
2174 ASSERT(hasRareData());
2175 return elementRareData()->childrenAffectedByForwardPositionalRules();
2176}
2177
2178bool Element::rareDataChildrenAffectedByBackwardPositionalRules() const
2179{
2180 ASSERT(hasRareData());
2181 return elementRareData()->childrenAffectedByBackwardPositionalRules();
2182}
2183
2184unsigned Element::rareDataChildIndex() const
2185{
2186 ASSERT(hasRareData());
2187 return elementRareData()->childIndex();
2188}
2189
2190void Element::setIsInCanvasSubtree(bool isInCanvasSubtree)
2191{
2192 ensureElementRareData()->setIsInCanvasSubtree(isInCanvasSubtree);
2193}
2194
2195bool Element::isInCanvasSubtree() const
2196{
2197 return hasRareData() && elementRareData()->isInCanvasSubtree();
2198}
2199
2200bool Element::isUnresolvedCustomElement()
2201{
2202 return isCustomElement() && document()->registry()->isUnresolved(this);
2203}
2204
2205AtomicString Element::computeInheritedLanguage() const
2206{
2207 const Node* n = this;
2208 AtomicString value;
2209 // The language property is inherited, so we iterate over the parents to find the first language.
2210 do {
2211 if (n->isElementNode()) {
2212 if (const ElementData* elementData = toElement(n)->elementData()) {
2213 // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7
2214 if (const Attribute* attribute = elementData->getAttributeItem(XMLNames::langAttr))
2215 value = attribute->value();
2216 else if (const Attribute* attribute = elementData->getAttributeItem(HTMLNames::langAttr))
2217 value = attribute->value();
2218 }
2219 } else if (n->isDocumentNode()) {
2220 // checking the MIME content-language
2221 value = toDocument(n)->contentLanguage();
2222 }
2223
2224 n = n->parentNode();
2225 } while (n && value.isNull());
2226
2227 return value;
2228}
2229
2230Locale& Element::locale() const
2231{
2232 return document()->getCachedLocale(computeInheritedLanguage());
2233}
2234
2235void Element::cancelFocusAppearanceUpdate()
2236{
2237 if (hasRareData())
2238 elementRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
2239 if (document()->focusedNode() == this)
2240 document()->cancelFocusAppearanceUpdate();
2241}
2242
2243void Element::normalizeAttributes()
2244{
2245 if (!hasAttributes())
2246 return;
2247 for (unsigned i = 0; i < attributeCount(); ++i) {
2248 if (RefPtr<Attr> attr = attrIfExists(attributeItem(i)->name()))
2249 attr->normalize();
2250 }
2251}
2252
2253void Element::updatePseudoElement(PseudoId pseudoId, StyleChange change)
2254{
2255 PseudoElement* element = pseudoElement(pseudoId);
2256 if (element && (needsStyleRecalc() || shouldRecalcStyle(change, element))) {
2257 // PseudoElement styles hang off their parent element's style so if we needed
2258 // a style recalc we should Force one on the pseudo.
2259 element->recalcStyle(needsStyleRecalc() ? Force : change);
2260
2261 // Wait until our parent is not displayed or pseudoElementRendererIsNeeded
2262 // is false, otherwise we could continously create and destroy PseudoElements
2263 // when RenderObject::isChildAllowed on our parent returns false for the
2264 // PseudoElement's renderer for each style recalc.
2265 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
2266 setPseudoElement(pseudoId, 0);
2267 } else if (change >= Inherit || needsStyleRecalc())
2268 createPseudoElementIfNeeded(pseudoId);
2269}
2270
2271void Element::createPseudoElementIfNeeded(PseudoId pseudoId)
2272{
2273 if (!document()->styleSheetCollection()->usesBeforeAfterRules())
2274 return;
2275
2276 if (!renderer() || !pseudoElementRendererIsNeeded(renderer()->getCachedPseudoStyle(pseudoId)))
2277 return;
2278
2279 if (!renderer()->canHaveGeneratedChildren())
2280 return;
2281
2282 ASSERT(!isPseudoElement());
2283 RefPtr<PseudoElement> element = PseudoElement::create(this, pseudoId);
2284 element->attach();
2285 setPseudoElement(pseudoId, element.release());
2286}
2287
2288bool Element::hasPseudoElements() const
2289{
2290 return hasRareData() && elementRareData()->hasPseudoElements();
2291}
2292
2293PseudoElement* Element::pseudoElement(PseudoId pseudoId) const
2294{
2295 return hasRareData() ? elementRareData()->pseudoElement(pseudoId) : 0;
2296}
2297
2298void Element::setPseudoElement(PseudoId pseudoId, PassRefPtr<PseudoElement> element)
2299{
2300 ensureElementRareData()->setPseudoElement(pseudoId, element);
2301 resetNeedsShadowTreeWalker();
2302}
2303
2304RenderObject* Element::pseudoElementRenderer(PseudoId pseudoId) const
2305{
2306 if (PseudoElement* element = pseudoElement(pseudoId))
2307 return element->renderer();
2308 return 0;
2309}
2310
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002311bool Element::matchesReadOnlyPseudoClass() const
2312{
2313 return false;
2314}
2315
2316bool Element::matchesReadWritePseudoClass() const
2317{
2318 return false;
2319}
2320
2321bool Element::webkitMatchesSelector(const String& selector, ExceptionCode& ec)
2322{
2323 if (selector.isEmpty()) {
2324 ec = SYNTAX_ERR;
2325 return false;
2326 }
2327
2328 SelectorQuery* selectorQuery = document()->selectorQueryCache()->add(selector, document(), ec);
2329 if (!selectorQuery)
2330 return false;
2331 return selectorQuery->matches(this);
2332}
2333
2334bool Element::shouldAppearIndeterminate() const
2335{
2336 return false;
2337}
2338
2339DOMTokenList* Element::classList()
2340{
2341 ElementRareData* data = ensureElementRareData();
2342 if (!data->classList())
2343 data->setClassList(ClassList::create(this));
2344 return data->classList();
2345}
2346
2347DOMStringMap* Element::dataset()
2348{
2349 ElementRareData* data = ensureElementRareData();
2350 if (!data->dataset())
2351 data->setDataset(DatasetDOMStringMap::create(this));
2352 return data->dataset();
2353}
2354
2355KURL Element::getURLAttribute(const QualifiedName& name) const
2356{
2357#if !ASSERT_DISABLED
2358 if (elementData()) {
2359 if (const Attribute* attribute = getAttributeItem(name))
2360 ASSERT(isURLAttribute(*attribute));
2361 }
2362#endif
2363 return document()->completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
2364}
2365
2366KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
2367{
2368#if !ASSERT_DISABLED
2369 if (elementData()) {
2370 if (const Attribute* attribute = getAttributeItem(name))
2371 ASSERT(isURLAttribute(*attribute));
2372 }
2373#endif
2374 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
2375 if (value.isEmpty())
2376 return KURL();
2377 return document()->completeURL(value);
2378}
2379
2380int Element::getIntegralAttribute(const QualifiedName& attributeName) const
2381{
2382 return getAttribute(attributeName).string().toInt();
2383}
2384
2385void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
2386{
2387 // FIXME: Need an AtomicString version of String::number.
2388 setAttribute(attributeName, String::number(value));
2389}
2390
2391unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
2392{
2393 return getAttribute(attributeName).string().toUInt();
2394}
2395
2396void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
2397{
2398 // FIXME: Need an AtomicString version of String::number.
2399 setAttribute(attributeName, String::number(value));
2400}
2401
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002402bool Element::childShouldCreateRenderer(const NodeRenderingContext& childContext) const
2403{
2404 // Only create renderers for SVG elements whose parents are SVG elements, or for proper <svg xmlns="svgNS"> subdocuments.
2405 if (childContext.node()->isSVGElement())
2406 return childContext.node()->hasTagName(SVGNames::svgTag) || isSVGElement();
2407
2408 return ContainerNode::childShouldCreateRenderer(childContext);
2409}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002410
2411void Element::webkitRequestFullscreen()
2412{
2413 document()->requestFullScreenForElement(this, ALLOW_KEYBOARD_INPUT, Document::EnforceIFrameAllowFullScreenRequirement);
2414}
2415
2416void Element::webkitRequestFullScreen(unsigned short flags)
2417{
2418 document()->requestFullScreenForElement(this, (flags | LEGACY_MOZILLA_REQUEST), Document::EnforceIFrameAllowFullScreenRequirement);
2419}
2420
2421bool Element::containsFullScreenElement() const
2422{
2423 return hasRareData() && elementRareData()->containsFullScreenElement();
2424}
2425
2426void Element::setContainsFullScreenElement(bool flag)
2427{
2428 ensureElementRareData()->setContainsFullScreenElement(flag);
2429 setNeedsStyleRecalc(SyntheticStyleChange);
2430}
2431
2432static Element* parentCrossingFrameBoundaries(Element* element)
2433{
2434 ASSERT(element);
2435 return element->parentElement() ? element->parentElement() : element->document()->ownerElement();
2436}
2437
2438void Element::setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool flag)
2439{
2440 Element* element = this;
2441 while ((element = parentCrossingFrameBoundaries(element)))
2442 element->setContainsFullScreenElement(flag);
2443}
2444
2445bool Element::isInTopLayer() const
2446{
2447 return hasRareData() && elementRareData()->isInTopLayer();
2448}
2449
2450void Element::setIsInTopLayer(bool inTopLayer)
2451{
2452 if (isInTopLayer() == inTopLayer)
2453 return;
2454 ensureElementRareData()->setIsInTopLayer(inTopLayer);
2455
2456 // We must ensure a reattach occurs so the renderer is inserted in the correct sibling order under RenderView according to its
2457 // top layer position, or in its usual place if not in the top layer.
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002458 lazyReattachIfAttached();
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002459}
2460
2461void Element::webkitRequestPointerLock()
2462{
2463 if (document()->page())
2464 document()->page()->pointerLockController()->requestPointerLock(this);
2465}
2466
2467SpellcheckAttributeState Element::spellcheckAttributeState() const
2468{
2469 const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
2470 if (value == nullAtom)
2471 return SpellcheckAttributeDefault;
2472 if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
2473 return SpellcheckAttributeTrue;
2474 if (equalIgnoringCase(value, "false"))
2475 return SpellcheckAttributeFalse;
2476
2477 return SpellcheckAttributeDefault;
2478}
2479
2480bool Element::isSpellCheckingEnabled() const
2481{
2482 for (const Element* element = this; element; element = element->parentOrShadowHostElement()) {
2483 switch (element->spellcheckAttributeState()) {
2484 case SpellcheckAttributeTrue:
2485 return true;
2486 case SpellcheckAttributeFalse:
2487 return false;
2488 case SpellcheckAttributeDefault:
2489 break;
2490 }
2491 }
2492
2493 return true;
2494}
2495
2496RenderRegion* Element::renderRegion() const
2497{
2498 if (renderer() && renderer()->isRenderRegion())
2499 return toRenderRegion(renderer());
2500
2501 return 0;
2502}
2503
2504const AtomicString& Element::webkitRegionOverset() const
2505{
2506 document()->updateLayoutIgnorePendingStylesheets();
2507
2508 DEFINE_STATIC_LOCAL(AtomicString, undefinedState, ("undefined", AtomicString::ConstructFromLiteral));
2509 if (!RuntimeEnabledFeatures::cssRegionsEnabled() || !renderRegion())
2510 return undefinedState;
2511
2512 switch (renderRegion()->regionState()) {
2513 case RenderRegion::RegionFit: {
2514 DEFINE_STATIC_LOCAL(AtomicString, fitState, ("fit", AtomicString::ConstructFromLiteral));
2515 return fitState;
2516 }
2517 case RenderRegion::RegionEmpty: {
2518 DEFINE_STATIC_LOCAL(AtomicString, emptyState, ("empty", AtomicString::ConstructFromLiteral));
2519 return emptyState;
2520 }
2521 case RenderRegion::RegionOverset: {
2522 DEFINE_STATIC_LOCAL(AtomicString, overflowState, ("overset", AtomicString::ConstructFromLiteral));
2523 return overflowState;
2524 }
2525 case RenderRegion::RegionUndefined:
2526 return undefinedState;
2527 }
2528
2529 ASSERT_NOT_REACHED();
2530 return undefinedState;
2531}
2532
2533Vector<RefPtr<Range> > Element::webkitGetRegionFlowRanges() const
2534{
2535 document()->updateLayoutIgnorePendingStylesheets();
2536
2537 Vector<RefPtr<Range> > rangeObjects;
2538 if (RuntimeEnabledFeatures::cssRegionsEnabled() && renderer() && renderer()->isRenderRegion()) {
2539 RenderRegion* region = toRenderRegion(renderer());
2540 if (region->isValid())
2541 region->getRanges(rangeObjects);
2542 }
2543
2544 return rangeObjects;
2545}
2546
2547#ifndef NDEBUG
2548bool Element::fastAttributeLookupAllowed(const QualifiedName& name) const
2549{
2550 if (name == HTMLNames::styleAttr)
2551 return false;
2552
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002553 if (isSVGElement())
2554 return !static_cast<const SVGElement*>(this)->isAnimatableAttribute(name);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002555
2556 return true;
2557}
2558#endif
2559
2560#ifdef DUMP_NODE_STATISTICS
2561bool Element::hasNamedNodeMap() const
2562{
2563 return hasRareData() && elementRareData()->attributeMap();
2564}
2565#endif
2566
2567inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName)
2568{
2569 if (!inDocument() || isInShadowTree())
2570 return;
2571
2572 if (oldName == newName)
2573 return;
2574
2575 if (shouldRegisterAsNamedItem())
2576 updateNamedItemRegistration(oldName, newName);
2577}
2578
2579inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
2580{
2581 if (!isInTreeScope())
2582 return;
2583
2584 if (oldId == newId)
2585 return;
2586
2587 updateId(treeScope(), oldId, newId);
2588}
2589
2590inline void Element::updateId(TreeScope* scope, const AtomicString& oldId, const AtomicString& newId)
2591{
2592 ASSERT(isInTreeScope());
2593 ASSERT(oldId != newId);
2594
2595 if (!oldId.isEmpty())
2596 scope->removeElementById(oldId, this);
2597 if (!newId.isEmpty())
2598 scope->addElementById(newId, this);
2599
2600 if (shouldRegisterAsExtraNamedItem())
2601 updateExtraNamedItemRegistration(oldId, newId);
2602}
2603
2604void Element::updateLabel(TreeScope* scope, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue)
2605{
2606 ASSERT(hasTagName(labelTag));
2607
2608 if (!inDocument())
2609 return;
2610
2611 if (oldForAttributeValue == newForAttributeValue)
2612 return;
2613
2614 if (!oldForAttributeValue.isEmpty())
2615 scope->removeLabel(oldForAttributeValue, static_cast<HTMLLabelElement*>(this));
2616 if (!newForAttributeValue.isEmpty())
2617 scope->addLabel(newForAttributeValue, static_cast<HTMLLabelElement*>(this));
2618}
2619
2620void Element::willModifyAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& newValue)
2621{
2622 if (isIdAttributeName(name))
2623 updateId(oldValue, newValue);
2624 else if (name == HTMLNames::nameAttr)
2625 updateName(oldValue, newValue);
2626 else if (name == HTMLNames::forAttr && hasTagName(labelTag)) {
2627 TreeScope* scope = treeScope();
2628 if (scope->shouldCacheLabelsByForAttribute())
2629 updateLabel(scope, oldValue, newValue);
2630 }
2631
2632 if (oldValue != newValue) {
2633 if (attached() && document()->styleResolver() && document()->styleResolver()->hasSelectorForAttribute(name.localName()))
2634 setNeedsStyleRecalc();
2635 }
2636
2637 if (OwnPtr<MutationObserverInterestGroup> recipients = MutationObserverInterestGroup::createForAttributesMutation(this, name))
2638 recipients->enqueueMutationRecord(MutationRecord::createAttributes(this, name, oldValue));
2639
2640 InspectorInstrumentation::willModifyDOMAttr(document(), this, oldValue, newValue);
2641}
2642
2643void Element::didAddAttribute(const QualifiedName& name, const AtomicString& value)
2644{
2645 attributeChanged(name, value);
2646 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value);
2647 dispatchSubtreeModifiedEvent();
2648}
2649
2650void Element::didModifyAttribute(const QualifiedName& name, const AtomicString& value)
2651{
2652 attributeChanged(name, value);
2653 InspectorInstrumentation::didModifyDOMAttr(document(), this, name.localName(), value);
2654 // Do not dispatch a DOMSubtreeModified event here; see bug 81141.
2655}
2656
2657void Element::didRemoveAttribute(const QualifiedName& name)
2658{
2659 attributeChanged(name, nullAtom);
2660 InspectorInstrumentation::didRemoveDOMAttr(document(), this, name.localName());
2661 dispatchSubtreeModifiedEvent();
2662}
2663
2664
2665void Element::updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName)
2666{
2667 if (!document()->isHTMLDocument())
2668 return;
2669
2670 if (!oldName.isEmpty())
2671 toHTMLDocument(document())->removeNamedItem(oldName);
2672
2673 if (!newName.isEmpty())
2674 toHTMLDocument(document())->addNamedItem(newName);
2675}
2676
2677void Element::updateExtraNamedItemRegistration(const AtomicString& oldId, const AtomicString& newId)
2678{
2679 if (!document()->isHTMLDocument())
2680 return;
2681
2682 if (!oldId.isEmpty())
2683 toHTMLDocument(document())->removeExtraNamedItem(oldId);
2684
2685 if (!newId.isEmpty())
2686 toHTMLDocument(document())->addExtraNamedItem(newId);
2687}
2688
2689PassRefPtr<HTMLCollection> Element::ensureCachedHTMLCollection(CollectionType type)
2690{
2691 if (HTMLCollection* collection = cachedHTMLCollection(type))
2692 return collection;
2693
2694 RefPtr<HTMLCollection> collection;
2695 if (type == TableRows) {
2696 ASSERT(hasTagName(tableTag));
2697 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLTableRowsCollection>(this, type);
2698 } else if (type == SelectOptions) {
2699 ASSERT(hasTagName(selectTag));
2700 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLOptionsCollection>(this, type);
2701 } else if (type == FormControls) {
2702 ASSERT(hasTagName(formTag) || hasTagName(fieldsetTag));
2703 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLFormControlsCollection>(this, type);
2704 }
2705 return ensureRareData()->ensureNodeLists()->addCacheWithAtomicName<HTMLCollection>(this, type);
2706}
2707
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002708static void needsSyntheticStyleChangeCallback(Node* node)
2709{
2710 node->setNeedsStyleRecalc(SyntheticStyleChange);
2711}
2712
2713void Element::scheduleSyntheticStyleChange()
2714{
2715 if (postAttachCallbacksAreSuspended())
2716 queuePostAttachCallback(needsSyntheticStyleChangeCallback, this);
2717 else
2718 setNeedsStyleRecalc(SyntheticStyleChange);
2719}
2720
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002721HTMLCollection* Element::cachedHTMLCollection(CollectionType type)
2722{
2723 return hasRareData() && rareData()->nodeLists() ? rareData()->nodeLists()->cacheWithAtomicName<HTMLCollection>(type) : 0;
2724}
2725
2726IntSize Element::savedLayerScrollOffset() const
2727{
2728 return hasRareData() ? elementRareData()->savedLayerScrollOffset() : IntSize();
2729}
2730
2731void Element::setSavedLayerScrollOffset(const IntSize& size)
2732{
2733 if (size.isZero() && !hasRareData())
2734 return;
2735 ensureElementRareData()->setSavedLayerScrollOffset(size);
2736}
2737
2738PassRefPtr<Attr> Element::attrIfExists(const QualifiedName& name)
2739{
2740 if (AttrNodeList* attrNodeList = attrNodeListForElement(this))
2741 return findAttrNodeInList(attrNodeList, name);
2742 return 0;
2743}
2744
2745PassRefPtr<Attr> Element::ensureAttr(const QualifiedName& name)
2746{
2747 AttrNodeList* attrNodeList = ensureAttrNodeListForElement(this);
2748 RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, name);
2749 if (!attrNode) {
2750 attrNode = Attr::create(this, name);
2751 treeScope()->adoptIfNeeded(attrNode.get());
2752 attrNodeList->append(attrNode);
2753 }
2754 return attrNode.release();
2755}
2756
2757void Element::detachAttrNodeFromElementWithValue(Attr* attrNode, const AtomicString& value)
2758{
2759 ASSERT(hasSyntheticAttrChildNodes());
2760 attrNode->detachFromElementWithValue(value);
2761
2762 AttrNodeList* attrNodeList = attrNodeListForElement(this);
2763 for (unsigned i = 0; i < attrNodeList->size(); ++i) {
2764 if (attrNodeList->at(i)->qualifiedName() == attrNode->qualifiedName()) {
2765 attrNodeList->remove(i);
2766 if (attrNodeList->isEmpty())
2767 removeAttrNodeListForElement(this);
2768 return;
2769 }
2770 }
2771 ASSERT_NOT_REACHED();
2772}
2773
2774void Element::detachAllAttrNodesFromElement()
2775{
2776 AttrNodeList* attrNodeList = attrNodeListForElement(this);
2777 ASSERT(attrNodeList);
2778
2779 for (unsigned i = 0; i < attributeCount(); ++i) {
2780 const Attribute* attribute = attributeItem(i);
2781 if (RefPtr<Attr> attrNode = findAttrNodeInList(attrNodeList, attribute->name()))
2782 attrNode->detachFromElementWithValue(attribute->value());
2783 }
2784
2785 removeAttrNodeListForElement(this);
2786}
2787
2788void Element::willRecalcStyle(StyleChange)
2789{
2790 ASSERT(hasCustomStyleCallbacks());
2791}
2792
2793void Element::didRecalcStyle(StyleChange)
2794{
2795 ASSERT(hasCustomStyleCallbacks());
2796}
2797
2798
2799PassRefPtr<RenderStyle> Element::customStyleForRenderer()
2800{
2801 ASSERT(hasCustomStyleCallbacks());
2802 return 0;
2803}
2804
2805void Element::cloneAttributesFromElement(const Element& other)
2806{
2807 if (hasSyntheticAttrChildNodes())
2808 detachAllAttrNodesFromElement();
2809
2810 other.synchronizeAllAttributes();
2811 if (!other.m_elementData) {
2812 m_elementData.clear();
2813 return;
2814 }
2815
2816 const AtomicString& oldID = getIdAttribute();
2817 const AtomicString& newID = other.getIdAttribute();
2818
2819 if (!oldID.isNull() || !newID.isNull())
2820 updateId(oldID, newID);
2821
2822 const AtomicString& oldName = getNameAttribute();
2823 const AtomicString& newName = other.getNameAttribute();
2824
2825 if (!oldName.isNull() || !newName.isNull())
2826 updateName(oldName, newName);
2827
2828 // If 'other' has a mutable ElementData, convert it to an immutable one so we can share it between both elements.
2829 // We can only do this if there is no CSSOM wrapper for other's inline style, and there are no presentation attributes.
2830 if (other.m_elementData->isUnique()
2831 && !other.m_elementData->presentationAttributeStyle()
2832 && (!other.m_elementData->inlineStyle() || !other.m_elementData->inlineStyle()->hasCSSOMWrapper()))
2833 const_cast<Element&>(other).m_elementData = static_cast<const UniqueElementData*>(other.m_elementData.get())->makeShareableCopy();
2834
2835 if (!other.m_elementData->isUnique())
2836 m_elementData = other.m_elementData;
2837 else
2838 m_elementData = other.m_elementData->makeUniqueCopy();
2839
2840 for (unsigned i = 0; i < m_elementData->length(); ++i) {
2841 const Attribute* attribute = const_cast<const ElementData*>(m_elementData.get())->attributeItem(i);
2842 attributeChangedFromParserOrByCloning(attribute->name(), attribute->value(), ModifiedByCloning);
2843 }
2844}
2845
2846void Element::cloneDataFromElement(const Element& other)
2847{
2848 cloneAttributesFromElement(other);
2849 copyNonAttributePropertiesFromElement(other);
2850}
2851
2852void Element::createUniqueElementData()
2853{
2854 if (!m_elementData)
2855 m_elementData = UniqueElementData::create();
2856 else {
2857 ASSERT(!m_elementData->isUnique());
2858 m_elementData = static_cast<ShareableElementData*>(m_elementData.get())->makeUniqueCopy();
2859 }
2860}
2861
2862void Element::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
2863{
2864 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM);
2865 ContainerNode::reportMemoryUsage(memoryObjectInfo);
2866 info.addMember(m_tagName, "tagName");
2867 info.addMember(m_elementData, "elementData");
2868}
2869
Torne (Richard Coles)81a51572013-05-13 16:52:28 +01002870InputMethodContext* Element::getInputContext()
2871{
2872 return ensureElementRareData()->ensureInputMethodContext(toHTMLElement(this));
2873}
2874
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002875bool Element::hasPendingResources() const
2876{
2877 return hasRareData() && elementRareData()->hasPendingResources();
2878}
2879
2880void Element::setHasPendingResources()
2881{
2882 ensureElementRareData()->setHasPendingResources(true);
2883}
2884
2885void Element::clearHasPendingResources()
2886{
2887 ensureElementRareData()->setHasPendingResources(false);
2888}
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002889
2890void ElementData::deref()
2891{
2892 if (!derefBase())
2893 return;
2894
2895 if (m_isUnique)
2896 delete static_cast<UniqueElementData*>(this);
2897 else
2898 delete static_cast<ShareableElementData*>(this);
2899}
2900
2901ElementData::ElementData()
2902 : m_isUnique(true)
2903 , m_arraySize(0)
2904 , m_presentationAttributeStyleIsDirty(false)
2905 , m_styleAttributeIsDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002906 , m_animatedSVGAttributesAreDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002907{
2908}
2909
2910ElementData::ElementData(unsigned arraySize)
2911 : m_isUnique(false)
2912 , m_arraySize(arraySize)
2913 , m_presentationAttributeStyleIsDirty(false)
2914 , m_styleAttributeIsDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002915 , m_animatedSVGAttributesAreDirty(false)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002916{
2917}
2918
2919struct SameSizeAsElementData : public RefCounted<SameSizeAsElementData> {
2920 unsigned bitfield;
2921 void* refPtrs[3];
2922};
2923
2924COMPILE_ASSERT(sizeof(ElementData) == sizeof(SameSizeAsElementData), element_attribute_data_should_stay_small);
2925
2926static size_t sizeForShareableElementDataWithAttributeCount(unsigned count)
2927{
2928 return sizeof(ShareableElementData) + sizeof(Attribute) * count;
2929}
2930
2931PassRefPtr<ShareableElementData> ShareableElementData::createWithAttributes(const Vector<Attribute>& attributes)
2932{
2933 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(attributes.size()));
2934 return adoptRef(new (slot) ShareableElementData(attributes));
2935}
2936
2937PassRefPtr<UniqueElementData> UniqueElementData::create()
2938{
2939 return adoptRef(new UniqueElementData);
2940}
2941
2942ShareableElementData::ShareableElementData(const Vector<Attribute>& attributes)
2943 : ElementData(attributes.size())
2944{
2945 for (unsigned i = 0; i < m_arraySize; ++i)
2946 new (&m_attributeArray[i]) Attribute(attributes[i]);
2947}
2948
2949ShareableElementData::~ShareableElementData()
2950{
2951 for (unsigned i = 0; i < m_arraySize; ++i)
2952 m_attributeArray[i].~Attribute();
2953}
2954
2955ShareableElementData::ShareableElementData(const UniqueElementData& other)
2956 : ElementData(other, false)
2957{
2958 ASSERT(!other.m_presentationAttributeStyle);
2959
2960 if (other.m_inlineStyle) {
2961 ASSERT(!other.m_inlineStyle->hasCSSOMWrapper());
2962 m_inlineStyle = other.m_inlineStyle->immutableCopyIfNeeded();
2963 }
2964
2965 for (unsigned i = 0; i < m_arraySize; ++i)
2966 new (&m_attributeArray[i]) Attribute(other.m_attributeVector.at(i));
2967}
2968
2969ElementData::ElementData(const ElementData& other, bool isUnique)
2970 : m_isUnique(isUnique)
2971 , m_arraySize(isUnique ? 0 : other.length())
2972 , m_presentationAttributeStyleIsDirty(other.m_presentationAttributeStyleIsDirty)
2973 , m_styleAttributeIsDirty(other.m_styleAttributeIsDirty)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002974 , m_animatedSVGAttributesAreDirty(other.m_animatedSVGAttributesAreDirty)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002975 , m_classNames(other.m_classNames)
2976 , m_idForStyleResolution(other.m_idForStyleResolution)
2977{
2978 // NOTE: The inline style is copied by the subclass copy constructor since we don't know what to do with it here.
2979}
2980
2981UniqueElementData::UniqueElementData()
2982{
2983}
2984
2985UniqueElementData::UniqueElementData(const UniqueElementData& other)
2986 : ElementData(other, true)
2987 , m_presentationAttributeStyle(other.m_presentationAttributeStyle)
2988 , m_attributeVector(other.m_attributeVector)
2989{
Torne (Richard Coles)93ac45c2013-05-29 14:40:20 +01002990 m_inlineStyle = other.m_inlineStyle ? other.m_inlineStyle->mutableCopy() : 0;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01002991}
2992
2993UniqueElementData::UniqueElementData(const ShareableElementData& other)
2994 : ElementData(other, true)
2995{
2996 // An ShareableElementData should never have a mutable inline StylePropertySet attached.
2997 ASSERT(!other.m_inlineStyle || !other.m_inlineStyle->isMutable());
2998 m_inlineStyle = other.m_inlineStyle;
2999
3000 m_attributeVector.reserveCapacity(other.length());
3001 for (unsigned i = 0; i < other.length(); ++i)
3002 m_attributeVector.uncheckedAppend(other.m_attributeArray[i]);
3003}
3004
3005PassRefPtr<UniqueElementData> ElementData::makeUniqueCopy() const
3006{
3007 if (isUnique())
3008 return adoptRef(new UniqueElementData(static_cast<const UniqueElementData&>(*this)));
3009 return adoptRef(new UniqueElementData(static_cast<const ShareableElementData&>(*this)));
3010}
3011
3012PassRefPtr<ShareableElementData> UniqueElementData::makeShareableCopy() const
3013{
3014 void* slot = WTF::fastMalloc(sizeForShareableElementDataWithAttributeCount(m_attributeVector.size()));
3015 return adoptRef(new (slot) ShareableElementData(*this));
3016}
3017
3018void UniqueElementData::addAttribute(const QualifiedName& attributeName, const AtomicString& value)
3019{
3020 m_attributeVector.append(Attribute(attributeName, value));
3021}
3022
3023void UniqueElementData::removeAttribute(size_t index)
3024{
3025 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
3026 m_attributeVector.remove(index);
3027}
3028
3029bool ElementData::isEquivalent(const ElementData* other) const
3030{
3031 if (!other)
3032 return isEmpty();
3033
3034 unsigned len = length();
3035 if (len != other->length())
3036 return false;
3037
3038 for (unsigned i = 0; i < len; i++) {
3039 const Attribute* attribute = attributeItem(i);
3040 const Attribute* otherAttr = other->getAttributeItem(attribute->name());
3041 if (!otherAttr || attribute->value() != otherAttr->value())
3042 return false;
3043 }
3044
3045 return true;
3046}
3047
3048void ElementData::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
3049{
3050 size_t actualSize = m_isUnique ? sizeof(ElementData) : sizeForShareableElementDataWithAttributeCount(m_arraySize);
3051 MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::DOM, actualSize);
3052 info.addMember(m_inlineStyle, "inlineStyle");
3053 info.addMember(m_classNames, "classNames");
3054 info.addMember(m_idForStyleResolution, "idForStyleResolution");
3055 if (m_isUnique) {
3056 const UniqueElementData* uniqueThis = static_cast<const UniqueElementData*>(this);
3057 info.addMember(uniqueThis->m_presentationAttributeStyle, "presentationAttributeStyle");
3058 info.addMember(uniqueThis->m_attributeVector, "attributeVector");
3059 }
3060 for (unsigned i = 0, len = length(); i < len; i++)
3061 info.addMember(*attributeItem(i), "*attributeItem");
3062}
3063
Torne (Richard Coles)e5249552013-05-15 11:35:13 +01003064size_t ElementData::getAttrIndex(Attr* attr) const
3065{
3066 // This relies on the fact that Attr's QualifiedName == the Attribute's name.
3067 for (unsigned i = 0; i < length(); ++i) {
3068 if (attributeItem(i)->name() == attr->qualifiedName())
3069 return i;
3070 }
3071 return notFound;
3072}
3073
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01003074size_t ElementData::getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const
3075{
3076 // Continue to checking case-insensitively and/or full namespaced names if necessary:
3077 for (unsigned i = 0; i < length(); ++i) {
3078 const Attribute* attribute = attributeItem(i);
3079 if (!attribute->name().hasPrefix()) {
3080 if (shouldIgnoreAttributeCase && equalIgnoringCase(name, attribute->localName()))
3081 return i;
3082 } else {
3083 // FIXME: Would be faster to do this comparison without calling toString, which
3084 // generates a temporary string by concatenation. But this branch is only reached
3085 // if the attribute name has a prefix, which is rare in HTML.
3086 if (equalPossiblyIgnoringCase(name, attribute->name().toString(), shouldIgnoreAttributeCase))
3087 return i;
3088 }
3089 }
3090 return notFound;
3091}
3092
3093Attribute* UniqueElementData::getAttributeItem(const QualifiedName& name)
3094{
3095 for (unsigned i = 0; i < length(); ++i) {
3096 if (m_attributeVector.at(i).name().matches(name))
3097 return &m_attributeVector.at(i);
3098 }
3099 return 0;
3100}
3101
3102Attribute* UniqueElementData::attributeItem(unsigned index)
3103{
3104 ASSERT_WITH_SECURITY_IMPLICATION(index < length());
3105 return &m_attributeVector.at(index);
3106}
3107
3108} // namespace WebCore