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