• 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  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24 
25 #ifndef Element_h
26 #define Element_h
27 
28 #include "Document.h"
29 #include "FragmentScriptingPermission.h"
30 #include "NamedNodeMap.h"
31 #include "ScrollTypes.h"
32 
33 namespace WebCore {
34 
35 class Attribute;
36 class ClientRect;
37 class ClientRectList;
38 class DOMStringMap;
39 class DOMTokenList;
40 class ElementRareData;
41 class IntSize;
42 class WebKitAnimationList;
43 
44 enum SpellcheckAttributeState {
45     SpellcheckAttributeTrue,
46     SpellcheckAttributeFalse,
47     SpellcheckAttributeDefault
48 };
49 
50 class Element : public ContainerNode {
51 public:
52     static PassRefPtr<Element> create(const QualifiedName&, Document*);
53     virtual ~Element();
54 
55     DEFINE_ATTRIBUTE_EVENT_LISTENER(abort);
56     DEFINE_ATTRIBUTE_EVENT_LISTENER(change);
57     DEFINE_ATTRIBUTE_EVENT_LISTENER(click);
58     DEFINE_ATTRIBUTE_EVENT_LISTENER(contextmenu);
59     DEFINE_ATTRIBUTE_EVENT_LISTENER(dblclick);
60     DEFINE_ATTRIBUTE_EVENT_LISTENER(dragenter);
61     DEFINE_ATTRIBUTE_EVENT_LISTENER(dragover);
62     DEFINE_ATTRIBUTE_EVENT_LISTENER(dragleave);
63     DEFINE_ATTRIBUTE_EVENT_LISTENER(drop);
64     DEFINE_ATTRIBUTE_EVENT_LISTENER(dragstart);
65     DEFINE_ATTRIBUTE_EVENT_LISTENER(drag);
66     DEFINE_ATTRIBUTE_EVENT_LISTENER(dragend);
67     DEFINE_ATTRIBUTE_EVENT_LISTENER(input);
68     DEFINE_ATTRIBUTE_EVENT_LISTENER(invalid);
69     DEFINE_ATTRIBUTE_EVENT_LISTENER(keydown);
70     DEFINE_ATTRIBUTE_EVENT_LISTENER(keypress);
71     DEFINE_ATTRIBUTE_EVENT_LISTENER(keyup);
72     DEFINE_ATTRIBUTE_EVENT_LISTENER(mousedown);
73     DEFINE_ATTRIBUTE_EVENT_LISTENER(mousemove);
74     DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseout);
75     DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseover);
76     DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseup);
77     DEFINE_ATTRIBUTE_EVENT_LISTENER(mousewheel);
78     DEFINE_ATTRIBUTE_EVENT_LISTENER(scroll);
79     DEFINE_ATTRIBUTE_EVENT_LISTENER(select);
80     DEFINE_ATTRIBUTE_EVENT_LISTENER(submit);
81 
82     // These four attribute event handler attributes are overridden by HTMLBodyElement
83     // and HTMLFrameSetElement to forward to the DOMWindow.
84     DECLARE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(blur);
85     DECLARE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(error);
86     DECLARE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(focus);
87     DECLARE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(load);
88 
89     // WebKit extensions
90     DEFINE_ATTRIBUTE_EVENT_LISTENER(beforecut);
91     DEFINE_ATTRIBUTE_EVENT_LISTENER(cut);
92     DEFINE_ATTRIBUTE_EVENT_LISTENER(beforecopy);
93     DEFINE_ATTRIBUTE_EVENT_LISTENER(copy);
94     DEFINE_ATTRIBUTE_EVENT_LISTENER(beforepaste);
95     DEFINE_ATTRIBUTE_EVENT_LISTENER(paste);
96     DEFINE_ATTRIBUTE_EVENT_LISTENER(reset);
97     DEFINE_ATTRIBUTE_EVENT_LISTENER(search);
98     DEFINE_ATTRIBUTE_EVENT_LISTENER(selectstart);
99 #if ENABLE(TOUCH_EVENTS)
100     DEFINE_ATTRIBUTE_EVENT_LISTENER(touchstart);
101     DEFINE_ATTRIBUTE_EVENT_LISTENER(touchmove);
102     DEFINE_ATTRIBUTE_EVENT_LISTENER(touchend);
103     DEFINE_ATTRIBUTE_EVENT_LISTENER(touchcancel);
104 #endif
105 #if ENABLE(FULLSCREEN_API)
106     DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitfullscreenchange);
107 #endif
108 
109     virtual PassRefPtr<DocumentFragment> deprecatedCreateContextualFragment(const String&, FragmentScriptingPermission = FragmentScriptingAllowed);
110 
111     bool hasAttribute(const QualifiedName&) const;
112     const AtomicString& getAttribute(const QualifiedName&) const;
113     void setAttribute(const QualifiedName&, const AtomicString& value, ExceptionCode&);
114     void removeAttribute(const QualifiedName&, ExceptionCode&);
115 
116     // Typed getters and setters for language bindings.
117     int getIntegralAttribute(const QualifiedName& attributeName) const;
118     void setIntegralAttribute(const QualifiedName& attributeName, int value);
119     unsigned getUnsignedIntegralAttribute(const QualifiedName& attributeName) const;
120     void setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value);
121 
122     // Call this to get the value of an attribute that is known not to be the style
123     // attribute or one of the SVG animatable attributes.
124     bool fastHasAttribute(const QualifiedName&) const;
125     const AtomicString& fastGetAttribute(const QualifiedName&) const;
126 
127     bool hasAttributes() const;
128 
129     bool hasAttribute(const String& name) const;
130     bool hasAttributeNS(const String& namespaceURI, const String& localName) const;
131 
132     const AtomicString& getAttribute(const String& name) const;
133     const AtomicString& getAttributeNS(const String& namespaceURI, const String& localName) const;
134 
135     void setAttribute(const AtomicString& name, const AtomicString& value, ExceptionCode&);
136     void setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode&, FragmentScriptingPermission = FragmentScriptingAllowed);
137 
138     bool isIdAttributeName(const QualifiedName&) const;
139     const AtomicString& getIdAttribute() const;
140     void setIdAttribute(const AtomicString&);
141 
142     // Call this to get the value of the id attribute for style resolution purposes.
143     // The value will already be lowercased if the document is in compatibility mode,
144     // so this function is not suitable for non-style uses.
145     const AtomicString& idForStyleResolution() const;
146 
147     void scrollIntoView(bool alignToTop = true);
148     void scrollIntoViewIfNeeded(bool centerIfNeeded = true);
149 
150     void scrollByLines(int lines);
151     void scrollByPages(int pages);
152 
153     int offsetLeft();
154     int offsetTop();
155     int offsetWidth();
156     int offsetHeight();
157     Element* offsetParent();
158     int clientLeft();
159     int clientTop();
160     int clientWidth();
161     int clientHeight();
162     virtual int scrollLeft() const;
163     virtual int scrollTop() const;
164     virtual void setScrollLeft(int);
165     virtual void setScrollTop(int);
166     virtual int scrollWidth() const;
167     virtual int scrollHeight() const;
168 
169     IntRect boundsInWindowSpace() const;
170 
171     PassRefPtr<ClientRectList> getClientRects() const;
172     PassRefPtr<ClientRect> getBoundingClientRect() const;
173 
174     // Returns the absolute bounding box translated into screen coordinates:
175     IntRect screenRect() const;
176 
177     void removeAttribute(const String& name, ExceptionCode&);
178     void removeAttributeNS(const String& namespaceURI, const String& localName, ExceptionCode&);
179 
180     PassRefPtr<Attr> getAttributeNode(const String& name);
181     PassRefPtr<Attr> getAttributeNodeNS(const String& namespaceURI, const String& localName);
182     PassRefPtr<Attr> setAttributeNode(Attr*, ExceptionCode&);
183     PassRefPtr<Attr> setAttributeNodeNS(Attr*, ExceptionCode&);
184     PassRefPtr<Attr> removeAttributeNode(Attr*, ExceptionCode&);
185 
186     virtual CSSStyleDeclaration* style();
187 
tagQName()188     const QualifiedName& tagQName() const { return m_tagName; }
tagName()189     String tagName() const { return nodeName(); }
hasTagName(const QualifiedName & tagName)190     bool hasTagName(const QualifiedName& tagName) const { return m_tagName.matches(tagName); }
191 
192     // A fast function for checking the local name against another atomic string.
hasLocalName(const AtomicString & other)193     bool hasLocalName(const AtomicString& other) const { return m_tagName.localName() == other; }
hasLocalName(const QualifiedName & other)194     bool hasLocalName(const QualifiedName& other) const { return m_tagName.localName() == other.localName(); }
195 
localName()196     const AtomicString& localName() const { return m_tagName.localName(); }
prefix()197     const AtomicString& prefix() const { return m_tagName.prefix(); }
namespaceURI()198     const AtomicString& namespaceURI() const { return m_tagName.namespaceURI(); }
199 
200     virtual KURL baseURI() const;
201 
202     virtual String nodeName() const;
203 
204     PassRefPtr<Element> cloneElementWithChildren();
205     PassRefPtr<Element> cloneElementWithoutChildren();
206 
207     void normalizeAttributes();
208     String nodeNamePreservingCase() const;
209 
210     // convenience methods which ignore exceptions
211     void setAttribute(const QualifiedName&, const AtomicString& value);
212     void setBooleanAttribute(const QualifiedName& name, bool);
213     // Please don't use setCStringAttribute in performance-sensitive code;
214     // use a static AtomicString value instead to avoid the conversion overhead.
215     void setCStringAttribute(const QualifiedName&, const char* cStringValue);
216 
217     NamedNodeMap* attributes(bool readonly = false) const;
218 
219     // This method is called whenever an attribute is added, changed or removed.
220     virtual void attributeChanged(Attribute*, bool preserveDecls = false);
221 
222     void setAttributeMap(PassRefPtr<NamedNodeMap>, FragmentScriptingPermission = FragmentScriptingAllowed);
attributeMap()223     NamedNodeMap* attributeMap() const { return m_attributeMap.get(); }
224 
copyNonAttributeProperties(const Element *)225     virtual void copyNonAttributeProperties(const Element* /*source*/) { }
226 
227     virtual void attach();
228     virtual void detach();
229     virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
230     virtual void recalcStyle(StyleChange = NoChange);
231 
232     ContainerNode* shadowRoot() const;
233     ContainerNode* ensureShadowRoot();
234     void removeShadowRoot();
235 
236     virtual const AtomicString& shadowPseudoId() const;
237 
238     RenderStyle* computedStyle(PseudoId = NOPSEUDO);
239 
240     AtomicString computeInheritedLanguage() const;
241 
242     void dispatchAttrRemovalEvent(Attribute*);
243     void dispatchAttrAdditionEvent(Attribute*);
244 
accessKeyAction(bool)245     virtual void accessKeyAction(bool /*sendToAnyEvent*/) { }
246 
247     virtual bool isURLAttribute(Attribute*) const;
248 
249     KURL getURLAttribute(const QualifiedName&) const;
250     KURL getNonEmptyURLAttribute(const QualifiedName&) const;
251 
252     virtual const QualifiedName& imageSourceAttributeName() const;
target()253     virtual String target() const { return String(); }
254 
255     virtual void focus(bool restorePreviousSelection = true);
256     virtual void updateFocusAppearance(bool restorePreviousSelection);
257     void blur();
258 
259     String innerText() const;
260     String outerText() const;
261 
262     virtual String title() const;
263 
264     String openTagStartToString() const;
265 
266     void updateId(const AtomicString& oldId, const AtomicString& newId);
267 
268     IntSize minimumSizeForResizing() const;
269     void setMinimumSizeForResizing(const IntSize&);
270 
271     // Use Document::registerForDocumentActivationCallbacks() to subscribe to these
documentWillBecomeInactive()272     virtual void documentWillBecomeInactive() { }
documentDidBecomeActive()273     virtual void documentDidBecomeActive() { }
274 
275     // Use Document::registerForMediaVolumeCallbacks() to subscribe to this
mediaVolumeDidChange()276     virtual void mediaVolumeDidChange() { }
277 
278     // Use Document::registerForPrivateBrowsingStateChangedCallbacks() to subscribe to this.
privateBrowsingStateDidChange()279     virtual void privateBrowsingStateDidChange() { }
280 
isFinishedParsingChildren()281     bool isFinishedParsingChildren() const { return isParsingChildrenFinished(); }
282     virtual void finishParsingChildren();
283     virtual void beginParsingChildren();
284 
285     // ElementTraversal API
286     Element* firstElementChild() const;
287     Element* lastElementChild() const;
288     Element* previousElementSibling() const;
289     Element* nextElementSibling() const;
290     unsigned childElementCount() const;
291 
292     bool webkitMatchesSelector(const String& selectors, ExceptionCode&);
293 
294     DOMTokenList* classList();
295     DOMTokenList* optionalClassList() const;
296 
297     DOMStringMap* dataset();
298     DOMStringMap* optionalDataset() const;
299 
300 #if ENABLE(MATHML)
isMathMLElement()301     virtual bool isMathMLElement() const { return false; }
302 #else
isMathMLElement()303     static bool isMathMLElement() { return false; }
304 #endif
305 
306 #if ENABLE(INPUT_SPEECH)
isInputFieldSpeechButtonElement()307     virtual bool isInputFieldSpeechButtonElement() const { return false; }
308 #endif
309 
isFormControlElement()310     virtual bool isFormControlElement() const { return false; }
isEnabledFormControl()311     virtual bool isEnabledFormControl() const { return true; }
isReadOnlyFormControl()312     virtual bool isReadOnlyFormControl() const { return false; }
isSpinButtonElement()313     virtual bool isSpinButtonElement() const { return false; }
isTextFormControl()314     virtual bool isTextFormControl() const { return false; }
isOptionalFormControl()315     virtual bool isOptionalFormControl() const { return false; }
isRequiredFormControl()316     virtual bool isRequiredFormControl() const { return false; }
isDefaultButtonForForm()317     virtual bool isDefaultButtonForForm() const { return false; }
willValidate()318     virtual bool willValidate() const { return false; }
isValidFormControlElement()319     virtual bool isValidFormControlElement() { return false; }
hasUnacceptableValue()320     virtual bool hasUnacceptableValue() const { return false; }
isInRange()321     virtual bool isInRange() const { return false; }
isOutOfRange()322     virtual bool isOutOfRange() const { return false; }
323 
formControlValueMatchesRenderer()324     virtual bool formControlValueMatchesRenderer() const { return false; }
setFormControlValueMatchesRenderer(bool)325     virtual void setFormControlValueMatchesRenderer(bool) { }
326 
formControlName()327     virtual const AtomicString& formControlName() const { return nullAtom; }
formControlType()328     virtual const AtomicString& formControlType() const { return nullAtom; }
329 
shouldSaveAndRestoreFormControlState()330     virtual bool shouldSaveAndRestoreFormControlState() const { return true; }
saveFormControlState(String &)331     virtual bool saveFormControlState(String&) const { return false; }
restoreFormControlState(const String &)332     virtual void restoreFormControlState(const String&) { }
333 
334     virtual bool wasChangedSinceLastFormControlChangeEvent() const;
335     virtual void setChangedSinceLastFormControlChangeEvent(bool);
dispatchFormControlChangeEvent()336     virtual void dispatchFormControlChangeEvent() { }
337 
338 #if ENABLE(SVG)
339     virtual bool childShouldCreateRenderer(Node*) const;
340 #endif
341 
342 #if ENABLE(FULLSCREEN_API)
343     enum {
344         ALLOW_KEYBOARD_INPUT = 1
345     };
346 
347     void webkitRequestFullScreen(unsigned short flags);
348 #endif
349 
350     virtual bool isSpellCheckingEnabled() const;
351 
352     PassRefPtr<WebKitAnimationList> webkitGetAnimations() const;
353 
354 protected:
Element(const QualifiedName & tagName,Document * document,ConstructionType type)355     Element(const QualifiedName& tagName, Document* document, ConstructionType type)
356         : ContainerNode(document, type)
357         , m_tagName(tagName)
358     {
359     }
360 
361     virtual void insertedIntoDocument();
362     virtual void removedFromDocument();
363     virtual void insertedIntoTree(bool);
364     virtual void removedFromTree(bool);
365     virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
366 
367     // The implementation of Element::attributeChanged() calls the following two functions.
368     // They are separated to allow a different flow of control in StyledElement::attributeChanged().
369     void recalcStyleIfNeededAfterAttributeChanged(Attribute*);
370     void updateAfterAttributeChanged(Attribute*);
371 
372     void idAttributeChanged(Attribute*);
373 
374 private:
375     void scrollByUnits(int units, ScrollGranularity);
376 
377     virtual void setPrefix(const AtomicString&, ExceptionCode&);
378     virtual NodeType nodeType() const;
379     virtual bool childTypeAllowed(NodeType) const;
380 
381     virtual PassRefPtr<Attribute> createAttribute(const QualifiedName&, const AtomicString& value);
382 
383 #ifndef NDEBUG
384     virtual void formatForDebugger(char* buffer, unsigned length) const;
385 #endif
386 
387     bool pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle);
388 
389     void createAttributeMap() const;
390 
updateStyleAttribute()391     virtual void updateStyleAttribute() const { }
392 
393 #if ENABLE(SVG)
updateAnimatedSVGAttribute(const QualifiedName &)394     virtual void updateAnimatedSVGAttribute(const QualifiedName&) const { }
395 #endif
396 
397     void cancelFocusAppearanceUpdate();
398 
virtualPrefix()399     virtual const AtomicString& virtualPrefix() const { return prefix(); }
virtualLocalName()400     virtual const AtomicString& virtualLocalName() const { return localName(); }
virtualNamespaceURI()401     virtual const AtomicString& virtualNamespaceURI() const { return namespaceURI(); }
402     virtual RenderStyle* virtualComputedStyle(PseudoId pseudoElementSpecifier = NOPSEUDO) { return computedStyle(pseudoElementSpecifier); }
403 
404     // cloneNode is private so that non-virtual cloneElementWithChildren and cloneElementWithoutChildren
405     // are used instead.
406     virtual PassRefPtr<Node> cloneNode(bool deep);
407     virtual PassRefPtr<Element> cloneElementWithoutAttributesAndChildren() const;
408 
409     QualifiedName m_tagName;
410     virtual NodeRareData* createRareData();
411 
412     ElementRareData* rareData() const;
413     ElementRareData* ensureRareData();
414 
415     SpellcheckAttributeState spellcheckAttributeState() const;
416 
417 private:
418     mutable RefPtr<NamedNodeMap> m_attributeMap;
419 };
420 
toElement(Node * node)421 inline Element* toElement(Node* node)
422 {
423     ASSERT(!node || node->isElementNode());
424     return static_cast<Element*>(node);
425 }
426 
toElement(const Node * node)427 inline const Element* toElement(const Node* node)
428 {
429     ASSERT(!node || node->isElementNode());
430     return static_cast<const Element*>(node);
431 }
432 
433 // This will catch anyone doing an unnecessary cast.
434 void toElement(const Element*);
435 
hasTagName(const QualifiedName & name)436 inline bool Node::hasTagName(const QualifiedName& name) const
437 {
438     return isElementNode() && toElement(this)->hasTagName(name);
439 }
440 
hasLocalName(const AtomicString & name)441 inline bool Node::hasLocalName(const AtomicString& name) const
442 {
443     return isElementNode() && toElement(this)->hasLocalName(name);
444 }
445 
hasAttributes()446 inline bool Node::hasAttributes() const
447 {
448     return isElementNode() && toElement(this)->hasAttributes();
449 }
450 
attributes()451 inline NamedNodeMap* Node::attributes() const
452 {
453     return isElementNode() ? toElement(this)->attributes() : 0;
454 }
455 
parentElement()456 inline Element* Node::parentElement() const
457 {
458     ContainerNode* parent = parentNode();
459     return parent && parent->isElementNode() ? toElement(parent) : 0;
460 }
461 
attributes(bool readonly)462 inline NamedNodeMap* Element::attributes(bool readonly) const
463 {
464     if (!isStyleAttributeValid())
465         updateStyleAttribute();
466 
467 #if ENABLE(SVG)
468     if (!areSVGAttributesValid())
469         updateAnimatedSVGAttribute(anyQName());
470 #endif
471 
472     if (!readonly && !m_attributeMap)
473         createAttributeMap();
474     return m_attributeMap.get();
475 }
476 
updateId(const AtomicString & oldId,const AtomicString & newId)477 inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
478 {
479     if (!inDocument())
480         return;
481 
482     if (oldId == newId)
483         return;
484 
485     Document* doc = document();
486     if (!oldId.isEmpty())
487         doc->removeElementById(oldId, this);
488     if (!newId.isEmpty())
489         doc->addElementById(newId, this);
490 }
491 
fastHasAttribute(const QualifiedName & name)492 inline bool Element::fastHasAttribute(const QualifiedName& name) const
493 {
494     return m_attributeMap && m_attributeMap->getAttributeItem(name);
495 }
496 
fastGetAttribute(const QualifiedName & name)497 inline const AtomicString& Element::fastGetAttribute(const QualifiedName& name) const
498 {
499     if (m_attributeMap) {
500         if (Attribute* attribute = m_attributeMap->getAttributeItem(name))
501             return attribute->value();
502     }
503     return nullAtom;
504 }
505 
idForStyleResolution()506 inline const AtomicString& Element::idForStyleResolution() const
507 {
508     ASSERT(hasID());
509     return m_attributeMap->idForStyleResolution();
510 }
511 
isIdAttributeName(const QualifiedName & attributeName)512 inline bool Element::isIdAttributeName(const QualifiedName& attributeName) const
513 {
514     // FIXME: This check is probably not correct for the case where the document has an id attribute
515     // with a non-null namespace, because it will return false, a false negative, if the prefixes
516     // don't match but the local name and namespace both do. However, since this has been like this
517     // for a while and the code paths may be hot, we'll have to measure performance if we fix it.
518     return attributeName == document()->idAttributeName();
519 }
520 
getIdAttribute()521 inline const AtomicString& Element::getIdAttribute() const
522 {
523     return fastGetAttribute(document()->idAttributeName());
524 }
525 
setIdAttribute(const AtomicString & value)526 inline void Element::setIdAttribute(const AtomicString& value)
527 {
528     setAttribute(document()->idAttributeName(), value);
529 }
530 
shadowPseudoId()531 inline const AtomicString& Element::shadowPseudoId() const
532 {
533     return nullAtom;
534 }
535 
firstElementChild(const ContainerNode * container)536 inline Element* firstElementChild(const ContainerNode* container)
537 {
538     ASSERT_ARG(container, container);
539     Node* child = container->firstChild();
540     while (child && !child->isElementNode())
541         child = child->nextSibling();
542     return static_cast<Element*>(child);
543 }
544 
545 } // namespace
546 
547 #endif
548