• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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 "CSSStyleSelector.h"
32 #include "CString.h"
33 #include "ClientRect.h"
34 #include "ClientRectList.h"
35 #include "Document.h"
36 #include "ElementRareData.h"
37 #include "ExceptionCode.h"
38 #include "FocusController.h"
39 #include "Frame.h"
40 #include "FrameView.h"
41 #include "HTMLElement.h"
42 #include "HTMLNames.h"
43 #include "NamedNodeMap.h"
44 #include "NodeList.h"
45 #include "NodeRenderStyle.h"
46 #include "Page.h"
47 #include "RenderView.h"
48 #include "TextIterator.h"
49 #include "XMLNames.h"
50 
51 #if ENABLE(SVG)
52 #include "SVGNames.h"
53 #endif
54 
55 namespace WebCore {
56 
57 using namespace HTMLNames;
58 using namespace XMLNames;
59 
Element(const QualifiedName & tagName,Document * doc)60 Element::Element(const QualifiedName& tagName, Document* doc)
61     : ContainerNode(doc, true)
62     , m_tagName(tagName)
63 {
64 }
65 
~Element()66 Element::~Element()
67 {
68     if (namedAttrMap)
69         namedAttrMap->detachFromElement();
70 }
71 
rareData() const72 inline ElementRareData* Element::rareData() const
73 {
74     ASSERT(hasRareData());
75     return static_cast<ElementRareData*>(NodeRareData::rareDataFromMap(this));
76 }
77 
ensureRareData()78 inline ElementRareData* Element::ensureRareData()
79 {
80     return static_cast<ElementRareData*>(Node::ensureRareData());
81 }
82 
createRareData()83 NodeRareData* Element::createRareData()
84 {
85     return new ElementRareData;
86 }
87 
cloneNode(bool deep)88 PassRefPtr<Node> Element::cloneNode(bool deep)
89 {
90     return deep ? cloneElementWithChildren() : cloneElementWithoutChildren();
91 }
92 
cloneElementWithChildren()93 PassRefPtr<Element> Element::cloneElementWithChildren()
94 {
95     RefPtr<Element> clone = cloneElementWithoutChildren();
96     cloneChildNodes(clone.get());
97     return clone.release();
98 }
99 
cloneElementWithoutChildren()100 PassRefPtr<Element> Element::cloneElementWithoutChildren()
101 {
102     RefPtr<Element> clone = document()->createElement(tagQName(), false);
103     // This will catch HTML elements in the wrong namespace that are not correctly copied.
104     // This is a sanity check as HTML overloads some of the DOM methods.
105     ASSERT(isHTMLElement() == clone->isHTMLElement());
106 
107     // Clone attributes.
108     if (namedAttrMap)
109         clone->attributes()->setAttributes(*attributes(true)); // Call attributes(true) to force attribute synchronization to occur (for svg and style) before cloning happens.
110 
111     clone->copyNonAttributeProperties(this);
112 
113     return clone.release();
114 }
115 
removeAttribute(const QualifiedName & name,ExceptionCode & ec)116 void Element::removeAttribute(const QualifiedName& name, ExceptionCode& ec)
117 {
118     if (namedAttrMap) {
119         namedAttrMap->removeNamedItem(name, ec);
120         if (ec == NOT_FOUND_ERR)
121             ec = 0;
122     }
123 }
124 
setAttribute(const QualifiedName & name,const AtomicString & value)125 void Element::setAttribute(const QualifiedName& name, const AtomicString& value)
126 {
127     ExceptionCode ec;
128     setAttribute(name, value, ec);
129 }
130 
setBooleanAttribute(const QualifiedName & name,bool b)131 void Element::setBooleanAttribute(const QualifiedName& name, bool b)
132 {
133     if (b)
134         setAttribute(name, name.localName());
135     else {
136         ExceptionCode ex;
137         removeAttribute(name, ex);
138     }
139 }
140 
141 // Virtual function, defined in base class.
attributes() const142 NamedNodeMap* Element::attributes() const
143 {
144     return attributes(false);
145 }
146 
attributes(bool readonly) const147 NamedNodeMap* Element::attributes(bool readonly) const
148 {
149     if (!m_isStyleAttributeValid)
150         updateStyleAttribute();
151 
152 #if ENABLE(SVG)
153     if (!m_areSVGAttributesValid)
154         updateAnimatedSVGAttribute(String());
155 #endif
156 
157     if (!readonly && !namedAttrMap)
158         createAttributeMap();
159     return namedAttrMap.get();
160 }
161 
nodeType() const162 Node::NodeType Element::nodeType() const
163 {
164     return ELEMENT_NODE;
165 }
166 
getIDAttribute() const167 const AtomicString& Element::getIDAttribute() const
168 {
169     return namedAttrMap ? namedAttrMap->id() : nullAtom;
170 }
171 
hasAttribute(const QualifiedName & name) const172 bool Element::hasAttribute(const QualifiedName& name) const
173 {
174     return hasAttributeNS(name.namespaceURI(), name.localName());
175 }
176 
getAttribute(const QualifiedName & name) const177 const AtomicString& Element::getAttribute(const QualifiedName& name) const
178 {
179     if (name == styleAttr && !m_isStyleAttributeValid)
180         updateStyleAttribute();
181 
182 #if ENABLE(SVG)
183     if (!m_areSVGAttributesValid)
184         updateAnimatedSVGAttribute(name.localName());
185 #endif
186 
187     if (namedAttrMap)
188         if (Attribute* a = namedAttrMap->getAttributeItem(name))
189             return a->value();
190 
191     return nullAtom;
192 }
193 
scrollIntoView(bool alignToTop)194 void Element::scrollIntoView(bool alignToTop)
195 {
196     document()->updateLayoutIgnorePendingStylesheets();
197     IntRect bounds = getRect();
198     if (renderer()) {
199         // Align to the top / bottom and to the closest edge.
200         if (alignToTop)
201             renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignTopAlways);
202         else
203             renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignBottomAlways);
204     }
205 }
206 
scrollIntoViewIfNeeded(bool centerIfNeeded)207 void Element::scrollIntoViewIfNeeded(bool centerIfNeeded)
208 {
209     document()->updateLayoutIgnorePendingStylesheets();
210     IntRect bounds = getRect();
211     if (renderer()) {
212         if (centerIfNeeded)
213             renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, ScrollAlignment::alignCenterIfNeeded, ScrollAlignment::alignCenterIfNeeded);
214         else
215             renderer()->enclosingLayer()->scrollRectToVisible(bounds, false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
216     }
217 }
218 
scrollByUnits(int units,ScrollGranularity granularity)219 void Element::scrollByUnits(int units, ScrollGranularity granularity)
220 {
221     document()->updateLayoutIgnorePendingStylesheets();
222     if (RenderObject *rend = renderer()) {
223         if (rend->hasOverflowClip()) {
224             ScrollDirection direction = ScrollDown;
225             if (units < 0) {
226                 direction = ScrollUp;
227                 units = -units;
228             }
229             toRenderBox(rend)->layer()->scroll(direction, granularity, units);
230         }
231     }
232 }
233 
scrollByLines(int lines)234 void Element::scrollByLines(int lines)
235 {
236     scrollByUnits(lines, ScrollByLine);
237 }
238 
scrollByPages(int pages)239 void Element::scrollByPages(int pages)
240 {
241     scrollByUnits(pages, ScrollByPage);
242 }
243 
localZoomForRenderer(RenderObject * renderer)244 static float localZoomForRenderer(RenderObject* renderer)
245 {
246     // FIXME: This does the wrong thing if two opposing zooms are in effect and canceled each
247     // other out, but the alternative is that we'd have to crawl up the whole render tree every
248     // time (or store an additional bit in the RenderStyle to indicate that a zoom was specified).
249     float zoomFactor = 1.0f;
250     if (renderer->style()->effectiveZoom() != 1.0f) {
251         // Need to find the nearest enclosing RenderObject that set up
252         // a differing zoom, and then we divide our result by it to eliminate the zoom.
253         RenderObject* prev = renderer;
254         for (RenderObject* curr = prev->parent(); curr; curr = curr->parent()) {
255             if (curr->style()->effectiveZoom() != prev->style()->effectiveZoom()) {
256                 zoomFactor = prev->style()->zoom();
257                 break;
258             }
259             prev = curr;
260         }
261         if (prev->isRenderView())
262             zoomFactor = prev->style()->zoom();
263     }
264     return zoomFactor;
265 }
266 
adjustForLocalZoom(int value,RenderObject * renderer)267 static int adjustForLocalZoom(int value, RenderObject* renderer)
268 {
269     float zoomFactor = localZoomForRenderer(renderer);
270     if (zoomFactor == 1)
271         return value;
272     // Needed because computeLengthInt truncates (rather than rounds) when scaling up.
273     if (zoomFactor > 1)
274         value++;
275     return static_cast<int>(value / zoomFactor);
276 }
277 
adjustForAbsoluteZoom(int value,RenderObject * renderer)278 static int adjustForAbsoluteZoom(int value, RenderObject* renderer)
279 {
280     float zoomFactor = renderer->style()->effectiveZoom();
281     if (zoomFactor == 1)
282         return value;
283     // Needed because computeLengthInt truncates (rather than rounds) when scaling up.
284     if (zoomFactor > 1)
285         value++;
286     return static_cast<int>(value / zoomFactor);
287 }
288 
adjustFloatPointForAbsoluteZoom(const FloatPoint & point,RenderObject * renderer)289 static FloatPoint adjustFloatPointForAbsoluteZoom(const FloatPoint& point, RenderObject* renderer)
290 {
291     // The result here is in floats, so we don't need the truncation hack from the integer version above.
292     float zoomFactor = renderer->style()->effectiveZoom();
293     if (zoomFactor == 1)
294         return point;
295     return FloatPoint(point.x() / zoomFactor, point.y() / zoomFactor);
296 }
297 
adjustFloatQuadForAbsoluteZoom(FloatQuad & quad,RenderObject * renderer)298 static void adjustFloatQuadForAbsoluteZoom(FloatQuad& quad, RenderObject* renderer)
299 {
300     quad.setP1(adjustFloatPointForAbsoluteZoom(quad.p1(), renderer));
301     quad.setP2(adjustFloatPointForAbsoluteZoom(quad.p2(), renderer));
302     quad.setP3(adjustFloatPointForAbsoluteZoom(quad.p3(), renderer));
303     quad.setP4(adjustFloatPointForAbsoluteZoom(quad.p4(), renderer));
304 }
305 
adjustIntRectForAbsoluteZoom(IntRect & rect,RenderObject * renderer)306 static void adjustIntRectForAbsoluteZoom(IntRect& rect, RenderObject* renderer)
307 {
308     rect.setX(adjustForAbsoluteZoom(rect.x(), renderer));
309     rect.setY(adjustForAbsoluteZoom(rect.y(), renderer));
310     rect.setWidth(adjustForAbsoluteZoom(rect.width(), renderer));
311     rect.setHeight(adjustForAbsoluteZoom(rect.height(), renderer));
312 }
313 
offsetLeft()314 int Element::offsetLeft()
315 {
316     document()->updateLayoutIgnorePendingStylesheets();
317     if (RenderBoxModelObject* rend = renderBoxModelObject())
318         return adjustForLocalZoom(rend->offsetLeft(), rend);
319     return 0;
320 }
321 
offsetTop()322 int Element::offsetTop()
323 {
324     document()->updateLayoutIgnorePendingStylesheets();
325     if (RenderBoxModelObject* rend = renderBoxModelObject())
326         return adjustForLocalZoom(rend->offsetTop(), rend);
327     return 0;
328 }
329 
offsetWidth()330 int Element::offsetWidth()
331 {
332     document()->updateLayoutIgnorePendingStylesheets();
333     if (RenderBoxModelObject* rend = renderBoxModelObject())
334         return adjustForAbsoluteZoom(rend->offsetWidth(), rend);
335     return 0;
336 }
337 
offsetHeight()338 int Element::offsetHeight()
339 {
340     document()->updateLayoutIgnorePendingStylesheets();
341     if (RenderBoxModelObject* rend = renderBoxModelObject())
342         return adjustForAbsoluteZoom(rend->offsetHeight(), rend);
343     return 0;
344 }
345 
offsetParent()346 Element* Element::offsetParent()
347 {
348     document()->updateLayoutIgnorePendingStylesheets();
349     if (RenderObject* rend = renderer())
350         if (RenderObject* offsetParent = rend->offsetParent())
351             return static_cast<Element*>(offsetParent->node());
352     return 0;
353 }
354 
clientLeft()355 int Element::clientLeft()
356 {
357     document()->updateLayoutIgnorePendingStylesheets();
358 
359     if (RenderBox* rend = renderBox())
360         return adjustForAbsoluteZoom(rend->clientLeft(), rend);
361     return 0;
362 }
363 
clientTop()364 int Element::clientTop()
365 {
366     document()->updateLayoutIgnorePendingStylesheets();
367 
368     if (RenderBox* rend = renderBox())
369         return adjustForAbsoluteZoom(rend->clientTop(), rend);
370     return 0;
371 }
372 
clientWidth()373 int Element::clientWidth()
374 {
375     document()->updateLayoutIgnorePendingStylesheets();
376 
377     // When in strict mode, clientWidth for the document element should return the width of the containing frame.
378     // When in quirks mode, clientWidth for the body element should return the width of the containing frame.
379     bool inCompatMode = document()->inCompatMode();
380     if ((!inCompatMode && document()->documentElement() == this) ||
381         (inCompatMode && isHTMLElement() && document()->body() == this)) {
382         if (FrameView* view = document()->view()) {
383             if (RenderView* renderView = document()->renderView())
384                 return adjustForAbsoluteZoom(view->layoutWidth(), renderView);
385         }
386     }
387 
388     if (RenderBox* rend = renderBox())
389         return adjustForAbsoluteZoom(rend->clientWidth(), rend);
390     return 0;
391 }
392 
clientHeight()393 int Element::clientHeight()
394 {
395     document()->updateLayoutIgnorePendingStylesheets();
396 
397     // When in strict mode, clientHeight for the document element should return the height of the containing frame.
398     // When in quirks mode, clientHeight for the body element should return the height of the containing frame.
399     bool inCompatMode = document()->inCompatMode();
400 
401     if ((!inCompatMode && document()->documentElement() == this) ||
402         (inCompatMode && isHTMLElement() && document()->body() == this)) {
403         if (FrameView* view = document()->view()) {
404             if (RenderView* renderView = document()->renderView())
405                 return adjustForAbsoluteZoom(view->layoutHeight(), renderView);
406         }
407     }
408 
409     if (RenderBox* rend = renderBox())
410         return adjustForAbsoluteZoom(rend->clientHeight(), rend);
411     return 0;
412 }
413 
scrollLeft() const414 int Element::scrollLeft() const
415 {
416     document()->updateLayoutIgnorePendingStylesheets();
417     if (RenderBox* rend = renderBox())
418         return adjustForAbsoluteZoom(rend->scrollLeft(), rend);
419     return 0;
420 }
421 
scrollTop() const422 int Element::scrollTop() const
423 {
424     document()->updateLayoutIgnorePendingStylesheets();
425     if (RenderBox* rend = renderBox())
426         return adjustForAbsoluteZoom(rend->scrollTop(), rend);
427     return 0;
428 }
429 
setScrollLeft(int newLeft)430 void Element::setScrollLeft(int newLeft)
431 {
432     document()->updateLayoutIgnorePendingStylesheets();
433     if (RenderBox* rend = renderBox())
434         rend->setScrollLeft(static_cast<int>(newLeft * rend->style()->effectiveZoom()));
435 }
436 
setScrollTop(int newTop)437 void Element::setScrollTop(int newTop)
438 {
439     document()->updateLayoutIgnorePendingStylesheets();
440     if (RenderBox* rend = renderBox())
441         rend->setScrollTop(static_cast<int>(newTop * rend->style()->effectiveZoom()));
442 }
443 
scrollWidth() const444 int Element::scrollWidth() const
445 {
446     document()->updateLayoutIgnorePendingStylesheets();
447     if (RenderBox* rend = renderBox())
448         return adjustForAbsoluteZoom(rend->scrollWidth(), rend);
449     return 0;
450 }
451 
scrollHeight() const452 int Element::scrollHeight() const
453 {
454     document()->updateLayoutIgnorePendingStylesheets();
455     if (RenderBox* rend = renderBox())
456         return adjustForAbsoluteZoom(rend->scrollHeight(), rend);
457     return 0;
458 }
459 
getClientRects() const460 PassRefPtr<ClientRectList> Element::getClientRects() const
461 {
462     document()->updateLayoutIgnorePendingStylesheets();
463 
464     RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject();
465     if (!renderBoxModelObject)
466         return ClientRectList::create();
467 
468     // FIXME: Handle SVG elements.
469     // FIXME: Handle table/inline-table with a caption.
470 
471     Vector<FloatQuad> quads;
472     renderBoxModelObject->absoluteQuads(quads);
473 
474     if (FrameView* view = document()->view()) {
475         IntRect visibleContentRect = view->visibleContentRect();
476         for (size_t i = 0; i < quads.size(); ++i) {
477             quads[i].move(-visibleContentRect.x(), -visibleContentRect.y());
478             adjustFloatQuadForAbsoluteZoom(quads[i], renderBoxModelObject);
479         }
480     }
481 
482     return ClientRectList::create(quads);
483 }
484 
getBoundingClientRect() const485 PassRefPtr<ClientRect> Element::getBoundingClientRect() const
486 {
487     document()->updateLayoutIgnorePendingStylesheets();
488     RenderBoxModelObject* renderBoxModelObject = this->renderBoxModelObject();
489     if (!renderBoxModelObject)
490         return ClientRect::create();
491 
492     Vector<FloatQuad> quads;
493     renderBoxModelObject->absoluteQuads(quads);
494 
495     if (quads.isEmpty())
496         return ClientRect::create();
497 
498     IntRect result = quads[0].enclosingBoundingBox();
499     for (size_t i = 1; i < quads.size(); ++i)
500         result.unite(quads[i].enclosingBoundingBox());
501 
502     if (FrameView* view = document()->view()) {
503         IntRect visibleContentRect = view->visibleContentRect();
504         result.move(-visibleContentRect.x(), -visibleContentRect.y());
505     }
506 
507     adjustIntRectForAbsoluteZoom(result, renderBoxModelObject);
508 
509     return ClientRect::create(result);
510 }
511 
shouldIgnoreAttributeCase(const Element * e)512 static inline bool shouldIgnoreAttributeCase(const Element* e)
513 {
514     return e && e->document()->isHTMLDocument() && e->isHTMLElement();
515 }
516 
getAttribute(const String & name) const517 const AtomicString& Element::getAttribute(const String& name) const
518 {
519     String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
520     if (localName == styleAttr.localName() && !m_isStyleAttributeValid)
521         updateStyleAttribute();
522 
523 #if ENABLE(SVG)
524     if (!m_areSVGAttributesValid)
525         updateAnimatedSVGAttribute(name);
526 #endif
527 
528     if (namedAttrMap)
529         if (Attribute* a = namedAttrMap->getAttributeItem(name, shouldIgnoreAttributeCase(this)))
530             return a->value();
531 
532     return nullAtom;
533 }
534 
getAttributeNS(const String & namespaceURI,const String & localName) const535 const AtomicString& Element::getAttributeNS(const String& namespaceURI, const String& localName) const
536 {
537     return getAttribute(QualifiedName(nullAtom, localName, namespaceURI));
538 }
539 
setAttribute(const AtomicString & name,const AtomicString & value,ExceptionCode & ec)540 void Element::setAttribute(const AtomicString& name, const AtomicString& value, ExceptionCode& ec)
541 {
542     if (!Document::isValidName(name)) {
543         ec = INVALID_CHARACTER_ERR;
544         return;
545     }
546 
547     const AtomicString& localName = (shouldIgnoreAttributeCase(this) && !name.string().impl()->isLower()) ? AtomicString(name.string().lower()) : name;
548 
549     // allocate attributemap if necessary
550     Attribute* old = attributes(false)->getAttributeItem(localName, false);
551 
552     document()->incDOMTreeVersion();
553 
554     if (localName == idAttr.localName())
555         updateId(old ? old->value() : nullAtom, value);
556 
557     if (old && value.isNull())
558         namedAttrMap->removeAttribute(old->name());
559     else if (!old && !value.isNull())
560         namedAttrMap->addAttribute(createAttribute(QualifiedName(nullAtom, localName, nullAtom), value));
561     else if (old && !value.isNull()) {
562         old->setValue(value);
563         attributeChanged(old);
564     }
565 }
566 
setAttribute(const QualifiedName & name,const AtomicString & value,ExceptionCode &)567 void Element::setAttribute(const QualifiedName& name, const AtomicString& value, ExceptionCode&)
568 {
569     document()->incDOMTreeVersion();
570 
571     // allocate attributemap if necessary
572     Attribute* old = attributes(false)->getAttributeItem(name);
573 
574     if (name == idAttr)
575         updateId(old ? old->value() : nullAtom, value);
576 
577     if (old && value.isNull())
578         namedAttrMap->removeAttribute(name);
579     else if (!old && !value.isNull())
580         namedAttrMap->addAttribute(createAttribute(name, value));
581     else if (old) {
582         old->setValue(value);
583         attributeChanged(old);
584     }
585 }
586 
createAttribute(const QualifiedName & name,const AtomicString & value)587 PassRefPtr<Attribute> Element::createAttribute(const QualifiedName& name, const AtomicString& value)
588 {
589     return Attribute::create(name, value);
590 }
591 
attributeChanged(Attribute * attr,bool)592 void Element::attributeChanged(Attribute* attr, bool)
593 {
594     recalcStyleIfNeededAfterAttributeChanged(attr);
595     updateAfterAttributeChanged(attr);
596 }
597 
updateAfterAttributeChanged(Attribute * attr)598 void Element::updateAfterAttributeChanged(Attribute* attr)
599 {
600     if (!document()->axObjectCache()->accessibilityEnabled())
601         return;
602 
603     const QualifiedName& attrName = attr->name();
604     if (attrName == aria_activedescendantAttr) {
605         // any change to aria-activedescendant attribute triggers accessibility focus change, but document focus remains intact
606         document()->axObjectCache()->handleActiveDescendantChanged(renderer());
607     } else if (attrName == roleAttr) {
608         // the role attribute can change at any time, and the AccessibilityObject must pick up these changes
609         document()->axObjectCache()->handleAriaRoleChanged(renderer());
610     }
611 }
612 
recalcStyleIfNeededAfterAttributeChanged(Attribute * attr)613 void Element::recalcStyleIfNeededAfterAttributeChanged(Attribute* attr)
614 {
615     if (document()->attached() && document()->styleSelector()->hasSelectorForAttribute(attr->name().localName()))
616         setNeedsStyleRecalc();
617 }
618 
setAttributeMap(PassRefPtr<NamedNodeMap> list)619 void Element::setAttributeMap(PassRefPtr<NamedNodeMap> list)
620 {
621     document()->incDOMTreeVersion();
622 
623     // If setting the whole map changes the id attribute, we need to call updateId.
624 
625     Attribute* oldId = namedAttrMap ? namedAttrMap->getAttributeItem(idAttr) : 0;
626     Attribute* newId = list ? list->getAttributeItem(idAttr) : 0;
627 
628     if (oldId || newId)
629         updateId(oldId ? oldId->value() : nullAtom, newId ? newId->value() : nullAtom);
630 
631     if (namedAttrMap)
632         namedAttrMap->m_element = 0;
633 
634     namedAttrMap = list;
635 
636     if (namedAttrMap) {
637         namedAttrMap->m_element = this;
638         unsigned len = namedAttrMap->length();
639         for (unsigned i = 0; i < len; i++)
640             attributeChanged(namedAttrMap->m_attributes[i].get());
641         // FIXME: What about attributes that were in the old map that are not in the new map?
642     }
643 }
644 
hasAttributes() const645 bool Element::hasAttributes() const
646 {
647     if (!m_isStyleAttributeValid)
648         updateStyleAttribute();
649 
650 #if ENABLE(SVG)
651     if (!m_areSVGAttributesValid)
652         updateAnimatedSVGAttribute(String());
653 #endif
654 
655     return namedAttrMap && namedAttrMap->length() > 0;
656 }
657 
nodeName() const658 String Element::nodeName() const
659 {
660     return m_tagName.toString();
661 }
662 
nodeNamePreservingCase() const663 String Element::nodeNamePreservingCase() const
664 {
665     return m_tagName.toString();
666 }
667 
setPrefix(const AtomicString & _prefix,ExceptionCode & ec)668 void Element::setPrefix(const AtomicString &_prefix, ExceptionCode& ec)
669 {
670     ec = 0;
671     checkSetPrefix(_prefix, ec);
672     if (ec)
673         return;
674 
675     m_tagName.setPrefix(_prefix);
676 }
677 
baseURI() const678 KURL Element::baseURI() const
679 {
680     KURL base(getAttribute(baseAttr));
681     if (!base.protocol().isEmpty())
682         return base;
683 
684     Node* parent = parentNode();
685     if (!parent)
686         return base;
687 
688     const KURL& parentBase = parent->baseURI();
689     if (parentBase.isNull())
690         return base;
691 
692     return KURL(parentBase, base.string());
693 }
694 
createAttributeMap() const695 void Element::createAttributeMap() const
696 {
697     namedAttrMap = NamedNodeMap::create(const_cast<Element*>(this));
698 }
699 
isURLAttribute(Attribute *) const700 bool Element::isURLAttribute(Attribute*) const
701 {
702     return false;
703 }
704 
imageSourceAttributeName() const705 const QualifiedName& Element::imageSourceAttributeName() const
706 {
707     return srcAttr;
708 }
709 
createRenderer(RenderArena * arena,RenderStyle * style)710 RenderObject* Element::createRenderer(RenderArena* arena, RenderStyle* style)
711 {
712     if (document()->documentElement() == this && style->display() == NONE) {
713         // Ignore display: none on root elements.  Force a display of block in that case.
714         RenderBlock* result = new (arena) RenderBlock(this);
715         if (result)
716             result->setAnimatableStyle(style);
717         return result;
718     }
719     return RenderObject::createObject(this, style);
720 }
721 
722 
insertedIntoDocument()723 void Element::insertedIntoDocument()
724 {
725     // need to do superclass processing first so inDocument() is true
726     // by the time we reach updateId
727     ContainerNode::insertedIntoDocument();
728 
729     if (hasID()) {
730         if (NamedNodeMap* attrs = namedAttrMap.get()) {
731             Attribute* idItem = attrs->getAttributeItem(idAttr);
732             if (idItem && !idItem->isNull())
733                 updateId(nullAtom, idItem->value());
734         }
735     }
736 }
737 
removedFromDocument()738 void Element::removedFromDocument()
739 {
740     if (hasID()) {
741         if (NamedNodeMap* attrs = namedAttrMap.get()) {
742             Attribute* idItem = attrs->getAttributeItem(idAttr);
743             if (idItem && !idItem->isNull())
744                 updateId(idItem->value(), nullAtom);
745         }
746     }
747 
748     ContainerNode::removedFromDocument();
749 }
750 
attach()751 void Element::attach()
752 {
753     suspendPostAttachCallbacks();
754 
755     createRendererIfNeeded();
756     ContainerNode::attach();
757     if (hasRareData()) {
758         ElementRareData* data = rareData();
759         if (data->needsFocusAppearanceUpdateSoonAfterAttach()) {
760             if (isFocusable() && document()->focusedNode() == this)
761                 document()->updateFocusAppearanceSoon();
762             data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
763         }
764     }
765 
766     resumePostAttachCallbacks();
767 }
768 
detach()769 void Element::detach()
770 {
771     cancelFocusAppearanceUpdate();
772     if (hasRareData())
773         rareData()->resetComputedStyle();
774     ContainerNode::detach();
775 }
776 
pseudoStyleCacheIsInvalid(const RenderStyle * currentStyle,RenderStyle * newStyle)777 bool Element::pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle)
778 {
779     ASSERT(currentStyle = renderStyle());
780 
781     if (!renderer() || !currentStyle)
782         return false;
783 
784     RenderStyle::PseudoStyleCache pseudoStyleCache;
785     currentStyle->getPseudoStyleCache(pseudoStyleCache);
786     size_t cacheSize = pseudoStyleCache.size();
787     for (size_t i = 0; i < cacheSize; ++i) {
788         RefPtr<RenderStyle> newPseudoStyle;
789         PseudoId pseudoId = pseudoStyleCache[i]->styleType();
790         if (pseudoId == FIRST_LINE || pseudoId == FIRST_LINE_INHERITED)
791             newPseudoStyle = renderer()->uncachedFirstLineStyle(newStyle);
792         else
793             newPseudoStyle = renderer()->getUncachedPseudoStyle(pseudoId, newStyle, newStyle);
794 
795         if (*newPseudoStyle != *pseudoStyleCache[i]) {
796             if (pseudoId < FIRST_INTERNAL_PSEUDOID)
797                 newStyle->setHasPseudoStyle(pseudoId);
798             newStyle->addCachedPseudoStyle(newPseudoStyle);
799             return true;
800         }
801     }
802     return false;
803 }
804 
recalcStyle(StyleChange change)805 void Element::recalcStyle(StyleChange change)
806 {
807     RenderStyle* currentStyle = renderStyle();
808     bool hasParentStyle = parentNode() ? parentNode()->renderStyle() : false;
809     bool hasPositionalRules = needsStyleRecalc() && currentStyle && currentStyle->childrenAffectedByPositionalRules();
810     bool hasDirectAdjacentRules = currentStyle && currentStyle->childrenAffectedByDirectAdjacentRules();
811 
812 #if ENABLE(SVG)
813     if (!hasParentStyle && isShadowNode() && isSVGElement())
814         hasParentStyle = true;
815 #endif
816 
817     if ((change > NoChange || needsStyleRecalc())) {
818         if (hasRareData())
819             rareData()->resetComputedStyle();
820     }
821     if (hasParentStyle && (change >= Inherit || needsStyleRecalc())) {
822         RefPtr<RenderStyle> newStyle = document()->styleSelector()->styleForElement(this);
823         StyleChange ch = diff(currentStyle, newStyle.get());
824         if (ch == Detach || !currentStyle) {
825             if (attached())
826                 detach();
827             attach(); // FIXME: The style gets computed twice by calling attach. We could do better if we passed the style along.
828             // attach recalulates the style for all children. No need to do it twice.
829             setNeedsStyleRecalc(NoStyleChange);
830             setChildNeedsStyleRecalc(false);
831             return;
832         }
833 
834         if (currentStyle) {
835             // Preserve "affected by" bits that were propagated to us from descendants in the case where we didn't do a full
836             // style change (e.g., only inline style changed).
837             if (currentStyle->affectedByHoverRules())
838                 newStyle->setAffectedByHoverRules(true);
839             if (currentStyle->affectedByActiveRules())
840                 newStyle->setAffectedByActiveRules(true);
841             if (currentStyle->affectedByDragRules())
842                 newStyle->setAffectedByDragRules(true);
843             if (currentStyle->childrenAffectedByForwardPositionalRules())
844                 newStyle->setChildrenAffectedByForwardPositionalRules();
845             if (currentStyle->childrenAffectedByBackwardPositionalRules())
846                 newStyle->setChildrenAffectedByBackwardPositionalRules();
847             if (currentStyle->childrenAffectedByFirstChildRules())
848                 newStyle->setChildrenAffectedByFirstChildRules();
849             if (currentStyle->childrenAffectedByLastChildRules())
850                 newStyle->setChildrenAffectedByLastChildRules();
851             if (currentStyle->childrenAffectedByDirectAdjacentRules())
852                 newStyle->setChildrenAffectedByDirectAdjacentRules();
853         }
854 
855         if (ch != NoChange || pseudoStyleCacheIsInvalid(currentStyle, newStyle.get())) {
856             setRenderStyle(newStyle);
857         } else if (needsStyleRecalc() && (styleChangeType() != AnimationStyleChange) && (document()->usesSiblingRules() || document()->usesDescendantRules())) {
858             // Although no change occurred, we use the new style so that the cousin style sharing code won't get
859             // fooled into believing this style is the same.  This is only necessary if the document actually uses
860             // sibling/descendant rules, since otherwise it isn't possible for ancestor styles to affect sharing of
861             // descendants.
862             if (renderer())
863                 renderer()->setStyleInternal(newStyle.get());
864             else
865                 setRenderStyle(newStyle);
866         } else if (styleChangeType() == AnimationStyleChange)
867              setRenderStyle(newStyle);
868 
869         if (change != Force) {
870             // 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
871             // 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).
872             if (document()->usesRemUnits() && ch != NoChange && currentStyle && newStyle && currentStyle->fontSize() != newStyle->fontSize() && document()->documentElement() == this)
873                 change = Force;
874             else if ((document()->usesDescendantRules() || hasPositionalRules) && styleChangeType() >= FullStyleChange)
875                 change = Force;
876             else
877                 change = ch;
878         }
879     }
880 
881     // FIXME: This check is good enough for :hover + foo, but it is not good enough for :hover + foo + bar.
882     // For now we will just worry about the common case, since it's a lot trickier to get the second case right
883     // without doing way too much re-resolution.
884     bool forceCheckOfNextElementSibling = false;
885     for (Node *n = firstChild(); n; n = n->nextSibling()) {
886         bool childRulesChanged = n->needsStyleRecalc() && n->styleChangeType() == FullStyleChange;
887         if (forceCheckOfNextElementSibling && n->isElementNode())
888             n->setNeedsStyleRecalc();
889         if (change >= Inherit || n->isTextNode() || n->childNeedsStyleRecalc() || n->needsStyleRecalc())
890             n->recalcStyle(change);
891         if (n->isElementNode())
892             forceCheckOfNextElementSibling = childRulesChanged && hasDirectAdjacentRules;
893     }
894 
895     setNeedsStyleRecalc(NoStyleChange);
896     setChildNeedsStyleRecalc(false);
897 }
898 
childTypeAllowed(NodeType type)899 bool Element::childTypeAllowed(NodeType type)
900 {
901     switch (type) {
902         case ELEMENT_NODE:
903         case TEXT_NODE:
904         case COMMENT_NODE:
905         case PROCESSING_INSTRUCTION_NODE:
906         case CDATA_SECTION_NODE:
907         case ENTITY_REFERENCE_NODE:
908             return true;
909             break;
910         default:
911             return false;
912     }
913 }
914 
checkForSiblingStyleChanges(Element * e,RenderStyle * style,bool finishedParsingCallback,Node * beforeChange,Node * afterChange,int childCountDelta)915 static void checkForSiblingStyleChanges(Element* e, RenderStyle* style, bool finishedParsingCallback,
916                                         Node* beforeChange, Node* afterChange, int childCountDelta)
917 {
918     if (!style || (e->needsStyleRecalc() && style->childrenAffectedByPositionalRules()))
919         return;
920 
921     // :first-child.  In the parser callback case, we don't have to check anything, since we were right the first time.
922     // In the DOM case, we only need to do something if |afterChange| is not 0.
923     // |afterChange| is 0 in the parser case, so it works out that we'll skip this block.
924     if (style->childrenAffectedByFirstChildRules() && afterChange) {
925         // Find our new first child.
926         Node* newFirstChild = 0;
927         for (newFirstChild = e->firstChild(); newFirstChild && !newFirstChild->isElementNode(); newFirstChild = newFirstChild->nextSibling()) {};
928 
929         // Find the first element node following |afterChange|
930         Node* firstElementAfterInsertion = 0;
931         for (firstElementAfterInsertion = afterChange;
932              firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
933              firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
934 
935         // This is the insert/append case.
936         if (newFirstChild != firstElementAfterInsertion && firstElementAfterInsertion && firstElementAfterInsertion->attached() &&
937             firstElementAfterInsertion->renderStyle() && firstElementAfterInsertion->renderStyle()->firstChildState())
938             firstElementAfterInsertion->setNeedsStyleRecalc();
939 
940         // We also have to handle node removal.
941         if (childCountDelta < 0 && newFirstChild == firstElementAfterInsertion && newFirstChild && newFirstChild->renderStyle() && !newFirstChild->renderStyle()->firstChildState())
942             newFirstChild->setNeedsStyleRecalc();
943     }
944 
945     // :last-child.  In the parser callback case, we don't have to check anything, since we were right the first time.
946     // In the DOM case, we only need to do something if |afterChange| is not 0.
947     if (style->childrenAffectedByLastChildRules() && beforeChange) {
948         // Find our new last child.
949         Node* newLastChild = 0;
950         for (newLastChild = e->lastChild(); newLastChild && !newLastChild->isElementNode(); newLastChild = newLastChild->previousSibling()) {};
951 
952         // Find the last element node going backwards from |beforeChange|
953         Node* lastElementBeforeInsertion = 0;
954         for (lastElementBeforeInsertion = beforeChange;
955              lastElementBeforeInsertion && !lastElementBeforeInsertion->isElementNode();
956              lastElementBeforeInsertion = lastElementBeforeInsertion->previousSibling()) {};
957 
958         if (newLastChild != lastElementBeforeInsertion && lastElementBeforeInsertion && lastElementBeforeInsertion->attached() &&
959             lastElementBeforeInsertion->renderStyle() && lastElementBeforeInsertion->renderStyle()->lastChildState())
960             lastElementBeforeInsertion->setNeedsStyleRecalc();
961 
962         // 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
963         // to match now.
964         if ((childCountDelta < 0 || finishedParsingCallback) && newLastChild == lastElementBeforeInsertion && newLastChild && newLastChild->renderStyle() && !newLastChild->renderStyle()->lastChildState())
965             newLastChild->setNeedsStyleRecalc();
966     }
967 
968     // The + selector.  We need to invalidate the first element following the insertion point.  It is the only possible element
969     // that could be affected by this DOM change.
970     if (style->childrenAffectedByDirectAdjacentRules() && afterChange) {
971         Node* firstElementAfterInsertion = 0;
972         for (firstElementAfterInsertion = afterChange;
973              firstElementAfterInsertion && !firstElementAfterInsertion->isElementNode();
974              firstElementAfterInsertion = firstElementAfterInsertion->nextSibling()) {};
975         if (firstElementAfterInsertion && firstElementAfterInsertion->attached())
976             firstElementAfterInsertion->setNeedsStyleRecalc();
977     }
978 
979     // Forward positional selectors include the ~ selector, nth-child, nth-of-type, first-of-type and only-of-type.
980     // Backward positional selectors include nth-last-child, nth-last-of-type, last-of-type and only-of-type.
981     // We have to invalidate everything following the insertion point in the forward case, and everything before the insertion point in the
982     // backward case.
983     // |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.
984     // 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
985     // here.  recalcStyle will then force a walk of the children when it sees that this has happened.
986     if ((style->childrenAffectedByForwardPositionalRules() && afterChange) ||
987         (style->childrenAffectedByBackwardPositionalRules() && beforeChange))
988         e->setNeedsStyleRecalc();
989 
990     // :empty selector.
991     if (style->affectedByEmpty() && (!style->emptyState() || e->hasChildNodes()))
992         e->setNeedsStyleRecalc();
993 }
994 
childrenChanged(bool changedByParser,Node * beforeChange,Node * afterChange,int childCountDelta)995 void Element::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
996 {
997     ContainerNode::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
998     if (!changedByParser)
999         checkForSiblingStyleChanges(this, renderStyle(), false, beforeChange, afterChange, childCountDelta);
1000 }
1001 
finishParsingChildren()1002 void Element::finishParsingChildren()
1003 {
1004     ContainerNode::finishParsingChildren();
1005     m_parsingChildrenFinished = true;
1006     checkForSiblingStyleChanges(this, renderStyle(), true, lastChild(), 0, 0);
1007 }
1008 
dispatchAttrRemovalEvent(Attribute *)1009 void Element::dispatchAttrRemovalEvent(Attribute*)
1010 {
1011     ASSERT(!eventDispatchForbidden());
1012 #if 0
1013     if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER))
1014         return;
1015     ExceptionCode ec = 0;
1016     dispatchEvent(new MutationEvent(DOMAttrModifiedEvent, true, false, attr, attr->value(),
1017         attr->value(), document()->attrName(attr->id()), MutationEvent::REMOVAL), ec);
1018 #endif
1019 }
1020 
dispatchAttrAdditionEvent(Attribute *)1021 void Element::dispatchAttrAdditionEvent(Attribute*)
1022 {
1023     ASSERT(!eventDispatchForbidden());
1024 #if 0
1025     if (!document()->hasListenerType(Document::DOMATTRMODIFIED_LISTENER))
1026         return;
1027     ExceptionCode ec = 0;
1028     dispatchEvent(new MutationEvent(DOMAttrModifiedEvent, true, false, attr, attr->value(),
1029         attr->value(), document()->attrName(attr->id()), MutationEvent::ADDITION), ec);
1030 #endif
1031 }
1032 
openTagStartToString() const1033 String Element::openTagStartToString() const
1034 {
1035     String result = "<" + nodeName();
1036 
1037     NamedNodeMap* attrMap = attributes(true);
1038 
1039     if (attrMap) {
1040         unsigned numAttrs = attrMap->length();
1041         for (unsigned i = 0; i < numAttrs; i++) {
1042             result += " ";
1043 
1044             Attribute *attribute = attrMap->attributeItem(i);
1045             result += attribute->name().toString();
1046             if (!attribute->value().isNull()) {
1047                 result += "=\"";
1048                 // FIXME: substitute entities for any instances of " or '
1049                 result += attribute->value();
1050                 result += "\"";
1051             }
1052         }
1053     }
1054 
1055     return result;
1056 }
1057 
updateId(const AtomicString & oldId,const AtomicString & newId)1058 void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
1059 {
1060     if (!inDocument())
1061         return;
1062 
1063     if (oldId == newId)
1064         return;
1065 
1066     Document* doc = document();
1067     if (!oldId.isEmpty())
1068         doc->removeElementById(oldId, this);
1069     if (!newId.isEmpty())
1070         doc->addElementById(newId, this);
1071 }
1072 
1073 #ifndef NDEBUG
formatForDebugger(char * buffer,unsigned length) const1074 void Element::formatForDebugger(char* buffer, unsigned length) const
1075 {
1076     String result;
1077     String s;
1078 
1079     s = nodeName();
1080     if (s.length() > 0) {
1081         result += s;
1082     }
1083 
1084     s = getAttribute(idAttr);
1085     if (s.length() > 0) {
1086         if (result.length() > 0)
1087             result += "; ";
1088         result += "id=";
1089         result += s;
1090     }
1091 
1092     s = getAttribute(classAttr);
1093     if (s.length() > 0) {
1094         if (result.length() > 0)
1095             result += "; ";
1096         result += "class=";
1097         result += s;
1098     }
1099 
1100     strncpy(buffer, result.utf8().data(), length - 1);
1101 }
1102 #endif
1103 
setAttributeNode(Attr * attr,ExceptionCode & ec)1104 PassRefPtr<Attr> Element::setAttributeNode(Attr* attr, ExceptionCode& ec)
1105 {
1106     if (!attr) {
1107         ec = TYPE_MISMATCH_ERR;
1108         return 0;
1109     }
1110     return static_pointer_cast<Attr>(attributes(false)->setNamedItem(attr, ec));
1111 }
1112 
setAttributeNodeNS(Attr * attr,ExceptionCode & ec)1113 PassRefPtr<Attr> Element::setAttributeNodeNS(Attr* attr, ExceptionCode& ec)
1114 {
1115     if (!attr) {
1116         ec = TYPE_MISMATCH_ERR;
1117         return 0;
1118     }
1119     return static_pointer_cast<Attr>(attributes(false)->setNamedItem(attr, ec));
1120 }
1121 
removeAttributeNode(Attr * attr,ExceptionCode & ec)1122 PassRefPtr<Attr> Element::removeAttributeNode(Attr* attr, ExceptionCode& ec)
1123 {
1124     if (!attr) {
1125         ec = TYPE_MISMATCH_ERR;
1126         return 0;
1127     }
1128     if (attr->ownerElement() != this) {
1129         ec = NOT_FOUND_ERR;
1130         return 0;
1131     }
1132     if (document() != attr->document()) {
1133         ec = WRONG_DOCUMENT_ERR;
1134         return 0;
1135     }
1136 
1137     NamedNodeMap* attrs = attributes(true);
1138     if (!attrs)
1139         return 0;
1140 
1141     return static_pointer_cast<Attr>(attrs->removeNamedItem(attr->qualifiedName(), ec));
1142 }
1143 
setAttributeNS(const AtomicString & namespaceURI,const AtomicString & qualifiedName,const AtomicString & value,ExceptionCode & ec)1144 void Element::setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode& ec)
1145 {
1146     String prefix, localName;
1147     if (!Document::parseQualifiedName(qualifiedName, prefix, localName, ec))
1148         return;
1149 
1150     QualifiedName qName(prefix, localName, namespaceURI);
1151     setAttribute(qName, value, ec);
1152 }
1153 
removeAttribute(const String & name,ExceptionCode & ec)1154 void Element::removeAttribute(const String& name, ExceptionCode& ec)
1155 {
1156     String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1157 
1158     if (namedAttrMap) {
1159         namedAttrMap->removeNamedItem(localName, ec);
1160         if (ec == NOT_FOUND_ERR)
1161             ec = 0;
1162     }
1163 }
1164 
removeAttributeNS(const String & namespaceURI,const String & localName,ExceptionCode & ec)1165 void Element::removeAttributeNS(const String& namespaceURI, const String& localName, ExceptionCode& ec)
1166 {
1167     removeAttribute(QualifiedName(nullAtom, localName, namespaceURI), ec);
1168 }
1169 
getAttributeNode(const String & name)1170 PassRefPtr<Attr> Element::getAttributeNode(const String& name)
1171 {
1172     NamedNodeMap* attrs = attributes(true);
1173     if (!attrs)
1174         return 0;
1175     String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1176     return static_pointer_cast<Attr>(attrs->getNamedItem(localName));
1177 }
1178 
getAttributeNodeNS(const String & namespaceURI,const String & localName)1179 PassRefPtr<Attr> Element::getAttributeNodeNS(const String& namespaceURI, const String& localName)
1180 {
1181     NamedNodeMap* attrs = attributes(true);
1182     if (!attrs)
1183         return 0;
1184     return static_pointer_cast<Attr>(attrs->getNamedItem(QualifiedName(nullAtom, localName, namespaceURI)));
1185 }
1186 
hasAttribute(const String & name) const1187 bool Element::hasAttribute(const String& name) const
1188 {
1189     NamedNodeMap* attrs = attributes(true);
1190     if (!attrs)
1191         return false;
1192 
1193     // This call to String::lower() seems to be required but
1194     // there may be a way to remove it.
1195     String localName = shouldIgnoreAttributeCase(this) ? name.lower() : name;
1196     return attrs->getAttributeItem(localName, false);
1197 }
1198 
hasAttributeNS(const String & namespaceURI,const String & localName) const1199 bool Element::hasAttributeNS(const String& namespaceURI, const String& localName) const
1200 {
1201     NamedNodeMap* attrs = attributes(true);
1202     if (!attrs)
1203         return false;
1204     return attrs->getAttributeItem(QualifiedName(nullAtom, localName, namespaceURI));
1205 }
1206 
style()1207 CSSStyleDeclaration *Element::style()
1208 {
1209     return 0;
1210 }
1211 
focus(bool restorePreviousSelection)1212 void Element::focus(bool restorePreviousSelection)
1213 {
1214     Document* doc = document();
1215     if (doc->focusedNode() == this)
1216         return;
1217 
1218     doc->updateLayoutIgnorePendingStylesheets();
1219 
1220     if (!supportsFocus())
1221         return;
1222 
1223     if (Page* page = doc->page())
1224         page->focusController()->setFocusedNode(this, doc->frame());
1225 
1226     if (!isFocusable()) {
1227         ensureRareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(true);
1228         return;
1229     }
1230 
1231     cancelFocusAppearanceUpdate();
1232     updateFocusAppearance(restorePreviousSelection);
1233 }
1234 
updateFocusAppearance(bool)1235 void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
1236 {
1237     if (this == rootEditableElement()) {
1238         Frame* frame = document()->frame();
1239         if (!frame)
1240             return;
1241 
1242         // FIXME: We should restore the previous selection if there is one.
1243         VisibleSelection newSelection = hasTagName(htmlTag) || hasTagName(bodyTag) ? VisibleSelection(Position(this, 0), DOWNSTREAM) : VisibleSelection::selectionFromContentsOfNode(this);
1244 
1245         if (frame->shouldChangeSelection(newSelection)) {
1246             frame->selection()->setSelection(newSelection);
1247             frame->revealSelection();
1248         }
1249     }
1250     // FIXME: I'm not sure all devices will want this off, but this is
1251     // currently turned off for Andriod.
1252 #if !ENABLE(DIRECTIONAL_PAD_NAVIGATION)
1253     else if (renderer() && !renderer()->isWidget())
1254         renderer()->enclosingLayer()->scrollRectToVisible(getRect());
1255 #endif
1256 }
1257 
blur()1258 void Element::blur()
1259 {
1260     cancelFocusAppearanceUpdate();
1261     Document* doc = document();
1262     if (doc->focusedNode() == this) {
1263         if (doc->frame())
1264             doc->frame()->page()->focusController()->setFocusedNode(0, doc->frame());
1265         else
1266             doc->setFocusedNode(0);
1267     }
1268 }
1269 
innerText() const1270 String Element::innerText() const
1271 {
1272     // We need to update layout, since plainText uses line boxes in the render tree.
1273     document()->updateLayoutIgnorePendingStylesheets();
1274 
1275     if (!renderer())
1276         return textContent(true);
1277 
1278     return plainText(rangeOfContents(const_cast<Element*>(this)).get());
1279 }
1280 
outerText() const1281 String Element::outerText() const
1282 {
1283     // Getting outerText is the same as getting innerText, only
1284     // setting is different. You would think this should get the plain
1285     // text for the outer range, but this is wrong, <br> for instance
1286     // would return different values for inner and outer text by such
1287     // a rule, but it doesn't in WinIE, and we want to match that.
1288     return innerText();
1289 }
1290 
title() const1291 String Element::title() const
1292 {
1293     return String();
1294 }
1295 
minimumSizeForResizing() const1296 IntSize Element::minimumSizeForResizing() const
1297 {
1298     return hasRareData() ? rareData()->m_minimumSizeForResizing : defaultMinimumSizeForResizing();
1299 }
1300 
setMinimumSizeForResizing(const IntSize & size)1301 void Element::setMinimumSizeForResizing(const IntSize& size)
1302 {
1303     if (size == defaultMinimumSizeForResizing() && !hasRareData())
1304         return;
1305     ensureRareData()->m_minimumSizeForResizing = size;
1306 }
1307 
computedStyle()1308 RenderStyle* Element::computedStyle()
1309 {
1310     if (RenderStyle* usedStyle = renderStyle())
1311         return usedStyle;
1312 
1313     if (!attached())
1314         // FIXME: Try to do better than this. Ensure that styleForElement() works for elements that are not in the
1315         // document tree and figure out when to destroy the computed style for such elements.
1316         return 0;
1317 
1318     ElementRareData* data = ensureRareData();
1319     if (!data->m_computedStyle)
1320         data->m_computedStyle = document()->styleSelector()->styleForElement(this, parent() ? parent()->computedStyle() : 0);
1321     return data->m_computedStyle.get();
1322 }
1323 
cancelFocusAppearanceUpdate()1324 void Element::cancelFocusAppearanceUpdate()
1325 {
1326     if (hasRareData())
1327         rareData()->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
1328     if (document()->focusedNode() == this)
1329         document()->cancelFocusAppearanceUpdate();
1330 }
1331 
normalizeAttributes()1332 void Element::normalizeAttributes()
1333 {
1334     // Normalize attributes.
1335     NamedNodeMap* attrs = attributes(true);
1336     if (!attrs)
1337         return;
1338     unsigned numAttrs = attrs->length();
1339     for (unsigned i = 0; i < numAttrs; i++) {
1340         if (Attr* attr = attrs->attributeItem(i)->attr())
1341             attr->normalize();
1342     }
1343 }
1344 
1345 // ElementTraversal API
firstElementChild() const1346 Element* Element::firstElementChild() const
1347 {
1348     Node* n = firstChild();
1349     while (n && !n->isElementNode())
1350         n = n->nextSibling();
1351     return static_cast<Element*>(n);
1352 }
1353 
lastElementChild() const1354 Element* Element::lastElementChild() const
1355 {
1356     Node* n = lastChild();
1357     while (n && !n->isElementNode())
1358         n = n->previousSibling();
1359     return static_cast<Element*>(n);
1360 }
1361 
previousElementSibling() const1362 Element* Element::previousElementSibling() const
1363 {
1364     Node* n = previousSibling();
1365     while (n && !n->isElementNode())
1366         n = n->previousSibling();
1367     return static_cast<Element*>(n);
1368 }
1369 
nextElementSibling() const1370 Element* Element::nextElementSibling() const
1371 {
1372     Node* n = nextSibling();
1373     while (n && !n->isElementNode())
1374         n = n->nextSibling();
1375     return static_cast<Element*>(n);
1376 }
1377 
childElementCount() const1378 unsigned Element::childElementCount() const
1379 {
1380     unsigned count = 0;
1381     Node* n = firstChild();
1382     while (n) {
1383         count += n->isElementNode();
1384         n = n->nextSibling();
1385     }
1386     return count;
1387 }
1388 
getURLAttribute(const QualifiedName & name) const1389 KURL Element::getURLAttribute(const QualifiedName& name) const
1390 {
1391 #ifndef NDEBUG
1392     if (namedAttrMap) {
1393         if (Attribute* attribute = namedAttrMap->getAttributeItem(name))
1394             ASSERT(isURLAttribute(attribute));
1395     }
1396 #endif
1397     return document()->completeURL(getAttribute(name));
1398 }
1399 
1400 } // namespace WebCore
1401