1 /*
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 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 "Element.h"
28
29 #include "AXObjectCache.h"
30 #include "Attr.h"
31 #include "CSSParser.h"
32 #include "CSSSelectorList.h"
33 #include "CSSStyleSelector.h"
34 #include "ClassList.h"
35 #include "ClientRect.h"
36 #include "ClientRectList.h"
37 #include "DOMTokenList.h"
38 #include "DatasetDOMStringMap.h"
39 #include "Document.h"
40 #include "DocumentFragment.h"
41 #include "ElementRareData.h"
42 #include "ExceptionCode.h"
43 #include "FocusController.h"
44 #include "Frame.h"
45 #include "FrameView.h"
46 #include "HTMLElement.h"
47 #include "HTMLNames.h"
48 #include "HTMLParserIdioms.h"
49 #include "InspectorInstrumentation.h"
50 #include "NodeList.h"
51 #include "NodeRenderStyle.h"
52 #include "Page.h"
53 #include "RenderLayer.h"
54 #include "RenderView.h"
55 #include "RenderWidget.h"
56 #include "Settings.h"
57 #include "ShadowRoot.h"
58 #include "TextIterator.h"
59 #include "WebKitAnimationList.h"
60 #include "XMLNames.h"
61 #include "htmlediting.h"
62 #include <wtf/text/CString.h>
63
64 #if ENABLE(SVG)
65 #include "SVGElement.h"
66 #include "SVGNames.h"
67 #endif
68
69 namespace WebCore {
70
71 using namespace HTMLNames;
72 using namespace XMLNames;
73
74 class StyleSelectorParentPusher {
75 public:
StyleSelectorParentPusher(Element * parent)76 StyleSelectorParentPusher(Element* parent)
77 : m_parent(parent)
78 , m_pushedStyleSelector(0)
79 {
80 }
push()81 void push()
82 {
83 if (m_pushedStyleSelector)
84 return;
85 m_pushedStyleSelector = m_parent->document()->styleSelector();
86 m_pushedStyleSelector->pushParent(m_parent);
87 }
~StyleSelectorParentPusher()88 ~StyleSelectorParentPusher()
89 {
90
91 if (!m_pushedStyleSelector)
92 return;
93
94 // This tells us that our pushed style selector is in a bad state,
95 // so we should just bail out in that scenario.
96 ASSERT(m_pushedStyleSelector == m_parent->document()->styleSelector());
97 if (m_pushedStyleSelector != m_parent->document()->styleSelector())
98 return;
99
100 m_pushedStyleSelector->popParent(m_parent);
101 }
102
103 private:
104 Element* m_parent;
105 CSSStyleSelector* m_pushedStyleSelector;
106 };
107
create(const QualifiedName & tagName,Document * document)108 PassRefPtr<Element> Element::create(const QualifiedName& tagName, Document* document)
109 {
110 return adoptRef(new Element(tagName, document, CreateElement));
111 }
112
~Element()113 Element::~Element()
114 {
115 removeShadowRoot();
116 if (m_attributeMap)
117 m_attributeMap->detachFromElement();
118 }
119
rareData() const120 inline ElementRareData* Element::rareData() const
121 {
122 ASSERT(hasRareData());
123 return static_cast<ElementRareData*>(NodeRareData::rareDataFromMap(this));
124 }
125
ensureRareData()126 inline ElementRareData* Element::ensureRareData()
127 {
128 return static_cast<ElementRareData*>(Node::ensureRareData());
129 }
130
createRareData()131 NodeRareData* Element::createRareData()
132 {
133 return new ElementRareData;
134 }
135
136 DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, blur);
137 DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, error);
138 DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, focus);
139 DEFINE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(Element, load);
140
deprecatedCreateContextualFragment(const String & markup,FragmentScriptingPermission scriptingPermission)141 PassRefPtr<DocumentFragment> Element::deprecatedCreateContextualFragment(const String& markup, FragmentScriptingPermission scriptingPermission)
142 {
143 RefPtr<DocumentFragment> fragment = document()->createDocumentFragment();
144
145 if (document()->isHTMLDocument())
146 fragment->parseHTML(markup, this, scriptingPermission);
147 else {
148 if (!fragment->parseXML(markup, this, scriptingPermission))
149 // FIXME: We should propagate a syntax error exception out here.
150 return 0;
151 }
152
153 // Exceptions are ignored because none ought to happen here.
154 ExceptionCode ignoredExceptionCode;
155
156 // We need to pop <html> and <body> elements and remove <head> to
157 // accommodate folks passing complete HTML documents to make the
158 // child of an element.
159
160 RefPtr<Node> nextNode;
161 for (RefPtr<Node> node = fragment->firstChild(); node; node = nextNode) {
162 nextNode = node->nextSibling();
163 if (node->hasTagName(htmlTag) || node->hasTagName(bodyTag)) {
164 HTMLElement* element = toHTMLElement(node.get());
165 Node* firstChild = element->firstChild();
166 if (firstChild)
167 nextNode = firstChild;
168 RefPtr<Node> nextChild;
169 for (RefPtr<Node> child = firstChild; child; child = nextChild) {
170 nextChild = child->nextSibling();
171 element->removeChild(child.get(), ignoredExceptionCode);
172 ASSERT(!ignoredExceptionCode);
173 fragment->insertBefore(child, element, ignoredExceptionCode);
174 ASSERT(!ignoredExceptionCode);
175 }
176 fragment->removeChild(element, ignoredExceptionCode);
177 ASSERT(!ignoredExceptionCode);
178 } else if (node->hasTagName(headTag)) {
179 fragment->removeChild(node.get(), ignoredExceptionCode);
180 ASSERT(!ignoredExceptionCode);
181 }
182 }
183 return fragment.release();
184 }
185
cloneNode(bool deep)186 PassRefPtr<Node> Element::cloneNode(bool deep)
187 {
188 return deep ? cloneElementWithChildren() : cloneElementWithoutChildren();
189 }
190
cloneElementWithChildren()191 PassRefPtr<Element> Element::cloneElementWithChildren()
192 {
193 RefPtr<Element> clone = cloneElementWithoutChildren();
194 cloneChildNodes(clone.get());
195 return clone.release();
196 }
197
cloneElementWithoutChildren()198 PassRefPtr<Element> Element::cloneElementWithoutChildren()
199 {
200 RefPtr<Element> clone = cloneElementWithoutAttributesAndChildren();
201 // This will catch HTML elements in the wrong namespace that are not correctly copied.
202 // This is a sanity check as HTML overloads some of the DOM methods.
203 ASSERT(isHTMLElement() == clone->isHTMLElement());
204
205 // Call attributes(true) to force attribute synchronization to occur for SVG and style attributes.
206 if (NamedNodeMap* attributeMap = attributes(true))
207 clone->attributes()->setAttributes(*attributeMap);
208
209 clone->copyNonAttributeProperties(this);
210
211 return clone.release();
212 }
213
cloneElementWithoutAttributesAndChildren() const214 PassRefPtr<Element> Element::cloneElementWithoutAttributesAndChildren() const
215 {
216 return document()->createElement(tagQName(), false);
217 }
218
removeAttribute(const QualifiedName & name,ExceptionCode & ec)219 void Element::removeAttribute(const QualifiedName& name, ExceptionCode& ec)
220 {
221 if (m_attributeMap) {
222 ec = 0;
223 m_attributeMap->removeNamedItem(name, ec);
224 if (ec == NOT_FOUND_ERR)
225 ec = 0;
226 }
227 }
228
setAttribute(const QualifiedName & name,const AtomicString & value)229 void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
230 {
231 ExceptionCode ec;
232 setAttribute(name, value, ec);
233 }
234
setCStringAttribute(const QualifiedName & name,const char * cStringValue)235 void Element::setCStringAttribute(const QualifiedName& name, const char* cStringValue)
236 {
237 ExceptionCode ec;
238 setAttribute(name, AtomicString(cStringValue), ec);
239 }
240
setBooleanAttribute(const QualifiedName & name,bool b)241 void Element::setBooleanAttribute(const QualifiedName& name, bool b)
242 {
243 if (b)
244 setAttribute(name, emptyAtom);
245 else {
246 ExceptionCode ex;
247 removeAttribute(name, ex);
248 }
249 }
250
nodeType() const251 Node::NodeType Element::nodeType() const
252 {
253 return ELEMENT_NODE;
254 }
255
hasAttribute(const QualifiedName & name) const256 bool Element::hasAttribute(const QualifiedName& name) const
257 {
258 return hasAttributeNS(name.namespaceURI(), name.localName());
259 }
260
getAttribute(const QualifiedName & name) const261 const AtomicString& Element::getAttribute(const QualifiedName& name) const
262 {
263 if (UNLIKELY(name == styleAttr) && !isStyleAttributeValid())
264 updateStyleAttribute();
265
266 #if ENABLE(SVG)
267 if (UNLIKELY(!areSVGAttributesValid()))
268 updateAnimatedSVGAttribute(name);
269 #endif
270
271 return fastGetAttribute(name);
272 }
273
scrollIntoView(bool alignToTop)274 void Element::scrollIntoView(bool alignToTop)
275 {
276 document()->updateLayoutIgnorePendingStylesheets();
277 IntRect bounds = getRect();
278 if (renderer()) {
279 // Align to the top / bottom and to the closest edge.
280 if (alignToTop)
281 renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
282 else
283 renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
284 }
285 }
286
scrollIntoViewIfNeeded(bool centerIfNeeded)287 void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
288 {
289 document()->updateLayoutIgnorePendingStylesheets();
290 IntRect bounds = getRect();
291 if (renderer()) {
292 if (centerIfNeeded)
293 renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
294 else
295 renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
296 }
297 }
298
scrollByUnits(int units,ScrollGranularity granularity)299 void Element::scrollByUnits(int units, ScrollGranularity granularity)
300 {
301 document()->updateLayoutIgnorePendingStylesheets();
302 if (RenderObject *rend = renderer()) {
303 if (rend->hasOverflowClip()) {
304 ScrollDirection direction = ScrollDown;
305 if (units < 0) {
306 direction = ScrollUp;
307 units = -units;
308 }
309 toRenderBox(rend)->layer()->scroll(direction, granularity, units);
310 }
311 }
312 }
313
scrollByLines(int lines)314 void Element::scrollByLines(int lines)
315 {
316 scrollByUnits(lines, ScrollByLine);
317 }
318
scrollByPages(int pages)319 void Element::scrollByPages(int pages)
320 {
321 scrollByUnits(pages, ScrollByPage);
322 }
323
localZoomForRenderer(RenderObject * renderer)324 static float localZoomForRenderer(RenderObject* renderer)
325 {
326 // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
327 // other out, but the alternative is that we'd have to crawl up the whole render tree every
328 // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
329 float zoomFactor = 1;
330 if (renderer->style()->effectiveZoom() != 1) {
331 // Need to find the nearest enclosing RenderObject that set up
332 // a differing zoom, and then we divide our result by it to eliminate the zoom.
333 RenderObject* prev = renderer;
334 for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) {
335 if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) {
336 zoomFactor = prev->style()->zoom();
337 break;
338 }
339 prev = curr;
340 }
341 if (prev->isRenderView())
342 zoomFactor = prev->style()->zoom();
343 }
344 return zoomFactor;
345 }
346
adjustForLocalZoom(int value,RenderObject * renderer)347 static int adjustForLocalZoom(int value, RenderObject* renderer)
348 {
349 float zoomFactor = localZoomForRenderer(renderer);
350 if (zoomFactor == 1)
351 return value;
352 // Needed because computeLengthInt truncates (rather than rounds) when scaling up.
353 if (zoomFactor > 1)
354 value++;
355 return static_cast<int>(value / zoomFactor);
356 }
357
offsetLeft()358 int Element::offsetLeft()
359 {
360 document()->updateLayoutIgnorePendingStylesheets();
361 if (RenderBoxModelObject* rend = renderBoxModelObject())
362 return adjustForLocalZoom(rend->offsetLeft(), rend);
363 return 0;
364 }
365
offsetTop()366 int Element::offsetTop()
367 {
368 document()->updateLayoutIgnorePendingStylesheets();
369 if (RenderBoxModelObject* rend = renderBoxModelObject())
370 return adjustForLocalZoom(rend->offsetTop(), rend);
371 return 0;
372 }
373
offsetWidth()374 int Element::offsetWidth()
375 {
376 document()->updateLayoutIgnorePendingStylesheets();
377 if (RenderBoxModelObject* rend = renderBoxModelObject())
378 return adjustForAbsoluteZoom(rend->offsetWidth(), rend);
379 return 0;
380 }
381
offsetHeight()382 int Element::offsetHeight()
383 {
384 document()->updateLayoutIgnorePendingStylesheets();
385 if (RenderBoxModelObject* rend = renderBoxModelObject())
386 return adjustForAbsoluteZoom(rend->offsetHeight(), rend);
387 return 0;
388 }
389
offsetParent()390 Element* Element::offsetParent()
391 {
392 document()->updateLayoutIgnorePendingStylesheets();
393 if (RenderObject* rend = renderer())
394 if (RenderObject* offsetParent = rend->offsetParent())
395 return static_cast<Element*>(offsetParent->node());
396 return 0;
397 }
398
clientLeft()399 int Element::clientLeft()
400 {
401 document()->updateLayoutIgnorePendingStylesheets();
402
403 if (RenderBox* rend = renderBox())
404 return adjustForAbsoluteZoom(rend->clientLeft(), rend);
405 return 0;
406 }
407
clientTop()408 int Element::clientTop()
409 {
410 document()->updateLayoutIgnorePendingStylesheets();
411
412 if (RenderBox* rend = renderBox())
413 return adjustForAbsoluteZoom(rend->clientTop(), rend);
414 return 0;
415 }
416
clientWidth()417 int Element::clientWidth()
418 {
419 document()->updateLayoutIgnorePendingStylesheets();
420
421 // When in strict mode, clientWidth for the document element should return the width of the containing frame.
422 // When in quirks mode, clientWidth for the body element should return the width of the containing frame.
423 bool inQuirksMode = document()->inQuirksMode();
424 if ((!inQuirksMode && document()->documentElement() == this) ||
425 (inQuirksMode && isHTMLElement() && document()->body() == this)) {
426 if (FrameView* view = document()->view()) {
427 if (RenderView* renderView = document()->renderView())
428 return adjustForAbsoluteZoom(view->layoutWidth(), renderView);
429 }
430 }
431
432 if (RenderBox* rend = renderBox())
433 return adjustForAbsoluteZoom(rend->clientWidth(), rend);
434 return 0;
435 }
436
clientHeight()437 int Element::clientHeight()
438 {
439 document()->updateLayoutIgnorePendingStylesheets();
440
441 // When in strict mode, clientHeight for the document element should return the height of the containing frame.
442 // When in quirks mode, clientHeight for the body element should return the height of the containing frame.
443 bool inQuirksMode = document()->inQuirksMode();
444
445 if ((!inQuirksMode && document()->documentElement() == this) ||
446 (inQuirksMode && isHTMLElement() && document()->body() == this)) {
447 if (FrameView* view = document()->view()) {
448 if (RenderView* renderView = document()->renderView())
449 return adjustForAbsoluteZoom(view->layoutHeight(), renderView);
450 }
451 }
452
453 if (RenderBox* rend = renderBox())
454 return adjustForAbsoluteZoom(rend->clientHeight(), rend);
455 return 0;
456 }
457
scrollLeft() const458 int Element::scrollLeft() const
459 {
460 document()->updateLayoutIgnorePendingStylesheets();
461 if (RenderBox* rend = renderBox())
462 return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
463 return 0;
464 }
465
scrollTop() const466 int Element::scrollTop() const
467 {
468 document()->updateLayoutIgnorePendingStylesheets();
469 if (RenderBox* rend = renderBox())
470 return adjustForAbsoluteZoom(rend->scrollTop(), rend);
471 return 0;
472 }
473
setScrollLeft(int newLeft)474 void Element::setScrollLeft(int newLeft)
475 {
476 document()->updateLayoutIgnorePendingStylesheets();
477 if (RenderBox* rend = renderBox())
478 rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
479 }
480
setScrollTop(int newTop)481 void Element::setScrollTop(int newTop)
482 {
483 document()->updateLayoutIgnorePendingStylesheets();
484 if (RenderBox* rend = renderBox())
485 rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
486 }
487
scrollWidth() const488 int Element::scrollWidth() const
489 {
490 document()->updateLayoutIgnorePendingStylesheets();
491 if (RenderBox* rend = renderBox())
492 return adjustForAbsoluteZoom(rend->scrollWidth(), rend);
493 return 0;
494 }
495
scrollHeight() const496 int Element::scrollHeight() const
497 {
498 document()->updateLayoutIgnorePendingStylesheets();
499 if (RenderBox* rend = renderBox())
500 return adjustForAbsoluteZoom(rend->scrollHeight(), rend);
501 return 0;
502 }
503
boundsInWindowSpace() const504 IntRect Element::boundsInWindowSpace() const
505 {
506 document()->updateLayoutIgnorePendingStylesheets();
507
508 FrameView* view = document()->view();
509 if (!view)
510 return IntRect();
511
512 Vector<FloatQuad> quads;
513 #if ENABLE(SVG)
514 if (isSVGElement() && renderer()) {
515 // Get the bounding rectangle from the SVG model.
516 const SVGElement* svgElement = static_cast<const SVGElement*>(this);
517 FloatRect localRect;
518 if (svgElement->boundingBox(localRect))
519 quads.append(renderer()->localToAbsoluteQuad(localRect));
520 } else
521 #endif
522 {
523 // Get the bounding rectangle from the box model.
524 if (renderBoxModelObject())
525 renderBoxModelObject()->absoluteQuads(quads);
526 }
527
528 if (quads.isEmpty())
529 return IntRect();
530
531 IntRect result = quads[0].enclosingBoundingBox();
532 for (size_t i = 1; i < quads.size(); ++i)
533 result.unite(quads[i].enclosingBoundingBox());
534
535 result = view->contentsToWindow(result);
536 return result;
537 }
538
getClientRects() const539 PassRefPtr<ClientRectList> Element::getClientRects() const
540 {
541 document()->updateLayoutIgnorePendingStylesheets();
542
543 RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject();
544 if (!renderBoxModelObject)
545 return ClientRectList::create();
546
547 // FIXME: Handle SVG elements.
548 // FIXME: Handle table/inline-table with a caption.
549
550 Vector<FloatQuad> quads;
551 renderBoxModelObject->absoluteQuads(quads);
552
553 float pageScale = 1;
554 if (Page* page = document()->page()) {
555 if (Frame* frame = page->mainFrame())
556 pageScale = frame->pageScaleFactor();
557 }
558
559 if (FrameView* view = document()->view()) {
560 IntRect visibleContentRect = view->visibleContentRect();
561 for (size_t i = 0; i < quads.size(); ++i) {
562 quads[i].move(-visibleContentRect.x(), -visibleContentRect.y());
563 adjustFloatQuadForAbsoluteZoom(quads[i], renderBoxModelObject);
564 if (pageScale != 1)
565 adjustFloatQuadForPageScale(quads[i], pageScale);
566 }
567 }
568
569 return ClientRectList::create(quads);
570 }
571
getBoundingClientRect() const572 PassRefPtr<ClientRect> Element::getBoundingClientRect() const
573 {
574 document()->updateLayoutIgnorePendingStylesheets();
575
576 Vector<FloatQuad> quads;
577 #if ENABLE(SVG)
578 if (isSVGElement() && renderer()) {
579 // Get the bounding rectangle from the SVG model.
580 const SVGElement* svgElement = static_cast<const SVGElement*>(this);
581 FloatRect localRect;
582 if (svgElement->boundingBox(localRect))
583 quads.append(renderer()->localToAbsoluteQuad(localRect));
584 } else
585 #endif
586 {
587 // Get the bounding rectangle from the box model.
588 if (renderBoxModelObject())
589 renderBoxModelObject()->absoluteQuads(quads);
590 }
591
592 if (quads.isEmpty())
593 return ClientRect::create();
594
595 FloatRect result = quads[0].boundingBox();
596 for (size_t i = 1; i < quads.size(); ++i)
597 result.unite(quads[i].boundingBox());
598
599 if (FrameView* view = document()->view()) {
600 IntRect visibleContentRect = view->visibleContentRect();
601 result.move(-visibleContentRect.x(), -visibleContentRect.y());
602 }
603
604 adjustFloatRectForAbsoluteZoom(result, renderer());
605 if (Page* page = document()->page()) {
606 if (Frame* frame = page->mainFrame())
607 adjustFloatRectForPageScale(result, frame->pageScaleFactor());
608 }
609
610 return ClientRect::create(result);
611 }
612
screenRect() const613 IntRect Element::screenRect() const
614 {
615 if (!renderer())
616 return IntRect();
617 return renderer()->view()->frameView()->contentsToScreen(renderer()->absoluteBoundingBoxRect());
618 }
619
shouldIgnoreAttributeCase(const Element * e)620 static inline bool shouldIgnoreAttributeCase(const Element* e)
621 {
622 return e && e->document()->isHTMLDocument() && e->isHTMLElement();
623 }
624
getAttribute(const String & name) const625 const AtomicString& Element::getAttribute(const String& name) const
626 {
627 bool ignoreCase = shouldIgnoreAttributeCase(this);
628
629 // Update the 'style' attribute if it's invalid and being requested:
630 if (!isStyleAttributeValid() && equalPossiblyIgnoringCase(name, styleAttr.localName(), ignoreCase))
631 updateStyleAttribute();
632
633 #if ENABLE(SVG)
634 if (!areSVGAttributesValid()) {
635 // We're not passing a namespace argument on purpose. SVGNames::*Attr are defined w/o namespaces as well.
636 updateAnimatedSVGAttribute(QualifiedName(nullAtom, name, nullAtom));
637 }
638 #endif
639
640 if (m_attributeMap) {
641 if (Attribute* attribute = m_attributeMap->getAttributeItem(name, ignoreCase))
642 return attribute->value();
643 }
644
645 return nullAtom;
646 }
647
getAttributeNS(const String & namespaceURI,const String & localName) const648 const AtomicString& Element::getAttributeNS(const String& namespaceURI, const String& localName) const
649 {
650 return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
651 }
652
setAttribute(const AtomicString & name,const AtomicString & value,ExceptionCode & ec)653 void Element::setAttribute(const AtomicString& name, const AtomicString& value, ExceptionCode& ec)
654 {
655 if (!Document::isValidName(name)) {
656 ec = INVALID_CHARACTER_ERR;
657 return;
658 }
659
660 #if ENABLE(INSPECTOR)
661 if (!isSynchronizingStyleAttribute())
662 InspectorInstrumentation::willModifyDOMAttr(document(), this);
663 #endif
664
665 const AtomicString& localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
666 QualifiedName attributeName(nullAtom, localName, nullAtom);
667
668 // Allocate attribute map if necessary.
669 Attribute* old = attributes(false)->getAttributeItem(localName, false);
670
671 document()->incDOMTreeVersion();
672
673 if (isIdAttributeName(old ? old->name() : attributeName))
674 updateId(old ? old->value() : nullAtom, value);
675
676 if (old && value.isNull())
677 m_attributeMap->removeAttribute(old->name());
678 else if (!old && !value.isNull())
679 m_attributeMap->addAttribute(createAttribute(attributeName, value));
680 else if (old && !value.isNull()) {
681 if (Attr* attrNode = old->attr())
682 attrNode->setValue(value);
683 else
684 old->setValue(value);
685 attributeChanged(old);
686 }
687
688 #if ENABLE(INSPECTOR)
689 if (!isSynchronizingStyleAttribute())
690 InspectorInstrumentation::didModifyDOMAttr(document(), this);
691 #endif
692 }
693
setAttribute(const QualifiedName & name,const AtomicString & value,ExceptionCode &)694 void Element::setAttribute(const QualifiedName& name, const AtomicString& value, ExceptionCode&)
695 {
696 #if ENABLE(INSPECTOR)
697 if (!isSynchronizingStyleAttribute())
698 InspectorInstrumentation::willModifyDOMAttr(document(), this);
699 #endif
700
701 document()->incDOMTreeVersion();
702
703 // Allocate attribute map if necessary.
704 Attribute* old = attributes(false)->getAttributeItem(name);
705
706 if (isIdAttributeName(name))
707 updateId(old ? old->value() : nullAtom, value);
708
709 if (old && value.isNull())
710 m_attributeMap->removeAttribute(name);
711 else if (!old && !value.isNull())
712 m_attributeMap->addAttribute(createAttribute(name, value));
713 else if (old) {
714 if (Attr* attrNode = old->attr())
715 attrNode->setValue(value);
716 else
717 old->setValue(value);
718 attributeChanged(old);
719 }
720
721 #if ENABLE(INSPECTOR)
722 if (!isSynchronizingStyleAttribute())
723 InspectorInstrumentation::didModifyDOMAttr(document(), this);
724 #endif
725 }
726
createAttribute(const QualifiedName & name,const AtomicString & value)727 PassRefPtr<Attribute> Element::createAttribute(const QualifiedName& name, const AtomicString& value)
728 {
729 return Attribute::create(name, value);
730 }
731
attributeChanged(Attribute * attr,bool)732 void Element::attributeChanged(Attribute* attr, bool)
733 {
734 if (isIdAttributeName(attr->name()))
735 idAttributeChanged(attr);
736 recalcStyleIfNeededAfterAttributeChanged(attr);
737 updateAfterAttributeChanged(attr);
738 }
739
updateAfterAttributeChanged(Attribute * attr)740 void Element::updateAfterAttributeChanged(Attribute* attr)
741 {
742 if (!AXObjectCache::accessibilityEnabled())
743 return;
744
745 const QualifiedName& attrName = attr->name();
746 if (attrName == aria_activedescendantAttr) {
747 // any change to aria-activedescendant attribute triggers accessibility focus change, but document focus remains intact
748 document()->axObjectCache()->handleActiveDescendantChanged(renderer());
749 } else if (attrName == roleAttr) {
750 // the role attribute can change at any time, and the AccessibilityObject must pick up these changes
751 document()->axObjectCache()->handleAriaRoleChanged(renderer());
752 } else if (attrName == aria_valuenowAttr) {
753 // If the valuenow attribute changes, AX clients need to be notified.
754 document()->axObjectCache()->postNotification(renderer(), AXObjectCache::AXValueChanged, true);
755 } else if (attrName == aria_labelAttr || attrName == aria_labeledbyAttr || attrName == altAttr || attrName == titleAttr) {
756 // If the content of an element changes due to an attribute change, notify accessibility.
757 document()->axObjectCache()->contentChanged(renderer());
758 } else if (attrName == aria_selectedAttr)
759 document()->axObjectCache()->selectedChildrenChanged(renderer());
760 else if (attrName == aria_expandedAttr)
761 document()->axObjectCache()->handleAriaExpandedChange(renderer());
762 else if (attrName == aria_hiddenAttr)
763 document()->axObjectCache()->childrenChanged(renderer());
764 else if (attrName == aria_invalidAttr)
765 document()->axObjectCache()->postNotification(renderer(), AXObjectCache::AXInvalidStatusChanged, true);
766 }
767
recalcStyleIfNeededAfterAttributeChanged(Attribute * attr)768 void Element::recalcStyleIfNeededAfterAttributeChanged(Attribute* attr)
769 {
770 if (document()->attached() && document()->styleSelector()->hasSelectorForAttribute(attr->name().localName()))
771 setNeedsStyleRecalc();
772 }
773
idAttributeChanged(Attribute * attr)774 void Element::idAttributeChanged(Attribute* attr)
775 {
776 setHasID(!attr->isNull());
777 if (attributeMap()) {
778 if (attr->isNull())
779 attributeMap()->setIdForStyleResolution(nullAtom);
780 else if (document()->inQuirksMode())
781 attributeMap()->setIdForStyleResolution(attr->value().lower());
782 else
783 attributeMap()->setIdForStyleResolution(attr->value());
784 }
785 setNeedsStyleRecalc();
786 }
787
788 // Returns true is the given attribute is an event handler.
789 // We consider an event handler any attribute that begins with "on".
790 // It is a simple solution that has the advantage of not requiring any
791 // code or configuration change if a new event handler is defined.
792
isEventHandlerAttribute(const QualifiedName & name)793 static bool isEventHandlerAttribute(const QualifiedName& name)
794 {
795 return name.namespaceURI().isNull() && name.localName().startsWith("on");
796 }
797
isAttributeToRemove(const QualifiedName & name,const AtomicString & value)798 static bool isAttributeToRemove(const QualifiedName& name, const AtomicString& value)
799 {
800 return (name.localName().endsWith(hrefAttr.localName()) || name == srcAttr || name == actionAttr) && protocolIsJavaScript(stripLeadingAndTrailingHTMLSpaces(value));
801 }
802
setAttributeMap(PassRefPtr<NamedNodeMap> list,FragmentScriptingPermission scriptingPermission)803 void Element::setAttributeMap(PassRefPtr<NamedNodeMap> list, FragmentScriptingPermission scriptingPermission)
804 {
805 document()->incDOMTreeVersion();
806
807 // If setting the whole map changes the id attribute, we need to call updateId.
808
809 const QualifiedName& idName = document()->idAttributeName();
810 Attribute* oldId = m_attributeMap ? m_attributeMap->getAttributeItem(idName) : 0;
811 Attribute* newId = list ? list->getAttributeItem(idName) : 0;
812
813 if (oldId || newId)
814 updateId(oldId ? oldId->value() : nullAtom, newId ? newId->value() : nullAtom);
815
816 if (m_attributeMap)
817 m_attributeMap->m_element = 0;
818
819 m_attributeMap = list;
820
821 if (m_attributeMap) {
822 m_attributeMap->m_element = this;
823 // If the element is created as result of a paste or drag-n-drop operation
824 // we want to remove all the script and event handlers.
825 if (scriptingPermission == FragmentScriptingNotAllowed) {
826 unsigned i = 0;
827 while (i < m_attributeMap->length()) {
828 const QualifiedName& attributeName = m_attributeMap->m_attributes[i]->name();
829 if (isEventHandlerAttribute(attributeName)) {
830 m_attributeMap->m_attributes.remove(i);
831 continue;
832 }
833
834 if (isAttributeToRemove(attributeName, m_attributeMap->m_attributes[i]->value()))
835 m_attributeMap->m_attributes[i]->setValue(nullAtom);
836 i++;
837 }
838 }
839 // Store the set of attributes that changed on the stack in case
840 // attributeChanged mutates m_attributeMap.
841 Vector<RefPtr<Attribute> > attributes;
842 m_attributeMap->copyAttributesToVector(attributes);
843 for (Vector<RefPtr<Attribute> >::iterator iter = attributes.begin(); iter != attributes.end(); ++iter)
844 attributeChanged(iter->get());
845 // FIXME: What about attributes that were in the old map that are not in the new map?
846 }
847 }
848
hasAttributes() const849 bool Element::hasAttributes() const
850 {
851 if (!isStyleAttributeValid())
852 updateStyleAttribute();
853
854 #if ENABLE(SVG)
855 if (!areSVGAttributesValid())
856 updateAnimatedSVGAttribute(anyQName());
857 #endif
858
859 return m_attributeMap && m_attributeMap->length();
860 }
861
nodeName() const862 String Element::nodeName() const
863 {
864 return m_tagName.toString();
865 }
866
nodeNamePreservingCase() const867 String Element::nodeNamePreservingCase() const
868 {
869 return m_tagName.toString();
870 }
871
setPrefix(const AtomicString & prefix,ExceptionCode & ec)872 void Element::setPrefix(const AtomicString& prefix, ExceptionCode& ec)
873 {
874 ec = 0;
875 checkSetPrefix(prefix, ec);
876 if (ec)
877 return;
878
879 m_tagName.setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
880 }
881
baseURI() const882 KURL Element::baseURI() const
883 {
884 const AtomicString& baseAttribute = getAttribute(baseAttr);
885 KURL base(KURL(), baseAttribute);
886 if (!base.protocol().isEmpty())
887 return base;
888
889 ContainerNode* parent = parentNode();
890 if (!parent)
891 return base;
892
893 const KURL& parentBase = parent->baseURI();
894 if (parentBase.isNull())
895 return base;
896
897 return KURL(parentBase, baseAttribute);
898 }
899
createAttributeMap() const900 void Element::createAttributeMap() const
901 {
902 m_attributeMap = NamedNodeMap::create(const_cast<Element*>(this));
903 }
904
isURLAttribute(Attribute *) const905 bool Element::isURLAttribute(Attribute*) const
906 {
907 return false;
908 }
909
imageSourceAttributeName() const910 const QualifiedName& Element::imageSourceAttributeName() const
911 {
912 return srcAttr;
913 }
914
createRenderer(RenderArena * arena,RenderStyle * style)915 RenderObject* Element::createRenderer(RenderArena* arena, RenderStyle* style)
916 {
917 if (document()->documentElement() == this && style->display() == NONE) {
918 // Ignore display: none on root elements. Force a display of block in that case.
919 RenderBlock* result = new (arena) RenderBlock(this);
920 if (result)
921 result->setAnimatableStyle(style);
922 return result;
923 }
924 return RenderObject::createObject(this, style);
925 }
926
wasChangedSinceLastFormControlChangeEvent() const927 bool Element::wasChangedSinceLastFormControlChangeEvent() const
928 {
929 return false;
930 }
931
setChangedSinceLastFormControlChangeEvent(bool)932 void Element::setChangedSinceLastFormControlChangeEvent(bool)
933 {
934 }
935
insertedIntoDocument()936 void Element::insertedIntoDocument()
937 {
938 // need to do superclass processing first so inDocument() is true
939 // by the time we reach updateId
940 ContainerNode::insertedIntoDocument();
941 if (Node* shadow = shadowRoot())
942 shadow->insertedIntoDocument();
943
944 if (hasID()) {
945 if (m_attributeMap) {
946 Attribute* idItem = m_attributeMap->getAttributeItem(document()->idAttributeName());
947 if (idItem && !idItem->isNull())
948 updateId(nullAtom, idItem->value());
949 }
950 }
951 }
952
removedFromDocument()953 void Element::removedFromDocument()
954 {
955 if (hasID()) {
956 if (m_attributeMap) {
957 Attribute* idItem = m_attributeMap->getAttributeItem(document()->idAttributeName());
958 if (idItem && !idItem->isNull())
959 updateId(idItem->value(), nullAtom);
960 }
961 }
962
963 ContainerNode::removedFromDocument();
964 if (Node* shadow = shadowRoot())
965 shadow->removedFromDocument();
966 }
967
insertedIntoTree(bool deep)968 void Element::insertedIntoTree(bool deep)
969 {
970 ContainerNode::insertedIntoTree(deep);
971 if (!deep)
972 return;
973 if (Node* shadow = shadowRoot())
974 shadow->insertedIntoTree(true);
975 }
976
removedFromTree(bool deep)977 void Element::removedFromTree(bool deep)
978 {
979 ContainerNode::removedFromTree(deep);
980 if (!deep)
981 return;
982 if (Node* shadow = shadowRoot())
983 shadow->removedFromTree(true);
984 }
985
attach()986 void Element::attach()
987 {
988 suspendPostAttachCallbacks();
989 RenderWidget::suspendWidgetHierarchyUpdates();
990
991 createRendererIfNeeded();
992
993 StyleSelectorParentPusher parentPusher(this);
994
995 if (Node* shadow = shadowRoot()) {
996 parentPusher.push();
997 shadow->attach();
998 }
999
1000 if (firstChild())
1001 parentPusher.push();
1002 ContainerNode::attach();
1003
1004 if (hasRareData()) {
1005 ElementRareData* data = rareData();
1006 if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
1007 if (isFocusable() && document()->focusedNode() == this)
1008 document()->updateFocusAppearanceSoon(false /* don't restore selection */);
1009 data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1010 }
1011 }
1012
1013 RenderWidget::resumeWidgetHierarchyUpdates();
1014 resumePostAttachCallbacks();
1015 }
1016
detach()1017 void Element::detach()
1018 {
1019 RenderWidget::suspendWidgetHierarchyUpdates();
1020
1021 cancelFocusAppearanceUpdate();
1022 if (hasRareData())
1023 rareData()->resetComputedStyle();
1024 ContainerNode::detach();
1025 if (Node* shadow = shadowRoot())
1026 shadow->detach();
1027
1028 RenderWidget::resumeWidgetHierarchyUpdates();
1029 }
1030
pseudoStyleCacheIsInvalid(const RenderStyle * currentStyle,RenderStyle * newStyle)1031 bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle)
1032 {
1033 ASSERT(currentStyle == renderStyle());
1034
1035 if (!renderer() || !currentStyle)
1036 return false;
1037
1038 const PseudoStyleCache* pseudoStyleCache = currentStyle->cachedPseudoStyles();
1039 if (!pseudoStyleCache)
1040 return false;
1041
1042 size_t cacheSize = pseudoStyleCache->size();
1043 for (size_t i = 0; i < cacheSize; ++i) {
1044 RefPtr<RenderStyle> newPseudoStyle;
1045 PseudoId pseudoId = pseudoStyleCache->at(i)->styleType();
1046 if (pseudoId == VISITED_LINK) {
1047 newPseudoStyle = newStyle->getCachedPseudoStyle(VISITED_LINK); // This pseudo-style was aggressively computed already when we first called styleForElement on the new style.
1048 if (!newPseudoStyle || *newPseudoStyle != *pseudoStyleCache->at(i))
1049 return true;
1050 } else if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
1051 newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle);
1052 else
1053 newPseudoStyle = renderer()->getUncachedPseudoStyle(pseudoId, newStyle, newStyle);
1054 if (!newPseudoStyle)
1055 return true;
1056 if (*newPseudoStyle != *pseudoStyleCache->at(i)) {
1057 if (pseudoId < FIRST_INTERNAL_PSEUDOID)
1058 newStyle->setHasPseudoStyle(pseudoId);
1059 newStyle->addCachedPseudoStyle(newPseudoStyle);
1060 if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED) {
1061 // FIXME: We should do an actual diff to determine whether a repaint vs. layout
1062 // is needed, but for now just assume a layout will be required. The diff code
1063 // in RenderObject::setStyle would need to be factored out so that it could be reused.
1064 renderer()->setNeedsLayoutAndPrefWidthsRecalc();
1065 }
1066 return true;
1067 }
1068 }
1069 return false;
1070 }
1071
1072 #ifdef ANDROID_STYLE_VERSION
displayDiff(const RenderStyle * s1,const RenderStyle * s2)1073 static bool displayDiff(const RenderStyle* s1, const RenderStyle* s2)
1074 {
1075 if (!s1 && !s2)
1076 return false;
1077 else if ((!s1 && s2) || (s1 && !s2))
1078 return true;
1079
1080 return s1->display() != s2->display()
1081 || s1->left() != s2->left() || s1->top() != s2->top()
1082 || s1->right() != s2->right() || s1->bottom() != s2->bottom()
1083 || s1->width() != s2->width() || s1->height() != s2->height();
1084 }
1085 #endif
1086
recalcStyle(StyleChange change)1087 void Element::recalcStyle(StyleChange change)
1088 {
1089 // Ref currentStyle in case it would otherwise be deleted when setRenderStyle() is called.
1090 RefPtr<RenderStyle> currentStyle(renderStyle());
1091 bool hasParentStyle = parentNodeForRenderingAndStyle() ? parentNodeForRenderingAndStyle()->renderStyle() : false;
1092 bool hasDirectAdjacentRules = currentStyle && currentStyle->childrenAffectedByDirectAdjacentRules();
1093
1094 if ((change > NoChange || needsStyleRecalc())) {
1095 #ifdef ANDROID_STYLE_VERSION
1096 RefPtr<RenderStyle> newStyle = document()->styleForElementIgnoringPendingStylesheets(this);
1097 if (displayDiff(currentStyle.get(), newStyle.get()))
1098 document()->incStyleVersion();
1099 #endif
1100 if (hasRareData())
1101 rareData()->resetComputedStyle();
1102 }
1103 if (hasParentStyle && (change >= Inherit || needsStyleRecalc())) {
1104 RefPtr<RenderStyle> newStyle = document()->styleSelector()->styleForElement(this);
1105 StyleChange ch = diff(currentStyle.get(), newStyle.get());
1106 if (ch == Detach || !currentStyle) {
1107 if (attached())
1108 detach();
1109 attach(); // FIXME: The style gets computed twice by calling attach. We could do better if we passed the style along.
1110 // attach recalulates the style for all children. No need to do it twice.
1111 clearNeedsStyleRecalc();
1112 clearChildNeedsStyleRecalc();
1113 return;
1114 }
1115
1116 if (currentStyle) {
1117 // Preserve "affected by" bits that were propagated to us from descendants in the case where we didn't do a full
1118 // style change (e.g., only inline style changed).
1119 if (currentStyle->affectedByHoverRules())
1120 newStyle->setAffectedByHoverRules(true);
1121 if (currentStyle->affectedByActiveRules())
1122 newStyle->setAffectedByActiveRules(true);
1123 if (currentStyle->affectedByDragRules())
1124 newStyle->setAffectedByDragRules(true);
1125 if (currentStyle->childrenAffectedByForwardPositionalRules())
1126 newStyle->setChildrenAffectedByForwardPositionalRules();
1127 if (currentStyle->childrenAffectedByBackwardPositionalRules())
1128 newStyle->setChildrenAffectedByBackwardPositionalRules();
1129 if (currentStyle->childrenAffectedByFirstChildRules())
1130 newStyle->setChildrenAffectedByFirstChildRules();
1131 if (currentStyle->childrenAffectedByLastChildRules())
1132 newStyle->setChildrenAffectedByLastChildRules();
1133 if (currentStyle->childrenAffectedByDirectAdjacentRules())
1134 newStyle->setChildrenAffectedByDirectAdjacentRules();
1135 }
1136
1137 if (ch != NoChange || pseudoStyleCacheIsInvalid(currentStyle.get(), newStyle.get()) || (change == Force && renderer() && renderer()->requiresForcedStyleRecalcPropagation())) {
1138 setRenderStyle(newStyle);
1139 } else if (needsStyleRecalc() && styleChangeType() != SyntheticStyleChange) {
1140 // Although no change occurred, we use the new style so that the cousin style sharing code won't get
1141 // fooled into believing this style is the same.
1142 if (renderer())
1143 renderer()->setStyleInternal(newStyle.get());
1144 else
1145 setRenderStyle(newStyle);
1146 } else if (styleChangeType() == SyntheticStyleChange)
1147 setRenderStyle(newStyle);
1148
1149 if (change != Force) {
1150 // 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
1151 // 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).
1152 if (document()->usesRemUnits() && ch != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize() && document()->documentElement() == this)
1153 change = Force;
1154 else if (styleChangeType() >= FullStyleChange)
1155 change = Force;
1156 else
1157 change = ch;
1158 }
1159 }
1160 StyleSelectorParentPusher parentPusher(this);
1161 // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
1162 // For now we will just worry about the common case, since it's a lot trickier to get the second case right
1163 // without doing way too much re-resolution.
1164 bool forceCheckOfNextElementSibling = false;
1165 for (Node *n = firstChild(); n; n = n->nextSibling()) {
1166 bool childRulesChanged = n->needsStyleRecalc() && n->styleChangeType() == FullStyleChange;
1167 if (forceCheckOfNextElementSibling && n->isElementNode())
1168 n->setNeedsStyleRecalc();
1169 if (change >= Inherit || n->isTextNode() || n->childNeedsStyleRecalc() || n->needsStyleRecalc()) {
1170 parentPusher.push();
1171 n->recalcStyle(change);
1172 }
1173 if (n->isElementNode())
1174 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
1175 }
1176 // FIXME: This does not care about sibling combinators. Will be necessary in XBL2 world.
1177 if (Node* shadow = shadowRoot()) {
1178 if (change >= Inherit || shadow->childNeedsStyleRecalc() || shadow->needsStyleRecalc()) {
1179 parentPusher.push();
1180 shadow->recalcStyle(change);
1181 }
1182 }
1183
1184 clearNeedsStyleRecalc();
1185 clearChildNeedsStyleRecalc();
1186 }
1187
shadowRoot() const1188 ContainerNode* Element::shadowRoot() const
1189 {
1190 return hasRareData() ? rareData()->m_shadowRoot : 0;
1191 }
1192
ensureShadowRoot()1193 ContainerNode* Element::ensureShadowRoot()
1194 {
1195 if (ContainerNode* existingRoot = shadowRoot())
1196 return existingRoot;
1197
1198 RefPtr<ShadowRoot> newRoot = ShadowRoot::create(document());
1199 ensureRareData()->m_shadowRoot = newRoot.get();
1200 newRoot->setShadowHost(this);
1201 if (inDocument())
1202 newRoot->insertedIntoDocument();
1203 if (attached())
1204 newRoot->lazyAttach();
1205 return newRoot.get();
1206 }
1207
removeShadowRoot()1208 void Element::removeShadowRoot()
1209 {
1210 if (!hasRareData())
1211 return;
1212
1213 ElementRareData* data = rareData();
1214 if (RefPtr<Node> oldRoot = data->m_shadowRoot) {
1215 data->m_shadowRoot = 0;
1216 document()->removeFocusedNodeOfSubtree(oldRoot.get());
1217 oldRoot->setShadowHost(0);
1218 if (oldRoot->inDocument())
1219 oldRoot->removedFromDocument();
1220 else
1221 oldRoot->removedFromTree(true);
1222 }
1223 }
1224
childTypeAllowed(NodeType type) const1225 bool Element::childTypeAllowed(NodeType type) const
1226 {
1227 switch (type) {
1228 case ELEMENT_NODE:
1229 case TEXT_NODE:
1230 case COMMENT_NODE:
1231 case PROCESSING_INSTRUCTION_NODE:
1232 case CDATA_SECTION_NODE:
1233 case ENTITY_REFERENCE_NODE:
1234 return true;
1235 default:
1236 break;
1237 }
1238 return false;
1239 }
1240
checkForEmptyStyleChange(Element * element,RenderStyle * style)1241 static void checkForEmptyStyleChange(Element* element, RenderStyle* style)
1242 {
1243 if (!style)
1244 return;
1245
1246 if (style->affectedByEmpty() && (!style->emptyState() || element->hasChildNodes()))
1247 element->setNeedsStyleRecalc();
1248 }
1249
checkForSiblingStyleChanges(Element * e,RenderStyle * style,bool finishedParsingCallback,Node * beforeChange,Node * afterChange,int childCountDelta)1250 static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
1251 Node* beforeChange, Node* afterChange, int childCountDelta)
1252 {
1253 if (!style || (e->needsStyleRecalc() && style->childrenAffectedByPositionalRules()))
1254 return;
1255
1256 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1257 // In the DOM case, we only need to do something if |afterChange| is not 0.
1258 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
1259 if (style->childrenAffectedByFirstChildRules() && afterChange) {
1260 // Find our new first child.
1261 Node* newFirstChild = 0;
1262 for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {};
1263
1264 // Find the first element node following |afterChange|
1265 Node* firstElementAfterInsertion = 0;
1266 for (firstElementAfterInsertion = afterChange;
1267 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
1268 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
1269
1270 // This is the insert/append case.
1271 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertion && firstElementAfterInsertion->attached() &&
1272 firstElementAfterInsertion->renderStyle() && firstElementAfterInsertion->renderStyle()->firstChildState())
1273 firstElementAfterInsertion->setNeedsStyleRecalc();
1274
1275 // We also have to handle node removal.
1276 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && newFirstChild->renderStyle() && !newFirstChild->renderStyle()->firstChildState())
1277 newFirstChild->setNeedsStyleRecalc();
1278 }
1279
1280 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1281 // In the DOM case, we only need to do something if |afterChange| is not 0.
1282 if (style->childrenAffectedByLastChildRules() && beforeChange) {
1283 // Find our new last child.
1284 Node* newLastChild = 0;
1285 for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {};
1286
1287 // Find the last element node going backwards from |beforeChange|
1288 Node* lastElementBeforeInsertion = 0;
1289 for (lastElementBeforeInsertion = beforeChange;
1290 lastElementBeforeInsertion && !lastElementBeforeInsertion->isElementNode();
1291 lastElementBeforeInsertion = lastElementBeforeInsertion->previousSibling()) {};
1292
1293 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertion && lastElementBeforeInsertion->attached() &&
1294 lastElementBeforeInsertion->renderStyle() && lastElementBeforeInsertion->renderStyle()->lastChildState())
1295 lastElementBeforeInsertion->setNeedsStyleRecalc();
1296
1297 // 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
1298 // to match now.
1299 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && newLastChild->renderStyle() && !newLastChild->renderStyle()->lastChildState())
1300 newLastChild->setNeedsStyleRecalc();
1301 }
1302
1303 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
1304 // that could be affected by this DOM change.
1305 if (style->childrenAffectedByDirectAdjacentRules() && afterChange) {
1306 Node* firstElementAfterInsertion = 0;
1307 for (firstElementAfterInsertion = afterChange;
1308 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
1309 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
1310 if (firstElementAfterInsertion && firstElementAfterInsertion->attached())
1311 firstElementAfterInsertion->setNeedsStyleRecalc();
1312 }
1313
1314 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
1315 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1316 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
1317 // backward case.
1318 // |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.
1319 // 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
1320 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
1321 if ((style->childrenAffectedByForwardPositionalRules() && afterChange) ||
1322 (style->childrenAffectedByBackwardPositionalRules() && beforeChange))
1323 e->setNeedsStyleRecalc();
1324
1325 // :empty selector.
1326 checkForEmptyStyleChange(e, style);
1327 }
1328
childrenChanged(bool changedByParser,Node * beforeChange,Node * afterChange,int childCountDelta)1329 void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
1330 {
1331 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
1332 if (changedByParser)
1333 checkForEmptyStyleChange(this, renderStyle());
1334 else
1335 checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
1336 }
1337
beginParsingChildren()1338 void Element::beginParsingChildren()
1339 {
1340 clearIsParsingChildrenFinished();
1341 CSSStyleSelector* styleSelector = document()->styleSelectorIfExists();
1342 if (styleSelector && attached())
1343 styleSelector->pushParent(this);
1344 }
1345
finishParsingChildren()1346 void Element::finishParsingChildren()
1347 {
1348 ContainerNode::finishParsingChildren();
1349 setIsParsingChildrenFinished();
1350 checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
1351 if (CSSStyleSelector* styleSelector = document()->styleSelectorIfExists())
1352 styleSelector->popParent(this);
1353 }
1354
dispatchAttrRemovalEvent(Attribute *)1355 void Element::dispatchAttrRemovalEvent(Attribute*)
1356 {
1357 ASSERT(!eventDispatchForbidden());
1358
1359 #if 0
1360 if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER))
1361 return;
1362 ExceptionCode ec = 0;
1363 dispatchScopedEvent(MutationEvent::create(DOMAttrModifiedEvent, true, attr, attr->value(),
1364 attr->value(), document()->attrName(attr->id()), MutationEvent::REMOVAL), ec);
1365 #endif
1366 }
1367
dispatchAttrAdditionEvent(Attribute *)1368 void Element::dispatchAttrAdditionEvent(Attribute*)
1369 {
1370 ASSERT(!eventDispatchForbidden());
1371
1372 #if 0
1373 if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER))
1374 return;
1375 ExceptionCode ec = 0;
1376 dispatchScopedEvent(MutationEvent::create(DOMAttrModifiedEvent, true, attr, attr->value(),
1377 attr->value(), document()->attrName(attr->id()), MutationEvent::ADDITION), ec);
1378 #endif
1379 }
1380
openTagStartToString() const1381 String Element::openTagStartToString() const
1382 {
1383 String result = "<" + nodeName();
1384
1385 NamedNodeMap* attrMap = attributes(true);
1386
1387 if (attrMap) {
1388 unsigned numAttrs = attrMap->length();
1389 for (unsigned i = 0; i < numAttrs; i++) {
1390 result += " ";
1391
1392 Attribute *attribute = attrMap->attributeItem(i);
1393 result += attribute->name().toString();
1394 if (!attribute->value().isNull()) {
1395 result += "=\"";
1396 // FIXME: substitute entities for any instances of " or '
1397 result += attribute->value();
1398 result += "\"";
1399 }
1400 }
1401 }
1402
1403 return result;
1404 }
1405
1406 #ifndef NDEBUG
formatForDebugger(char * buffer,unsigned length) const1407 void Element::formatForDebugger(char* buffer, unsigned length) const
1408 {
1409 String result;
1410 String s;
1411
1412 s = nodeName();
1413 if (s.length() > 0) {
1414 result += s;
1415 }
1416
1417 s = getIdAttribute();
1418 if (s.length() > 0) {
1419 if (result.length() > 0)
1420 result += "; ";
1421 result += "id=";
1422 result += s;
1423 }
1424
1425 s = getAttribute(classAttr);
1426 if (s.length() > 0) {
1427 if (result.length() > 0)
1428 result += "; ";
1429 result += "class=";
1430 result += s;
1431 }
1432
1433 strncpy(buffer, result.utf8().data(), length - 1);
1434 }
1435 #endif
1436
setAttributeNode(Attr * attr,ExceptionCode & ec)1437 PassRefPtr<Attr> Element::setAttributeNode(Attr* attr, ExceptionCode& ec)
1438 {
1439 if (!attr) {
1440 ec = TYPE_MISMATCH_ERR;
1441 return 0;
1442 }
1443 return static_pointer_cast<Attr>(attributes(false)->setNamedItem(attr, ec));
1444 }
1445
setAttributeNodeNS(Attr * attr,ExceptionCode & ec)1446 PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionCode& ec)
1447 {
1448 if (!attr) {
1449 ec = TYPE_MISMATCH_ERR;
1450 return 0;
1451 }
1452 return static_pointer_cast<Attr>(attributes(false)->setNamedItem(attr, ec));
1453 }
1454
removeAttributeNode(Attr * attr,ExceptionCode & ec)1455 PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec)
1456 {
1457 if (!attr) {
1458 ec = TYPE_MISMATCH_ERR;
1459 return 0;
1460 }
1461 if (attr->ownerElement() != this) {
1462 ec = NOT_FOUND_ERR;
1463 return 0;
1464 }
1465
1466 ASSERT(document() == attr->document());
1467
1468 NamedNodeMap* attrs = attributes(true);
1469 if (!attrs)
1470 return 0;
1471
1472 return static_pointer_cast<Attr>(attrs->removeNamedItem(attr->qualifiedName(), ec));
1473 }
1474
setAttributeNS(const AtomicString & namespaceURI,const AtomicString & qualifiedName,const AtomicString & value,ExceptionCode & ec,FragmentScriptingPermission scriptingPermission)1475 void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode& ec, FragmentScriptingPermission scriptingPermission)
1476 {
1477 String prefix, localName;
1478 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec))
1479 return;
1480
1481 if (namespaceURI.isNull() && !prefix.isNull()) {
1482 ec = NAMESPACE_ERR;
1483 return;
1484 }
1485
1486 QualifiedName qName(prefix, localName, namespaceURI);
1487
1488 if (scriptingPermission == FragmentScriptingNotAllowed && (isEventHandlerAttribute(qName) || isAttributeToRemove(qName, value)))
1489 return;
1490
1491 setAttribute(qName, value, ec);
1492 }
1493
removeAttribute(const String & name,ExceptionCode & ec)1494 void Element::removeAttribute(const String& name, ExceptionCode& ec)
1495 {
1496 InspectorInstrumentation::willModifyDOMAttr(document(), this);
1497
1498 String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1499
1500 if (m_attributeMap) {
1501 m_attributeMap->removeNamedItem(localName, ec);
1502 if (ec == NOT_FOUND_ERR)
1503 ec = 0;
1504 }
1505
1506 InspectorInstrumentation::didModifyDOMAttr(document(), this);
1507 }
1508
removeAttributeNS(const String & namespaceURI,const String & localName,ExceptionCode & ec)1509 void Element::removeAttributeNS(const String& namespaceURI, const String& localName, ExceptionCode& ec)
1510 {
1511 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI), ec);
1512 }
1513
getAttributeNode(const String & name)1514 PassRefPtr<Attr> Element::getAttributeNode(const String& name)
1515 {
1516 NamedNodeMap* attrs = attributes(true);
1517 if (!attrs)
1518 return 0;
1519 String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1520 return static_pointer_cast<Attr>(attrs->getNamedItem(localName));
1521 }
1522
getAttributeNodeNS(const String & namespaceURI,const String & localName)1523 PassRefPtr<Attr> Element::getAttributeNodeNS(const String& namespaceURI, const String& localName)
1524 {
1525 NamedNodeMap* attrs = attributes(true);
1526 if (!attrs)
1527 return 0;
1528 return static_pointer_cast<Attr>(attrs->getNamedItem(QualifiedName(nullAtom, localName, namespaceURI)));
1529 }
1530
hasAttribute(const String & name) const1531 bool Element::hasAttribute(const String& name) const
1532 {
1533 NamedNodeMap* attrs = attributes(true);
1534 if (!attrs)
1535 return false;
1536
1537 // This call to String::lower() seems to be required but
1538 // there may be a way to remove it.
1539 String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1540 return attrs->getAttributeItem(localName, false);
1541 }
1542
hasAttributeNS(const String & namespaceURI,const String & localName) const1543 bool Element::hasAttributeNS(const String& namespaceURI, const String& localName) const
1544 {
1545 NamedNodeMap* attrs = attributes(true);
1546 if (!attrs)
1547 return false;
1548 return attrs->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI));
1549 }
1550
style()1551 CSSStyleDeclaration *Element::style()
1552 {
1553 return 0;
1554 }
1555
focus(bool restorePreviousSelection)1556 void Element::focus(bool restorePreviousSelection)
1557 {
1558 if (!inDocument())
1559 return;
1560
1561 Document* doc = document();
1562 if (doc->focusedNode() == this)
1563 return;
1564
1565 // If the stylesheets have already been loaded we can reliably check isFocusable.
1566 // If not, we continue and set the focused node on the focus controller below so
1567 // that it can be updated soon after attach.
1568 if (doc->haveStylesheetsLoaded()) {
1569 doc->updateLayoutIgnorePendingStylesheets();
1570 if (!isFocusable())
1571 return;
1572 }
1573
1574 if (!supportsFocus())
1575 return;
1576
1577 RefPtr<Node> protect;
1578 if (Page* page = doc->page()) {
1579 // Focus and change event handlers can cause us to lose our last ref.
1580 // If a focus event handler changes the focus to a different node it
1581 // does not make sense to continue and update appearence.
1582 protect = this;
1583 if (!page->focusController()->setFocusedNode(this, doc->frame()))
1584 return;
1585 }
1586
1587 // Setting the focused node above might have invalidated the layout due to scripts.
1588 doc->updateLayoutIgnorePendingStylesheets();
1589
1590 if (!isFocusable()) {
1591 ensureRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
1592 return;
1593 }
1594
1595 cancelFocusAppearanceUpdate();
1596 updateFocusAppearance(restorePreviousSelection);
1597 }
1598
updateFocusAppearance(bool)1599 void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
1600 {
1601 if (this == rootEditableElement()) {
1602 Frame* frame = document()->frame();
1603 if (!frame)
1604 return;
1605
1606 // When focusing an editable element in an iframe, don't reset the selection if it already contains a selection.
1607 if (this == frame->selection()->rootEditableElement())
1608 return;
1609
1610 // FIXME: We should restore the previous selection if there is one.
1611 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
1612
1613 if (frame->selection()->shouldChangeSelection(newSelection)) {
1614 frame->selection()->setSelection(newSelection);
1615 frame->selection()->revealSelection();
1616 }
1617 } else if (renderer() && !renderer()->isWidget())
1618 renderer()->enclosingLayer()->scrollRectToVisible(getRect());
1619 }
1620
blur()1621 void Element::blur()
1622 {
1623 cancelFocusAppearanceUpdate();
1624 Document* doc = document();
1625 if (doc->focusedNode() == this) {
1626 if (doc->frame())
1627 doc->frame()->page()->focusController()->setFocusedNode(0, doc->frame());
1628 else
1629 doc->setFocusedNode(0);
1630 }
1631 }
1632
innerText() const1633 String Element::innerText() const
1634 {
1635 // We need to update layout, since plainText uses line boxes in the render tree.
1636 document()->updateLayoutIgnorePendingStylesheets();
1637
1638 if (!renderer())
1639 return textContent(true);
1640
1641 return plainText(rangeOfContents(const_cast<Element*>(this)).get());
1642 }
1643
outerText() const1644 String Element::outerText() const
1645 {
1646 // Getting outerText is the same as getting innerText, only
1647 // setting is different. You would think this should get the plain
1648 // text for the outer range, but this is wrong, <br> for instance
1649 // would return different values for inner and outer text by such
1650 // a rule, but it doesn't in WinIE, and we want to match that.
1651 return innerText();
1652 }
1653
title() const1654 String Element::title() const
1655 {
1656 return String();
1657 }
1658
minimumSizeForResizing() const1659 IntSize Element::minimumSizeForResizing() const
1660 {
1661 return hasRareData() ? rareData()->m_minimumSizeForResizing : defaultMinimumSizeForResizing();
1662 }
1663
setMinimumSizeForResizing(const IntSize & size)1664 void Element::setMinimumSizeForResizing(const IntSize& size)
1665 {
1666 if (size == defaultMinimumSizeForResizing() && !hasRareData())
1667 return;
1668 ensureRareData()->m_minimumSizeForResizing = size;
1669 }
1670
computedStyle(PseudoId pseudoElementSpecifier)1671 RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
1672 {
1673 // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
1674 // properties, which are only known by the renderer because it did the layout, will be correct and so that the
1675 // values returned for the ":selection" pseudo-element will be correct.
1676 if (RenderStyle* usedStyle = renderStyle())
1677 return pseudoElementSpecifier ? usedStyle->getCachedPseudoStyle(pseudoElementSpecifier) : usedStyle;
1678
1679 if (!attached())
1680 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
1681 // document tree and figure out when to destroy the computed style for such elements.
1682 return 0;
1683
1684 ElementRareData* data = ensureRareData();
1685 if (!data->m_computedStyle)
1686 data->m_computedStyle = document()->styleForElementIgnoringPendingStylesheets(this);
1687 return pseudoElementSpecifier ? data->m_computedStyle->getCachedPseudoStyle(pseudoElementSpecifier) : data->m_computedStyle.get();
1688 }
1689
computeInheritedLanguage() const1690 AtomicString Element::computeInheritedLanguage() const
1691 {
1692 const Node* n = this;
1693 AtomicString value;
1694 // The language property is inherited, so we iterate over the parents to find the first language.
1695 while (n && value.isNull()) {
1696 if (n->isElementNode()) {
1697 // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7
1698 value = static_cast<const Element*>(n)->fastGetAttribute(XMLNames::langAttr);
1699 if (value.isNull())
1700 value = static_cast<const Element*>(n)->fastGetAttribute(HTMLNames::langAttr);
1701 } else if (n->isDocumentNode()) {
1702 // checking the MIME content-language
1703 value = static_cast<const Document*>(n)->contentLanguage();
1704 }
1705
1706 n = n->parentNode();
1707 }
1708
1709 return value;
1710 }
1711
cancelFocusAppearanceUpdate()1712 void Element::cancelFocusAppearanceUpdate()
1713 {
1714 if (hasRareData())
1715 rareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1716 if (document()->focusedNode() == this)
1717 document()->cancelFocusAppearanceUpdate();
1718 }
1719
normalizeAttributes()1720 void Element::normalizeAttributes()
1721 {
1722 // Normalize attributes.
1723 NamedNodeMap* attrs = attributes(true);
1724 if (!attrs)
1725 return;
1726
1727 if (attrs->isEmpty())
1728 return;
1729
1730 Vector<RefPtr<Attribute> > attributeVector;
1731 attrs->copyAttributesToVector(attributeVector);
1732 size_t numAttrs = attributeVector.size();
1733 for (size_t i = 0; i < numAttrs; ++i) {
1734 if (Attr* attr = attributeVector[i]->attr())
1735 attr->normalize();
1736 }
1737 }
1738
1739 // ElementTraversal API
firstElementChild() const1740 Element* Element::firstElementChild() const
1741 {
1742 return WebCore::firstElementChild(this);
1743 }
1744
lastElementChild() const1745 Element* Element::lastElementChild() const
1746 {
1747 Node* n = lastChild();
1748 while (n && !n->isElementNode())
1749 n = n->previousSibling();
1750 return static_cast<Element*>(n);
1751 }
1752
previousElementSibling() const1753 Element* Element::previousElementSibling() const
1754 {
1755 Node* n = previousSibling();
1756 while (n && !n->isElementNode())
1757 n = n->previousSibling();
1758 return static_cast<Element*>(n);
1759 }
1760
nextElementSibling() const1761 Element* Element::nextElementSibling() const
1762 {
1763 Node* n = nextSibling();
1764 while (n && !n->isElementNode())
1765 n = n->nextSibling();
1766 return static_cast<Element*>(n);
1767 }
1768
childElementCount() const1769 unsigned Element::childElementCount() const
1770 {
1771 unsigned count = 0;
1772 Node* n = firstChild();
1773 while (n) {
1774 count += n->isElementNode();
1775 n = n->nextSibling();
1776 }
1777 return count;
1778 }
1779
webkitMatchesSelector(const String & selector,ExceptionCode & ec)1780 bool Element::webkitMatchesSelector(const String& selector, ExceptionCode& ec)
1781 {
1782 if (selector.isEmpty()) {
1783 ec = SYNTAX_ERR;
1784 return false;
1785 }
1786
1787 bool strictParsing = !document()->inQuirksMode();
1788 CSSParser p(strictParsing);
1789
1790 CSSSelectorList selectorList;
1791 p.parseSelector(selector, document(), selectorList);
1792
1793 if (!selectorList.first()) {
1794 ec = SYNTAX_ERR;
1795 return false;
1796 }
1797
1798 // Throw a NAMESPACE_ERR if the selector includes any namespace prefixes.
1799 if (selectorList.selectorsNeedNamespaceResolution()) {
1800 ec = NAMESPACE_ERR;
1801 return false;
1802 }
1803
1804 CSSStyleSelector::SelectorChecker selectorChecker(document(), strictParsing);
1805 for (CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
1806 if (selectorChecker.checkSelector(selector, this))
1807 return true;
1808 }
1809
1810 return false;
1811 }
1812
classList()1813 DOMTokenList* Element::classList()
1814 {
1815 ElementRareData* data = ensureRareData();
1816 if (!data->m_classList)
1817 data->m_classList = ClassList::create(this);
1818 return data->m_classList.get();
1819 }
1820
optionalClassList() const1821 DOMTokenList* Element::optionalClassList() const
1822 {
1823 if (!hasRareData())
1824 return 0;
1825 return rareData()->m_classList.get();
1826 }
1827
dataset()1828 DOMStringMap* Element::dataset()
1829 {
1830 ElementRareData* data = ensureRareData();
1831 if (!data->m_datasetDOMStringMap)
1832 data->m_datasetDOMStringMap = DatasetDOMStringMap::create(this);
1833 return data->m_datasetDOMStringMap.get();
1834 }
1835
optionalDataset() const1836 DOMStringMap* Element::optionalDataset() const
1837 {
1838 if (!hasRareData())
1839 return 0;
1840 return rareData()->m_datasetDOMStringMap.get();
1841 }
1842
getURLAttribute(const QualifiedName & name) const1843 KURL Element::getURLAttribute(const QualifiedName& name) const
1844 {
1845 #if !ASSERT_DISABLED
1846 if (m_attributeMap) {
1847 if (Attribute* attribute = m_attributeMap->getAttributeItem(name))
1848 ASSERT(isURLAttribute(attribute));
1849 }
1850 #endif
1851 return document()->completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
1852 }
1853
getNonEmptyURLAttribute(const QualifiedName & name) const1854 KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
1855 {
1856 #if !ASSERT_DISABLED
1857 if (m_attributeMap) {
1858 if (Attribute* attribute = m_attributeMap->getAttributeItem(name))
1859 ASSERT(isURLAttribute(attribute));
1860 }
1861 #endif
1862 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
1863 if (value.isEmpty())
1864 return KURL();
1865 return document()->completeURL(value);
1866 }
1867
getIntegralAttribute(const QualifiedName & attributeName) const1868 int Element::getIntegralAttribute(const QualifiedName& attributeName) const
1869 {
1870 return getAttribute(attributeName).string().toInt();
1871 }
1872
setIntegralAttribute(const QualifiedName & attributeName,int value)1873 void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
1874 {
1875 // FIXME: Need an AtomicString version of String::number.
1876 ExceptionCode ec;
1877 setAttribute(attributeName, String::number(value), ec);
1878 }
1879
getUnsignedIntegralAttribute(const QualifiedName & attributeName) const1880 unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
1881 {
1882 return getAttribute(attributeName).string().toUInt();
1883 }
1884
setUnsignedIntegralAttribute(const QualifiedName & attributeName,unsigned value)1885 void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
1886 {
1887 // FIXME: Need an AtomicString version of String::number.
1888 ExceptionCode ec;
1889 setAttribute(attributeName, String::number(value), ec);
1890 }
1891
1892 #if ENABLE(SVG)
childShouldCreateRenderer(Node * child) const1893 bool Element::childShouldCreateRenderer(Node* child) const
1894 {
1895 // Only create renderers for SVG elements whose parents are SVG elements, or for proper <svg xmlns="svgNS"> subdocuments.
1896 if (child->isSVGElement())
1897 return child->hasTagName(SVGNames::svgTag) || isSVGElement();
1898
1899 return Node::childShouldCreateRenderer(child);
1900 }
1901 #endif
1902
1903 #if ENABLE(FULLSCREEN_API)
webkitRequestFullScreen(unsigned short flags)1904 void Element::webkitRequestFullScreen(unsigned short flags)
1905 {
1906 document()->webkitRequestFullScreenForElement(this, flags);
1907 }
1908 #endif
1909
spellcheckAttributeState() const1910 SpellcheckAttributeState Element::spellcheckAttributeState() const
1911 {
1912 if (!hasAttribute(HTMLNames::spellcheckAttr))
1913 return SpellcheckAttributeDefault;
1914
1915 const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
1916 if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
1917 return SpellcheckAttributeTrue;
1918 if (equalIgnoringCase(value, "false"))
1919 return SpellcheckAttributeFalse;
1920
1921 return SpellcheckAttributeDefault;
1922 }
1923
isSpellCheckingEnabled() const1924 bool Element::isSpellCheckingEnabled() const
1925 {
1926 const Element* element = this;
1927 while (element) {
1928 switch (element->spellcheckAttributeState()) {
1929 case SpellcheckAttributeTrue:
1930 return true;
1931 case SpellcheckAttributeFalse:
1932 return false;
1933 case SpellcheckAttributeDefault:
1934 break;
1935 }
1936
1937 ContainerNode* parent = const_cast<Element*>(element)->parentOrHostNode();
1938 element = (parent && parent->isElementNode()) ? toElement(parent) : 0;
1939 }
1940
1941 return true;
1942 }
1943
webkitGetAnimations() const1944 PassRefPtr<WebKitAnimationList> Element::webkitGetAnimations() const
1945 {
1946 if (!renderer())
1947 return 0;
1948
1949 AnimationController* animController = renderer()->animation();
1950
1951 if (!animController)
1952 return 0;
1953
1954 return animController->animationsForRenderer(renderer());
1955 }
1956
1957 } // namespace WebCore
1958