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
recalcStyle(StyleChange change)1072 void Element::recalcStyle(StyleChange change)
1073 {
1074 // Ref currentStyle in case it would otherwise be deleted when setRenderStyle() is called.
1075 RefPtr<RenderStyle> currentStyle(renderStyle());
1076 bool hasParentStyle = parentNodeForRenderingAndStyle() ? parentNodeForRenderingAndStyle()->renderStyle() : false;
1077 bool hasDirectAdjacentRules = currentStyle && currentStyle->childrenAffectedByDirectAdjacentRules();
1078
1079 if ((change > NoChange || needsStyleRecalc())) {
1080 if (hasRareData())
1081 rareData()->resetComputedStyle();
1082 }
1083 if (hasParentStyle && (change >= Inherit || needsStyleRecalc())) {
1084 RefPtr<RenderStyle> newStyle = document()->styleSelector()->styleForElement(this);
1085 StyleChange ch = diff(currentStyle.get(), newStyle.get());
1086 if (ch == Detach || !currentStyle) {
1087 if (attached())
1088 detach();
1089 attach(); // FIXME: The style gets computed twice by calling attach. We could do better if we passed the style along.
1090 // attach recalulates the style for all children. No need to do it twice.
1091 clearNeedsStyleRecalc();
1092 clearChildNeedsStyleRecalc();
1093 return;
1094 }
1095
1096 if (currentStyle) {
1097 // Preserve "affected by" bits that were propagated to us from descendants in the case where we didn't do a full
1098 // style change (e.g., only inline style changed).
1099 if (currentStyle->affectedByHoverRules())
1100 newStyle->setAffectedByHoverRules(true);
1101 if (currentStyle->affectedByActiveRules())
1102 newStyle->setAffectedByActiveRules(true);
1103 if (currentStyle->affectedByDragRules())
1104 newStyle->setAffectedByDragRules(true);
1105 if (currentStyle->childrenAffectedByForwardPositionalRules())
1106 newStyle->setChildrenAffectedByForwardPositionalRules();
1107 if (currentStyle->childrenAffectedByBackwardPositionalRules())
1108 newStyle->setChildrenAffectedByBackwardPositionalRules();
1109 if (currentStyle->childrenAffectedByFirstChildRules())
1110 newStyle->setChildrenAffectedByFirstChildRules();
1111 if (currentStyle->childrenAffectedByLastChildRules())
1112 newStyle->setChildrenAffectedByLastChildRules();
1113 if (currentStyle->childrenAffectedByDirectAdjacentRules())
1114 newStyle->setChildrenAffectedByDirectAdjacentRules();
1115 }
1116
1117 if (ch != NoChange || pseudoStyleCacheIsInvalid(currentStyle.get(), newStyle.get()) || (change == Force && renderer() && renderer()->requiresForcedStyleRecalcPropagation())) {
1118 setRenderStyle(newStyle);
1119 } else if (needsStyleRecalc() && styleChangeType() != SyntheticStyleChange) {
1120 // Although no change occurred, we use the new style so that the cousin style sharing code won't get
1121 // fooled into believing this style is the same.
1122 if (renderer())
1123 renderer()->setStyleInternal(newStyle.get());
1124 else
1125 setRenderStyle(newStyle);
1126 } else if (styleChangeType() == SyntheticStyleChange)
1127 setRenderStyle(newStyle);
1128
1129 if (change != Force) {
1130 // 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
1131 // 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).
1132 if (document()->usesRemUnits() && ch != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize() && document()->documentElement() == this)
1133 change = Force;
1134 else if (styleChangeType() >= FullStyleChange)
1135 change = Force;
1136 else
1137 change = ch;
1138 }
1139 }
1140 StyleSelectorParentPusher parentPusher(this);
1141 // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
1142 // For now we will just worry about the common case, since it's a lot trickier to get the second case right
1143 // without doing way too much re-resolution.
1144 bool forceCheckOfNextElementSibling = false;
1145 for (Node *n = firstChild(); n; n = n->nextSibling()) {
1146 bool childRulesChanged = n->needsStyleRecalc() && n->styleChangeType() == FullStyleChange;
1147 if (forceCheckOfNextElementSibling && n->isElementNode())
1148 n->setNeedsStyleRecalc();
1149 if (change >= Inherit || n->isTextNode() || n->childNeedsStyleRecalc() || n->needsStyleRecalc()) {
1150 parentPusher.push();
1151 n->recalcStyle(change);
1152 }
1153 if (n->isElementNode())
1154 forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
1155 }
1156 // FIXME: This does not care about sibling combinators. Will be necessary in XBL2 world.
1157 if (Node* shadow = shadowRoot()) {
1158 if (change >= Inherit || shadow->childNeedsStyleRecalc() || shadow->needsStyleRecalc()) {
1159 parentPusher.push();
1160 shadow->recalcStyle(change);
1161 }
1162 }
1163
1164 clearNeedsStyleRecalc();
1165 clearChildNeedsStyleRecalc();
1166 }
1167
shadowRoot() const1168 ContainerNode* Element::shadowRoot() const
1169 {
1170 return hasRareData() ? rareData()->m_shadowRoot : 0;
1171 }
1172
ensureShadowRoot()1173 ContainerNode* Element::ensureShadowRoot()
1174 {
1175 if (ContainerNode* existingRoot = shadowRoot())
1176 return existingRoot;
1177
1178 RefPtr<ShadowRoot> newRoot = ShadowRoot::create(document());
1179 ensureRareData()->m_shadowRoot = newRoot.get();
1180 newRoot->setShadowHost(this);
1181 if (inDocument())
1182 newRoot->insertedIntoDocument();
1183 if (attached())
1184 newRoot->lazyAttach();
1185 return newRoot.get();
1186 }
1187
removeShadowRoot()1188 void Element::removeShadowRoot()
1189 {
1190 if (!hasRareData())
1191 return;
1192
1193 ElementRareData* data = rareData();
1194 if (RefPtr<Node> oldRoot = data->m_shadowRoot) {
1195 data->m_shadowRoot = 0;
1196 document()->removeFocusedNodeOfSubtree(oldRoot.get());
1197 oldRoot->setShadowHost(0);
1198 if (oldRoot->inDocument())
1199 oldRoot->removedFromDocument();
1200 else
1201 oldRoot->removedFromTree(true);
1202 }
1203 }
1204
childTypeAllowed(NodeType type) const1205 bool Element::childTypeAllowed(NodeType type) const
1206 {
1207 switch (type) {
1208 case ELEMENT_NODE:
1209 case TEXT_NODE:
1210 case COMMENT_NODE:
1211 case PROCESSING_INSTRUCTION_NODE:
1212 case CDATA_SECTION_NODE:
1213 case ENTITY_REFERENCE_NODE:
1214 return true;
1215 default:
1216 break;
1217 }
1218 return false;
1219 }
1220
checkForEmptyStyleChange(Element * element,RenderStyle * style)1221 static void checkForEmptyStyleChange(Element* element, RenderStyle* style)
1222 {
1223 if (!style)
1224 return;
1225
1226 if (style->affectedByEmpty() && (!style->emptyState() || element->hasChildNodes()))
1227 element->setNeedsStyleRecalc();
1228 }
1229
checkForSiblingStyleChanges(Element * e,RenderStyle * style,bool finishedParsingCallback,Node * beforeChange,Node * afterChange,int childCountDelta)1230 static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
1231 Node* beforeChange, Node* afterChange, int childCountDelta)
1232 {
1233 if (!style || (e->needsStyleRecalc() && style->childrenAffectedByPositionalRules()))
1234 return;
1235
1236 // :first-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1237 // In the DOM case, we only need to do something if |afterChange| is not 0.
1238 // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
1239 if (style->childrenAffectedByFirstChildRules() && afterChange) {
1240 // Find our new first child.
1241 Node* newFirstChild = 0;
1242 for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {};
1243
1244 // Find the first element node following |afterChange|
1245 Node* firstElementAfterInsertion = 0;
1246 for (firstElementAfterInsertion = afterChange;
1247 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
1248 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
1249
1250 // This is the insert/append case.
1251 if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertion && firstElementAfterInsertion->attached() &&
1252 firstElementAfterInsertion->renderStyle() && firstElementAfterInsertion->renderStyle()->firstChildState())
1253 firstElementAfterInsertion->setNeedsStyleRecalc();
1254
1255 // We also have to handle node removal.
1256 if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && newFirstChild->renderStyle() && !newFirstChild->renderStyle()->firstChildState())
1257 newFirstChild->setNeedsStyleRecalc();
1258 }
1259
1260 // :last-child. In the parser callback case, we don't have to check anything, since we were right the first time.
1261 // In the DOM case, we only need to do something if |afterChange| is not 0.
1262 if (style->childrenAffectedByLastChildRules() && beforeChange) {
1263 // Find our new last child.
1264 Node* newLastChild = 0;
1265 for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {};
1266
1267 // Find the last element node going backwards from |beforeChange|
1268 Node* lastElementBeforeInsertion = 0;
1269 for (lastElementBeforeInsertion = beforeChange;
1270 lastElementBeforeInsertion && !lastElementBeforeInsertion->isElementNode();
1271 lastElementBeforeInsertion = lastElementBeforeInsertion->previousSibling()) {};
1272
1273 if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertion && lastElementBeforeInsertion->attached() &&
1274 lastElementBeforeInsertion->renderStyle() && lastElementBeforeInsertion->renderStyle()->lastChildState())
1275 lastElementBeforeInsertion->setNeedsStyleRecalc();
1276
1277 // 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
1278 // to match now.
1279 if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && newLastChild->renderStyle() && !newLastChild->renderStyle()->lastChildState())
1280 newLastChild->setNeedsStyleRecalc();
1281 }
1282
1283 // The + selector. We need to invalidate the first element following the insertion point. It is the only possible element
1284 // that could be affected by this DOM change.
1285 if (style->childrenAffectedByDirectAdjacentRules() && afterChange) {
1286 Node* firstElementAfterInsertion = 0;
1287 for (firstElementAfterInsertion = afterChange;
1288 firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
1289 firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
1290 if (firstElementAfterInsertion && firstElementAfterInsertion->attached())
1291 firstElementAfterInsertion->setNeedsStyleRecalc();
1292 }
1293
1294 // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
1295 // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
1296 // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
1297 // backward case.
1298 // |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.
1299 // 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
1300 // here. recalcStyle will then force a walk of the children when it sees that this has happened.
1301 if ((style->childrenAffectedByForwardPositionalRules() && afterChange) ||
1302 (style->childrenAffectedByBackwardPositionalRules() && beforeChange))
1303 e->setNeedsStyleRecalc();
1304
1305 // :empty selector.
1306 checkForEmptyStyleChange(e, style);
1307 }
1308
childrenChanged(bool changedByParser,Node * beforeChange,Node * afterChange,int childCountDelta)1309 void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
1310 {
1311 ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
1312 if (changedByParser)
1313 checkForEmptyStyleChange(this, renderStyle());
1314 else
1315 checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
1316 }
1317
beginParsingChildren()1318 void Element::beginParsingChildren()
1319 {
1320 clearIsParsingChildrenFinished();
1321 CSSStyleSelector* styleSelector = document()->styleSelectorIfExists();
1322 if (styleSelector && attached())
1323 styleSelector->pushParent(this);
1324 }
1325
finishParsingChildren()1326 void Element::finishParsingChildren()
1327 {
1328 ContainerNode::finishParsingChildren();
1329 setIsParsingChildrenFinished();
1330 checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
1331 if (CSSStyleSelector* styleSelector = document()->styleSelectorIfExists())
1332 styleSelector->popParent(this);
1333 }
1334
dispatchAttrRemovalEvent(Attribute *)1335 void Element::dispatchAttrRemovalEvent(Attribute*)
1336 {
1337 ASSERT(!eventDispatchForbidden());
1338
1339 #if 0
1340 if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER))
1341 return;
1342 ExceptionCode ec = 0;
1343 dispatchScopedEvent(MutationEvent::create(DOMAttrModifiedEvent, true, attr, attr->value(),
1344 attr->value(), document()->attrName(attr->id()), MutationEvent::REMOVAL), ec);
1345 #endif
1346 }
1347
dispatchAttrAdditionEvent(Attribute *)1348 void Element::dispatchAttrAdditionEvent(Attribute*)
1349 {
1350 ASSERT(!eventDispatchForbidden());
1351
1352 #if 0
1353 if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER))
1354 return;
1355 ExceptionCode ec = 0;
1356 dispatchScopedEvent(MutationEvent::create(DOMAttrModifiedEvent, true, attr, attr->value(),
1357 attr->value(), document()->attrName(attr->id()), MutationEvent::ADDITION), ec);
1358 #endif
1359 }
1360
openTagStartToString() const1361 String Element::openTagStartToString() const
1362 {
1363 String result = "<" + nodeName();
1364
1365 NamedNodeMap* attrMap = attributes(true);
1366
1367 if (attrMap) {
1368 unsigned numAttrs = attrMap->length();
1369 for (unsigned i = 0; i < numAttrs; i++) {
1370 result += " ";
1371
1372 Attribute *attribute = attrMap->attributeItem(i);
1373 result += attribute->name().toString();
1374 if (!attribute->value().isNull()) {
1375 result += "=\"";
1376 // FIXME: substitute entities for any instances of " or '
1377 result += attribute->value();
1378 result += "\"";
1379 }
1380 }
1381 }
1382
1383 return result;
1384 }
1385
1386 #ifndef NDEBUG
formatForDebugger(char * buffer,unsigned length) const1387 void Element::formatForDebugger(char* buffer, unsigned length) const
1388 {
1389 String result;
1390 String s;
1391
1392 s = nodeName();
1393 if (s.length() > 0) {
1394 result += s;
1395 }
1396
1397 s = getIdAttribute();
1398 if (s.length() > 0) {
1399 if (result.length() > 0)
1400 result += "; ";
1401 result += "id=";
1402 result += s;
1403 }
1404
1405 s = getAttribute(classAttr);
1406 if (s.length() > 0) {
1407 if (result.length() > 0)
1408 result += "; ";
1409 result += "class=";
1410 result += s;
1411 }
1412
1413 strncpy(buffer, result.utf8().data(), length - 1);
1414 }
1415 #endif
1416
setAttributeNode(Attr * attr,ExceptionCode & ec)1417 PassRefPtr<Attr> Element::setAttributeNode(Attr* attr, ExceptionCode& ec)
1418 {
1419 if (!attr) {
1420 ec = TYPE_MISMATCH_ERR;
1421 return 0;
1422 }
1423 return static_pointer_cast<Attr>(attributes(false)->setNamedItem(attr, ec));
1424 }
1425
setAttributeNodeNS(Attr * attr,ExceptionCode & ec)1426 PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionCode& ec)
1427 {
1428 if (!attr) {
1429 ec = TYPE_MISMATCH_ERR;
1430 return 0;
1431 }
1432 return static_pointer_cast<Attr>(attributes(false)->setNamedItem(attr, ec));
1433 }
1434
removeAttributeNode(Attr * attr,ExceptionCode & ec)1435 PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec)
1436 {
1437 if (!attr) {
1438 ec = TYPE_MISMATCH_ERR;
1439 return 0;
1440 }
1441 if (attr->ownerElement() != this) {
1442 ec = NOT_FOUND_ERR;
1443 return 0;
1444 }
1445
1446 ASSERT(document() == attr->document());
1447
1448 NamedNodeMap* attrs = attributes(true);
1449 if (!attrs)
1450 return 0;
1451
1452 return static_pointer_cast<Attr>(attrs->removeNamedItem(attr->qualifiedName(), ec));
1453 }
1454
setAttributeNS(const AtomicString & namespaceURI,const AtomicString & qualifiedName,const AtomicString & value,ExceptionCode & ec,FragmentScriptingPermission scriptingPermission)1455 void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode& ec, FragmentScriptingPermission scriptingPermission)
1456 {
1457 String prefix, localName;
1458 if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec))
1459 return;
1460
1461 if (namespaceURI.isNull() && !prefix.isNull()) {
1462 ec = NAMESPACE_ERR;
1463 return;
1464 }
1465
1466 QualifiedName qName(prefix, localName, namespaceURI);
1467
1468 if (scriptingPermission == FragmentScriptingNotAllowed && (isEventHandlerAttribute(qName) || isAttributeToRemove(qName, value)))
1469 return;
1470
1471 setAttribute(qName, value, ec);
1472 }
1473
removeAttribute(const String & name,ExceptionCode & ec)1474 void Element::removeAttribute(const String& name, ExceptionCode& ec)
1475 {
1476 InspectorInstrumentation::willModifyDOMAttr(document(), this);
1477
1478 String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1479
1480 if (m_attributeMap) {
1481 m_attributeMap->removeNamedItem(localName, ec);
1482 if (ec == NOT_FOUND_ERR)
1483 ec = 0;
1484 }
1485
1486 InspectorInstrumentation::didModifyDOMAttr(document(), this);
1487 }
1488
removeAttributeNS(const String & namespaceURI,const String & localName,ExceptionCode & ec)1489 void Element::removeAttributeNS(const String& namespaceURI, const String& localName, ExceptionCode& ec)
1490 {
1491 removeAttribute(QualifiedName(nullAtom, localName, namespaceURI), ec);
1492 }
1493
getAttributeNode(const String & name)1494 PassRefPtr<Attr> Element::getAttributeNode(const String& name)
1495 {
1496 NamedNodeMap* attrs = attributes(true);
1497 if (!attrs)
1498 return 0;
1499 String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1500 return static_pointer_cast<Attr>(attrs->getNamedItem(localName));
1501 }
1502
getAttributeNodeNS(const String & namespaceURI,const String & localName)1503 PassRefPtr<Attr> Element::getAttributeNodeNS(const String& namespaceURI, const String& localName)
1504 {
1505 NamedNodeMap* attrs = attributes(true);
1506 if (!attrs)
1507 return 0;
1508 return static_pointer_cast<Attr>(attrs->getNamedItem(QualifiedName(nullAtom, localName, namespaceURI)));
1509 }
1510
hasAttribute(const String & name) const1511 bool Element::hasAttribute(const String& name) const
1512 {
1513 NamedNodeMap* attrs = attributes(true);
1514 if (!attrs)
1515 return false;
1516
1517 // This call to String::lower() seems to be required but
1518 // there may be a way to remove it.
1519 String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1520 return attrs->getAttributeItem(localName, false);
1521 }
1522
hasAttributeNS(const String & namespaceURI,const String & localName) const1523 bool Element::hasAttributeNS(const String& namespaceURI, const String& localName) const
1524 {
1525 NamedNodeMap* attrs = attributes(true);
1526 if (!attrs)
1527 return false;
1528 return attrs->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI));
1529 }
1530
style()1531 CSSStyleDeclaration *Element::style()
1532 {
1533 return 0;
1534 }
1535
focus(bool restorePreviousSelection)1536 void Element::focus(bool restorePreviousSelection)
1537 {
1538 if (!inDocument())
1539 return;
1540
1541 Document* doc = document();
1542 if (doc->focusedNode() == this)
1543 return;
1544
1545 // If the stylesheets have already been loaded we can reliably check isFocusable.
1546 // If not, we continue and set the focused node on the focus controller below so
1547 // that it can be updated soon after attach.
1548 if (doc->haveStylesheetsLoaded()) {
1549 doc->updateLayoutIgnorePendingStylesheets();
1550 if (!isFocusable())
1551 return;
1552 }
1553
1554 if (!supportsFocus())
1555 return;
1556
1557 RefPtr<Node> protect;
1558 if (Page* page = doc->page()) {
1559 // Focus and change event handlers can cause us to lose our last ref.
1560 // If a focus event handler changes the focus to a different node it
1561 // does not make sense to continue and update appearence.
1562 protect = this;
1563 if (!page->focusController()->setFocusedNode(this, doc->frame()))
1564 return;
1565 }
1566
1567 // Setting the focused node above might have invalidated the layout due to scripts.
1568 doc->updateLayoutIgnorePendingStylesheets();
1569
1570 if (!isFocusable()) {
1571 ensureRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
1572 return;
1573 }
1574
1575 cancelFocusAppearanceUpdate();
1576 updateFocusAppearance(restorePreviousSelection);
1577 }
1578
updateFocusAppearance(bool)1579 void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
1580 {
1581 if (this == rootEditableElement()) {
1582 Frame* frame = document()->frame();
1583 if (!frame)
1584 return;
1585
1586 // When focusing an editable element in an iframe, don't reset the selection if it already contains a selection.
1587 if (this == frame->selection()->rootEditableElement())
1588 return;
1589
1590 // FIXME: We should restore the previous selection if there is one.
1591 VisibleSelection newSelection = VisibleSelection(firstPositionInOrBeforeNode(this), DOWNSTREAM);
1592
1593 if (frame->selection()->shouldChangeSelection(newSelection)) {
1594 frame->selection()->setSelection(newSelection);
1595 frame->selection()->revealSelection();
1596 }
1597 } else if (renderer() && !renderer()->isWidget())
1598 renderer()->enclosingLayer()->scrollRectToVisible(getRect());
1599 }
1600
blur()1601 void Element::blur()
1602 {
1603 cancelFocusAppearanceUpdate();
1604 Document* doc = document();
1605 if (doc->focusedNode() == this) {
1606 if (doc->frame())
1607 doc->frame()->page()->focusController()->setFocusedNode(0, doc->frame());
1608 else
1609 doc->setFocusedNode(0);
1610 }
1611 }
1612
innerText() const1613 String Element::innerText() const
1614 {
1615 // We need to update layout, since plainText uses line boxes in the render tree.
1616 document()->updateLayoutIgnorePendingStylesheets();
1617
1618 if (!renderer())
1619 return textContent(true);
1620
1621 return plainText(rangeOfContents(const_cast<Element*>(this)).get());
1622 }
1623
outerText() const1624 String Element::outerText() const
1625 {
1626 // Getting outerText is the same as getting innerText, only
1627 // setting is different. You would think this should get the plain
1628 // text for the outer range, but this is wrong, <br> for instance
1629 // would return different values for inner and outer text by such
1630 // a rule, but it doesn't in WinIE, and we want to match that.
1631 return innerText();
1632 }
1633
title() const1634 String Element::title() const
1635 {
1636 return String();
1637 }
1638
minimumSizeForResizing() const1639 IntSize Element::minimumSizeForResizing() const
1640 {
1641 return hasRareData() ? rareData()->m_minimumSizeForResizing : defaultMinimumSizeForResizing();
1642 }
1643
setMinimumSizeForResizing(const IntSize & size)1644 void Element::setMinimumSizeForResizing(const IntSize& size)
1645 {
1646 if (size == defaultMinimumSizeForResizing() && !hasRareData())
1647 return;
1648 ensureRareData()->m_minimumSizeForResizing = size;
1649 }
1650
computedStyle(PseudoId pseudoElementSpecifier)1651 RenderStyle* Element::computedStyle(PseudoId pseudoElementSpecifier)
1652 {
1653 // FIXME: Find and use the renderer from the pseudo element instead of the actual element so that the 'length'
1654 // properties, which are only known by the renderer because it did the layout, will be correct and so that the
1655 // values returned for the ":selection" pseudo-element will be correct.
1656 if (RenderStyle* usedStyle = renderStyle())
1657 return pseudoElementSpecifier ? usedStyle->getCachedPseudoStyle(pseudoElementSpecifier) : usedStyle;
1658
1659 if (!attached())
1660 // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
1661 // document tree and figure out when to destroy the computed style for such elements.
1662 return 0;
1663
1664 ElementRareData* data = ensureRareData();
1665 if (!data->m_computedStyle)
1666 data->m_computedStyle = document()->styleForElementIgnoringPendingStylesheets(this);
1667 return pseudoElementSpecifier ? data->m_computedStyle->getCachedPseudoStyle(pseudoElementSpecifier) : data->m_computedStyle.get();
1668 }
1669
computeInheritedLanguage() const1670 AtomicString Element::computeInheritedLanguage() const
1671 {
1672 const Node* n = this;
1673 AtomicString value;
1674 // The language property is inherited, so we iterate over the parents to find the first language.
1675 while (n && value.isNull()) {
1676 if (n->isElementNode()) {
1677 // Spec: xml:lang takes precedence -- http://www.w3.org/TR/xhtml1/#C_7
1678 value = static_cast<const Element*>(n)->fastGetAttribute(XMLNames::langAttr);
1679 if (value.isNull())
1680 value = static_cast<const Element*>(n)->fastGetAttribute(HTMLNames::langAttr);
1681 } else if (n->isDocumentNode()) {
1682 // checking the MIME content-language
1683 value = static_cast<const Document*>(n)->contentLanguage();
1684 }
1685
1686 n = n->parentNode();
1687 }
1688
1689 return value;
1690 }
1691
cancelFocusAppearanceUpdate()1692 void Element::cancelFocusAppearanceUpdate()
1693 {
1694 if (hasRareData())
1695 rareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1696 if (document()->focusedNode() == this)
1697 document()->cancelFocusAppearanceUpdate();
1698 }
1699
normalizeAttributes()1700 void Element::normalizeAttributes()
1701 {
1702 // Normalize attributes.
1703 NamedNodeMap* attrs = attributes(true);
1704 if (!attrs)
1705 return;
1706
1707 if (attrs->isEmpty())
1708 return;
1709
1710 Vector<RefPtr<Attribute> > attributeVector;
1711 attrs->copyAttributesToVector(attributeVector);
1712 size_t numAttrs = attributeVector.size();
1713 for (size_t i = 0; i < numAttrs; ++i) {
1714 if (Attr* attr = attributeVector[i]->attr())
1715 attr->normalize();
1716 }
1717 }
1718
1719 // ElementTraversal API
firstElementChild() const1720 Element* Element::firstElementChild() const
1721 {
1722 return WebCore::firstElementChild(this);
1723 }
1724
lastElementChild() const1725 Element* Element::lastElementChild() const
1726 {
1727 Node* n = lastChild();
1728 while (n && !n->isElementNode())
1729 n = n->previousSibling();
1730 return static_cast<Element*>(n);
1731 }
1732
previousElementSibling() const1733 Element* Element::previousElementSibling() const
1734 {
1735 Node* n = previousSibling();
1736 while (n && !n->isElementNode())
1737 n = n->previousSibling();
1738 return static_cast<Element*>(n);
1739 }
1740
nextElementSibling() const1741 Element* Element::nextElementSibling() const
1742 {
1743 Node* n = nextSibling();
1744 while (n && !n->isElementNode())
1745 n = n->nextSibling();
1746 return static_cast<Element*>(n);
1747 }
1748
childElementCount() const1749 unsigned Element::childElementCount() const
1750 {
1751 unsigned count = 0;
1752 Node* n = firstChild();
1753 while (n) {
1754 count += n->isElementNode();
1755 n = n->nextSibling();
1756 }
1757 return count;
1758 }
1759
webkitMatchesSelector(const String & selector,ExceptionCode & ec)1760 bool Element::webkitMatchesSelector(const String& selector, ExceptionCode& ec)
1761 {
1762 if (selector.isEmpty()) {
1763 ec = SYNTAX_ERR;
1764 return false;
1765 }
1766
1767 bool strictParsing = !document()->inQuirksMode();
1768 CSSParser p(strictParsing);
1769
1770 CSSSelectorList selectorList;
1771 p.parseSelector(selector, document(), selectorList);
1772
1773 if (!selectorList.first()) {
1774 ec = SYNTAX_ERR;
1775 return false;
1776 }
1777
1778 // Throw a NAMESPACE_ERR if the selector includes any namespace prefixes.
1779 if (selectorList.selectorsNeedNamespaceResolution()) {
1780 ec = NAMESPACE_ERR;
1781 return false;
1782 }
1783
1784 CSSStyleSelector::SelectorChecker selectorChecker(document(), strictParsing);
1785 for (CSSSelector* selector = selectorList.first(); selector; selector = CSSSelectorList::next(selector)) {
1786 if (selectorChecker.checkSelector(selector, this))
1787 return true;
1788 }
1789
1790 return false;
1791 }
1792
classList()1793 DOMTokenList* Element::classList()
1794 {
1795 ElementRareData* data = ensureRareData();
1796 if (!data->m_classList)
1797 data->m_classList = ClassList::create(this);
1798 return data->m_classList.get();
1799 }
1800
optionalClassList() const1801 DOMTokenList* Element::optionalClassList() const
1802 {
1803 if (!hasRareData())
1804 return 0;
1805 return rareData()->m_classList.get();
1806 }
1807
dataset()1808 DOMStringMap* Element::dataset()
1809 {
1810 ElementRareData* data = ensureRareData();
1811 if (!data->m_datasetDOMStringMap)
1812 data->m_datasetDOMStringMap = DatasetDOMStringMap::create(this);
1813 return data->m_datasetDOMStringMap.get();
1814 }
1815
optionalDataset() const1816 DOMStringMap* Element::optionalDataset() const
1817 {
1818 if (!hasRareData())
1819 return 0;
1820 return rareData()->m_datasetDOMStringMap.get();
1821 }
1822
getURLAttribute(const QualifiedName & name) const1823 KURL Element::getURLAttribute(const QualifiedName& name) const
1824 {
1825 #if !ASSERT_DISABLED
1826 if (m_attributeMap) {
1827 if (Attribute* attribute = m_attributeMap->getAttributeItem(name))
1828 ASSERT(isURLAttribute(attribute));
1829 }
1830 #endif
1831 return document()->completeURL(stripLeadingAndTrailingHTMLSpaces(getAttribute(name)));
1832 }
1833
getNonEmptyURLAttribute(const QualifiedName & name) const1834 KURL Element::getNonEmptyURLAttribute(const QualifiedName& name) const
1835 {
1836 #if !ASSERT_DISABLED
1837 if (m_attributeMap) {
1838 if (Attribute* attribute = m_attributeMap->getAttributeItem(name))
1839 ASSERT(isURLAttribute(attribute));
1840 }
1841 #endif
1842 String value = stripLeadingAndTrailingHTMLSpaces(getAttribute(name));
1843 if (value.isEmpty())
1844 return KURL();
1845 return document()->completeURL(value);
1846 }
1847
getIntegralAttribute(const QualifiedName & attributeName) const1848 int Element::getIntegralAttribute(const QualifiedName& attributeName) const
1849 {
1850 return getAttribute(attributeName).string().toInt();
1851 }
1852
setIntegralAttribute(const QualifiedName & attributeName,int value)1853 void Element::setIntegralAttribute(const QualifiedName& attributeName, int value)
1854 {
1855 // FIXME: Need an AtomicString version of String::number.
1856 ExceptionCode ec;
1857 setAttribute(attributeName, String::number(value), ec);
1858 }
1859
getUnsignedIntegralAttribute(const QualifiedName & attributeName) const1860 unsigned Element::getUnsignedIntegralAttribute(const QualifiedName& attributeName) const
1861 {
1862 return getAttribute(attributeName).string().toUInt();
1863 }
1864
setUnsignedIntegralAttribute(const QualifiedName & attributeName,unsigned value)1865 void Element::setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value)
1866 {
1867 // FIXME: Need an AtomicString version of String::number.
1868 ExceptionCode ec;
1869 setAttribute(attributeName, String::number(value), ec);
1870 }
1871
1872 #if ENABLE(SVG)
childShouldCreateRenderer(Node * child) const1873 bool Element::childShouldCreateRenderer(Node* child) const
1874 {
1875 // Only create renderers for SVG elements whose parents are SVG elements, or for proper <svg xmlns="svgNS"> subdocuments.
1876 if (child->isSVGElement())
1877 return child->hasTagName(SVGNames::svgTag) || isSVGElement();
1878
1879 return Node::childShouldCreateRenderer(child);
1880 }
1881 #endif
1882
1883 #if ENABLE(FULLSCREEN_API)
webkitRequestFullScreen(unsigned short flags)1884 void Element::webkitRequestFullScreen(unsigned short flags)
1885 {
1886 document()->webkitRequestFullScreenForElement(this, flags);
1887 }
1888 #endif
1889
spellcheckAttributeState() const1890 SpellcheckAttributeState Element::spellcheckAttributeState() const
1891 {
1892 if (!hasAttribute(HTMLNames::spellcheckAttr))
1893 return SpellcheckAttributeDefault;
1894
1895 const AtomicString& value = getAttribute(HTMLNames::spellcheckAttr);
1896 if (equalIgnoringCase(value, "true") || equalIgnoringCase(value, ""))
1897 return SpellcheckAttributeTrue;
1898 if (equalIgnoringCase(value, "false"))
1899 return SpellcheckAttributeFalse;
1900
1901 return SpellcheckAttributeDefault;
1902 }
1903
isSpellCheckingEnabled() const1904 bool Element::isSpellCheckingEnabled() const
1905 {
1906 const Element* element = this;
1907 while (element) {
1908 switch (element->spellcheckAttributeState()) {
1909 case SpellcheckAttributeTrue:
1910 return true;
1911 case SpellcheckAttributeFalse:
1912 return false;
1913 case SpellcheckAttributeDefault:
1914 break;
1915 }
1916
1917 ContainerNode* parent = const_cast<Element*>(element)->parentOrHostNode();
1918 element = (parent && parent->isElementNode()) ? toElement(parent) : 0;
1919 }
1920
1921 return true;
1922 }
1923
webkitGetAnimations() const1924 PassRefPtr<WebKitAnimationList> Element::webkitGetAnimations() const
1925 {
1926 if (!renderer())
1927 return 0;
1928
1929 AnimationController* animController = renderer()->animation();
1930
1931 if (!animController)
1932 return 0;
1933
1934 return animController->animationsForRenderer(renderer());
1935 }
1936
1937 } // namespace WebCore
1938