Implement undoscope attribute.
[WebKit-https.git] / Source / WebCore / dom / Element.h
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 "CollectionType.h"
29 #include "Document.h"
30 #include "ElementAttributeData.h"
31 #include "FragmentScriptingPermission.h"
32 #include "HTMLNames.h"
33 #include "ScrollTypes.h"
34
35 namespace WebCore {
36
37 class Attribute;
38 class ClientRect;
39 class ClientRectList;
40 class DOMStringMap;
41 class DOMTokenList;
42 class ElementRareData;
43 class IntSize;
44 class ShadowRoot;
45 class ElementShadow;
46 class WebKitAnimationList;
47
48 enum SpellcheckAttributeState {
49     SpellcheckAttributeTrue,
50     SpellcheckAttributeFalse,
51     SpellcheckAttributeDefault
52 };
53
54 class Element : public ContainerNode {
55 public:
56     static PassRefPtr<Element> create(const QualifiedName&, Document*);
57     virtual ~Element();
58
59     DEFINE_ATTRIBUTE_EVENT_LISTENER(abort);
60     DEFINE_ATTRIBUTE_EVENT_LISTENER(change);
61     DEFINE_ATTRIBUTE_EVENT_LISTENER(click);
62     DEFINE_ATTRIBUTE_EVENT_LISTENER(contextmenu);
63     DEFINE_ATTRIBUTE_EVENT_LISTENER(dblclick);
64     DEFINE_ATTRIBUTE_EVENT_LISTENER(dragenter);
65     DEFINE_ATTRIBUTE_EVENT_LISTENER(dragover);
66     DEFINE_ATTRIBUTE_EVENT_LISTENER(dragleave);
67     DEFINE_ATTRIBUTE_EVENT_LISTENER(drop);
68     DEFINE_ATTRIBUTE_EVENT_LISTENER(dragstart);
69     DEFINE_ATTRIBUTE_EVENT_LISTENER(drag);
70     DEFINE_ATTRIBUTE_EVENT_LISTENER(dragend);
71     DEFINE_ATTRIBUTE_EVENT_LISTENER(input);
72     DEFINE_ATTRIBUTE_EVENT_LISTENER(invalid);
73     DEFINE_ATTRIBUTE_EVENT_LISTENER(keydown);
74     DEFINE_ATTRIBUTE_EVENT_LISTENER(keypress);
75     DEFINE_ATTRIBUTE_EVENT_LISTENER(keyup);
76     DEFINE_ATTRIBUTE_EVENT_LISTENER(mousedown);
77     DEFINE_ATTRIBUTE_EVENT_LISTENER(mousemove);
78     DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseout);
79     DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseover);
80     DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseup);
81     DEFINE_ATTRIBUTE_EVENT_LISTENER(mousewheel);
82     DEFINE_ATTRIBUTE_EVENT_LISTENER(scroll);
83     DEFINE_ATTRIBUTE_EVENT_LISTENER(select);
84     DEFINE_ATTRIBUTE_EVENT_LISTENER(submit);
85
86     // These four attribute event handler attributes are overridden by HTMLBodyElement
87     // and HTMLFrameSetElement to forward to the DOMWindow.
88     DECLARE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(blur);
89     DECLARE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(error);
90     DECLARE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(focus);
91     DECLARE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(load);
92
93     // WebKit extensions
94     DEFINE_ATTRIBUTE_EVENT_LISTENER(beforecut);
95     DEFINE_ATTRIBUTE_EVENT_LISTENER(cut);
96     DEFINE_ATTRIBUTE_EVENT_LISTENER(beforecopy);
97     DEFINE_ATTRIBUTE_EVENT_LISTENER(copy);
98     DEFINE_ATTRIBUTE_EVENT_LISTENER(beforepaste);
99     DEFINE_ATTRIBUTE_EVENT_LISTENER(paste);
100     DEFINE_ATTRIBUTE_EVENT_LISTENER(reset);
101     DEFINE_ATTRIBUTE_EVENT_LISTENER(search);
102     DEFINE_ATTRIBUTE_EVENT_LISTENER(selectstart);
103 #if ENABLE(TOUCH_EVENTS)
104     DEFINE_ATTRIBUTE_EVENT_LISTENER(touchstart);
105     DEFINE_ATTRIBUTE_EVENT_LISTENER(touchmove);
106     DEFINE_ATTRIBUTE_EVENT_LISTENER(touchend);
107     DEFINE_ATTRIBUTE_EVENT_LISTENER(touchcancel);
108 #endif
109 #if ENABLE(FULLSCREEN_API)
110     DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitfullscreenchange);
111     DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitfullscreenerror);
112 #endif
113
114     bool hasAttribute(const QualifiedName&) const;
115     const AtomicString& getAttribute(const QualifiedName&) const;
116     void setAttribute(const QualifiedName&, const AtomicString& value, EInUpdateStyleAttribute = NotInUpdateStyleAttribute);
117     void removeAttribute(const QualifiedName&);
118     void removeAttribute(size_t index);
119
120     // Typed getters and setters for language bindings.
121     int getIntegralAttribute(const QualifiedName& attributeName) const;
122     void setIntegralAttribute(const QualifiedName& attributeName, int value);
123     unsigned getUnsignedIntegralAttribute(const QualifiedName& attributeName) const;
124     void setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value);
125
126     // Call this to get the value of an attribute that is known not to be the style
127     // attribute or one of the SVG animatable attributes.
128     bool fastHasAttribute(const QualifiedName&) const;
129     const AtomicString& fastGetAttribute(const QualifiedName&) const;
130 #ifndef NDEBUG
131     bool fastAttributeLookupAllowed(const QualifiedName&) const;
132 #endif
133
134 #ifdef DUMP_NODE_STATISTICS
135     bool hasNamedNodeMap() const;
136 #endif
137     bool hasAttributes() const;
138     // This variant will not update the potentially invalid attributes. To be used when not interested
139     // in style attribute or one of the SVG animation attributes.
140     bool hasAttributesWithoutUpdate() const;
141
142     bool hasAttribute(const String& name) const;
143     bool hasAttributeNS(const String& namespaceURI, const String& localName) const;
144
145     const AtomicString& getAttribute(const AtomicString& name) const;
146     const AtomicString& getAttributeNS(const String& namespaceURI, const String& localName) const;
147
148     void setAttribute(const AtomicString& name, const AtomicString& value, ExceptionCode&);
149     static bool parseAttributeName(QualifiedName&, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionCode&);
150     void setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode&);
151
152     bool isIdAttributeName(const QualifiedName&) const;
153     const AtomicString& getIdAttribute() const;
154     void setIdAttribute(const AtomicString&);
155
156     const AtomicString& getNameAttribute() const;
157
158     // Call this to get the value of the id attribute for style resolution purposes.
159     // The value will already be lowercased if the document is in compatibility mode,
160     // so this function is not suitable for non-style uses.
161     const AtomicString& idForStyleResolution() const;
162
163     // Internal methods that assume the existence of attribute storage, one should use hasAttributes()
164     // before calling them.
165     size_t attributeCount() const;
166     const Attribute* attributeItem(unsigned index) const;
167     const Attribute* getAttributeItem(const QualifiedName&) const;
168     Attribute* getAttributeItem(const QualifiedName&);
169     size_t getAttributeItemIndex(const QualifiedName& name) const { return attributeData()->getAttributeItemIndex(name); }
170     size_t getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const { return attributeData()->getAttributeItemIndex(name, shouldIgnoreAttributeCase); }
171
172     void scrollIntoView(bool alignToTop = true);
173     void scrollIntoViewIfNeeded(bool centerIfNeeded = true);
174
175     void scrollByLines(int lines);
176     void scrollByPages(int pages);
177
178     int offsetLeft();
179     int offsetTop();
180     int offsetWidth();
181     int offsetHeight();
182     Element* offsetParent();
183     int clientLeft();
184     int clientTop();
185     int clientWidth();
186     int clientHeight();
187     virtual int scrollLeft();
188     virtual int scrollTop();
189     virtual void setScrollLeft(int);
190     virtual void setScrollTop(int);
191     virtual int scrollWidth();
192     virtual int scrollHeight();
193
194     IntRect boundsInRootViewSpace();
195
196     PassRefPtr<ClientRectList> getClientRects();
197     PassRefPtr<ClientRect> getBoundingClientRect();
198     
199     // Returns the absolute bounding box translated into screen coordinates:
200     IntRect screenRect() const;
201
202     void removeAttribute(const String& name);
203     void removeAttributeNS(const String& namespaceURI, const String& localName);
204
205     PassRefPtr<Attr> detachAttribute(size_t index);
206
207     PassRefPtr<Attr> getAttributeNode(const String& name);
208     PassRefPtr<Attr> getAttributeNodeNS(const String& namespaceURI, const String& localName);
209     PassRefPtr<Attr> setAttributeNode(Attr*, ExceptionCode&);
210     PassRefPtr<Attr> setAttributeNodeNS(Attr*, ExceptionCode&);
211     PassRefPtr<Attr> removeAttributeNode(Attr*, ExceptionCode&);
212
213     PassRefPtr<Attr> attrIfExists(const QualifiedName&);
214     PassRefPtr<Attr> ensureAttr(const QualifiedName&);
215     
216     virtual CSSStyleDeclaration* style();
217
218     const QualifiedName& tagQName() const { return m_tagName; }
219     String tagName() const { return nodeName(); }
220     bool hasTagName(const QualifiedName& tagName) const { return m_tagName.matches(tagName); }
221     
222     // A fast function for checking the local name against another atomic string.
223     bool hasLocalName(const AtomicString& other) const { return m_tagName.localName() == other; }
224     bool hasLocalName(const QualifiedName& other) const { return m_tagName.localName() == other.localName(); }
225
226     const AtomicString& localName() const { return m_tagName.localName(); }
227     const AtomicString& prefix() const { return m_tagName.prefix(); }
228     const AtomicString& namespaceURI() const { return m_tagName.namespaceURI(); }
229
230     virtual KURL baseURI() const;
231
232     virtual String nodeName() const;
233
234     PassRefPtr<Element> cloneElementWithChildren();
235     PassRefPtr<Element> cloneElementWithoutChildren();
236
237     void normalizeAttributes();
238     String nodeNamePreservingCase() const;
239
240     void setBooleanAttribute(const QualifiedName& name, bool);
241
242     // For exposing to DOM only.
243     NamedNodeMap* attributes() const;
244
245     // This method is called whenever an attribute is added, changed or removed.
246     virtual void attributeChanged(const Attribute&);
247
248     // Only called by the parser immediately after element construction.
249     void parserSetAttributes(const Vector<Attribute>&, FragmentScriptingPermission);
250
251     const ElementAttributeData* attributeData() const { return m_attributeData.get(); }
252     ElementAttributeData* mutableAttributeData();
253     const ElementAttributeData* ensureAttributeData();
254     const ElementAttributeData* updatedAttributeData() const;
255     const ElementAttributeData* ensureUpdatedAttributeData() const;
256
257     // Clones attributes only.
258     void cloneAttributesFromElement(const Element&);
259
260     // Clones all attribute-derived data, including subclass specifics (through copyNonAttributeProperties.)
261     void cloneDataFromElement(const Element&);
262
263     bool hasEquivalentAttributes(const Element* other) const;
264
265     virtual void copyNonAttributePropertiesFromElement(const Element&) { }
266
267     virtual void attach();
268     virtual void detach();
269     virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
270     void recalcStyle(StyleChange = NoChange);
271
272     ElementShadow* shadow() const;
273     ElementShadow* ensureShadow();
274     virtual void willAddAuthorShadowRoot() { }
275
276     ShadowRoot* userAgentShadowRoot() const;
277
278     // FIXME: Remove Element::ensureShadowRoot
279     // https://bugs.webkit.org/show_bug.cgi?id=77608
280     ShadowRoot* ensureShadowRoot();
281
282     virtual const AtomicString& shadowPseudoId() const;
283     void setShadowPseudoId(const AtomicString&, ExceptionCode& = ASSERT_NO_EXCEPTION);
284
285     RenderStyle* computedStyle(PseudoId = NOPSEUDO);
286
287     void setStyleAffectedByEmpty();
288     bool styleAffectedByEmpty() const;
289
290     void setIsInCanvasSubtree(bool);
291     bool isInCanvasSubtree() const;
292
293     AtomicString computeInheritedLanguage() const;
294
295     virtual void accessKeyAction(bool /*sendToAnyEvent*/) { }
296
297     virtual bool isURLAttribute(const Attribute&) const { return false; }
298
299     KURL getURLAttribute(const QualifiedName&) const;
300     KURL getNonEmptyURLAttribute(const QualifiedName&) const;
301
302     virtual const QualifiedName& imageSourceAttributeName() const;
303     virtual String target() const { return String(); }
304
305     virtual void focus(bool restorePreviousSelection = true);
306     virtual void updateFocusAppearance(bool restorePreviousSelection);
307     void blur();
308
309     String innerText();
310     String outerText();
311  
312     virtual String title() const;
313
314     void updateId(const AtomicString& oldId, const AtomicString& newId);
315     void updateId(TreeScope*, const AtomicString& oldId, const AtomicString& newId);
316     void updateName(const AtomicString& oldName, const AtomicString& newName);
317
318     void willModifyAttribute(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue);
319     void willRemoveAttribute(const QualifiedName&, const AtomicString& value);
320     void didAddAttribute(const Attribute&);
321     void didModifyAttribute(const Attribute&);
322     void didRemoveAttribute(const QualifiedName&);
323
324     void removeCachedHTMLCollection(HTMLCollection*, CollectionType);
325
326     LayoutSize minimumSizeForResizing() const;
327     void setMinimumSizeForResizing(const LayoutSize&);
328
329     // Use Document::registerForDocumentActivationCallbacks() to subscribe to these
330     virtual void documentWillSuspendForPageCache() { }
331     virtual void documentDidResumeFromPageCache() { }
332
333     // Use Document::registerForMediaVolumeCallbacks() to subscribe to this
334     virtual void mediaVolumeDidChange() { }
335
336     // Use Document::registerForPrivateBrowsingStateChangedCallbacks() to subscribe to this.
337     virtual void privateBrowsingStateDidChange() { }
338
339     virtual void didBecomeFullscreenElement() { }
340     virtual void willStopBeingFullscreenElement() { }
341
342     bool isFinishedParsingChildren() const { return isParsingChildrenFinished(); }
343     virtual void finishParsingChildren();
344     virtual void beginParsingChildren();
345
346     // ElementTraversal API
347     Element* firstElementChild() const;
348     Element* lastElementChild() const;
349     Element* previousElementSibling() const;
350     Element* nextElementSibling() const;
351     unsigned childElementCount() const;
352
353     bool webkitMatchesSelector(const String& selectors, ExceptionCode&);
354
355     DOMTokenList* classList();
356     DOMTokenList* optionalClassList() const;
357
358     DOMStringMap* dataset();
359
360 #if ENABLE(MATHML)
361     virtual bool isMathMLElement() const { return false; }
362 #else
363     static bool isMathMLElement() { return false; }
364 #endif
365
366 #if ENABLE(VIDEO)
367     virtual bool isMediaElement() const { return false; }
368 #endif
369
370 #if ENABLE(INPUT_SPEECH)
371     virtual bool isInputFieldSpeechButtonElement() const { return false; }
372 #endif
373
374     virtual bool isFormControlElement() const { return false; }
375     virtual bool isEnabledFormControl() const { return true; }
376     virtual bool isReadOnlyFormControl() const { return false; }
377     virtual bool isSpinButtonElement() const { return false; }
378     virtual bool isTextFormControl() const { return false; }
379     virtual bool isOptionalFormControl() const { return false; }
380     virtual bool isRequiredFormControl() const { return false; }
381     virtual bool isDefaultButtonForForm() const { return false; }
382     virtual bool willValidate() const { return false; }
383     virtual bool isValidFormControlElement() { return false; }
384     virtual bool hasUnacceptableValue() const { return false; }
385     virtual bool isInRange() const { return false; }
386     virtual bool isOutOfRange() const { return false; }
387     virtual bool isFrameElementBase() const { return false; }
388     virtual bool isTextFieldDecoration() const { return false; }
389
390     virtual bool canContainRangeEndPoint() const { return true; }
391
392     virtual const AtomicString& formControlType() const { return nullAtom; }
393
394     virtual bool wasChangedSinceLastFormControlChangeEvent() const;
395     virtual void setChangedSinceLastFormControlChangeEvent(bool);
396     virtual void dispatchFormControlChangeEvent() { }
397
398 #if ENABLE(SVG)
399     virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const;
400 #endif
401     
402 #if ENABLE(FULLSCREEN_API)
403     enum {
404         ALLOW_KEYBOARD_INPUT = 1 << 0,
405         LEGACY_MOZILLA_REQUEST = 1 << 1,
406     };
407     
408     void webkitRequestFullScreen(unsigned short flags);
409     virtual bool containsFullScreenElement() const;
410     virtual void setContainsFullScreenElement(bool);
411     virtual void setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool);
412
413     // W3C API
414     void webkitRequestFullscreen();
415 #endif
416
417 #if ENABLE(POINTER_LOCK)
418     void webkitRequestPointerLock();
419 #endif
420
421     virtual bool isSpellCheckingEnabled() const;
422
423     PassRefPtr<WebKitAnimationList> webkitGetAnimations() const;
424     
425     PassRefPtr<RenderStyle> styleForRenderer();
426
427     const AtomicString& webkitRegionOverflow() const;
428
429     bool hasID() const;
430     bool hasClass() const;
431
432     IntSize savedLayerScrollOffset() const;
433     void setSavedLayerScrollOffset(const IntSize&);
434
435     virtual void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const
436     {
437         MemoryClassInfo<Element> info(memoryObjectInfo, this, MemoryInstrumentation::DOM);
438         info.visitBaseClass<ContainerNode>(this);
439         info.addInstrumentedMember(m_tagName);
440         info.addInstrumentedMember(attributeData());
441     }
442
443 #if ENABLE(UNDO_MANAGER)
444     bool undoScope() const;
445     void setUndoScope(bool);
446     PassRefPtr<UndoManager> undoManager();
447     void disconnectUndoManager();
448     void disconnectUndoManagersInSubtree();
449 #endif
450
451 protected:
452     Element(const QualifiedName& tagName, Document* document, ConstructionType type)
453         : ContainerNode(document, type)
454         , m_tagName(tagName)
455     {
456     }
457
458     virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
459     virtual void removedFrom(ContainerNode*) OVERRIDE;
460     virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
461
462     virtual bool willRecalcStyle(StyleChange);
463     virtual void didRecalcStyle(StyleChange);
464     virtual PassRefPtr<RenderStyle> customStyleForRenderer();
465
466     virtual bool shouldRegisterAsNamedItem() const { return false; }
467     virtual bool shouldRegisterAsExtraNamedItem() const { return false; }
468
469     PassRefPtr<HTMLCollection> ensureCachedHTMLCollection(CollectionType);
470     HTMLCollection* cachedHTMLCollection(CollectionType);
471
472 private:
473     void updateInvalidAttributes() const;
474
475     void scrollByUnits(int units, ScrollGranularity);
476
477     virtual void setPrefix(const AtomicString&, ExceptionCode&);
478     virtual NodeType nodeType() const;
479     virtual bool childTypeAllowed(NodeType) const;
480
481     void setAttributeInternal(size_t index, const QualifiedName&, const AtomicString& value, EInUpdateStyleAttribute);
482
483 #ifndef NDEBUG
484     virtual void formatForDebugger(char* buffer, unsigned length) const;
485 #endif
486
487     bool pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle);
488
489     virtual void updateStyleAttribute() const { }
490
491 #if ENABLE(SVG)
492     virtual void updateAnimatedSVGAttribute(const QualifiedName&) const { }
493 #endif
494
495     void cancelFocusAppearanceUpdate();
496
497     virtual const AtomicString& virtualPrefix() const { return prefix(); }
498     virtual const AtomicString& virtualLocalName() const { return localName(); }
499     virtual const AtomicString& virtualNamespaceURI() const { return namespaceURI(); }
500     virtual RenderStyle* virtualComputedStyle(PseudoId pseudoElementSpecifier = NOPSEUDO) { return computedStyle(pseudoElementSpecifier); }
501     
502     // cloneNode is private so that non-virtual cloneElementWithChildren and cloneElementWithoutChildren
503     // are used instead.
504     virtual PassRefPtr<Node> cloneNode(bool deep);
505     virtual PassRefPtr<Element> cloneElementWithoutAttributesAndChildren();
506
507     QualifiedName m_tagName;
508     virtual OwnPtr<NodeRareData> createRareData();
509
510     SpellcheckAttributeState spellcheckAttributeState() const;
511
512     void updateNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName);
513     void updateExtraNamedItemRegistration(const AtomicString& oldName, const AtomicString& newName);
514
515     void unregisterNamedFlowContentNode();
516
517     void createMutableAttributeData();
518
519 private:
520     ElementRareData* elementRareData() const;
521     ElementRareData* ensureElementRareData();
522
523     OwnPtr<ElementAttributeData> m_attributeData;
524 };
525     
526 inline Element* toElement(Node* node)
527 {
528     ASSERT(!node || node->isElementNode());
529     return static_cast<Element*>(node);
530 }
531
532 inline const Element* toElement(const Node* node)
533 {
534     ASSERT(!node || node->isElementNode());
535     return static_cast<const Element*>(node);
536 }
537
538 // This will catch anyone doing an unnecessary cast.
539 void toElement(const Element*);
540
541 inline bool Node::hasTagName(const QualifiedName& name) const
542 {
543     return isElementNode() && toElement(this)->hasTagName(name);
544 }
545     
546 inline bool Node::hasLocalName(const AtomicString& name) const
547 {
548     return isElementNode() && toElement(this)->hasLocalName(name);
549 }
550
551 inline bool Node::hasAttributes() const
552 {
553     return isElementNode() && toElement(this)->hasAttributes();
554 }
555
556 inline NamedNodeMap* Node::attributes() const
557 {
558     return isElementNode() ? toElement(this)->attributes() : 0;
559 }
560
561 inline Element* Node::parentElement() const
562 {
563     ContainerNode* parent = parentNode();
564     return parent && parent->isElementNode() ? toElement(parent) : 0;
565 }
566
567 inline Element* Element::previousElementSibling() const
568 {
569     Node* n = previousSibling();
570     while (n && !n->isElementNode())
571         n = n->previousSibling();
572     return static_cast<Element*>(n);
573 }
574
575 inline Element* Element::nextElementSibling() const
576 {
577     Node* n = nextSibling();
578     while (n && !n->isElementNode())
579         n = n->nextSibling();
580     return static_cast<Element*>(n);
581 }
582
583 inline const ElementAttributeData* Element::updatedAttributeData() const
584 {
585     updateInvalidAttributes();
586     return attributeData();
587 }
588
589 inline const ElementAttributeData* Element::ensureAttributeData()
590 {
591     if (attributeData())
592         return attributeData();
593     return mutableAttributeData();
594 }
595
596 inline const ElementAttributeData* Element::ensureUpdatedAttributeData() const
597 {
598     updateInvalidAttributes();
599     if (attributeData())
600         return attributeData();
601     return const_cast<Element*>(this)->mutableAttributeData();
602 }
603
604 inline void Element::updateName(const AtomicString& oldName, const AtomicString& newName)
605 {
606     if (!inDocument())
607         return;
608
609     if (oldName == newName)
610         return;
611
612     if (shouldRegisterAsNamedItem())
613         updateNamedItemRegistration(oldName, newName);
614 }
615
616 inline void Element::updateId(const AtomicString& oldId, const AtomicString& newId)
617 {
618     if (!inDocument())
619         return;
620
621     if (oldId == newId)
622         return;
623
624     updateId(treeScope(), oldId, newId);
625 }
626
627 inline void Element::updateId(TreeScope* scope, const AtomicString& oldId, const AtomicString& newId)
628 {
629     ASSERT(inDocument());
630     ASSERT(oldId != newId);
631
632     if (!oldId.isEmpty())
633         scope->removeElementById(oldId, this);
634     if (!newId.isEmpty())
635         scope->addElementById(newId, this);
636
637     if (shouldRegisterAsExtraNamedItem())
638         updateExtraNamedItemRegistration(oldId, newId);
639 }
640
641 inline void Element::willRemoveAttribute(const QualifiedName& name, const AtomicString& value)
642 {
643     if (!value.isNull())
644         willModifyAttribute(name, value, nullAtom);
645 }
646
647 inline bool Element::fastHasAttribute(const QualifiedName& name) const
648 {
649     ASSERT(fastAttributeLookupAllowed(name));
650     return attributeData() && getAttributeItem(name);
651 }
652
653 inline const AtomicString& Element::fastGetAttribute(const QualifiedName& name) const
654 {
655     ASSERT(fastAttributeLookupAllowed(name));
656     if (attributeData()) {
657         if (const Attribute* attribute = getAttributeItem(name))
658             return attribute->value();
659     }
660     return nullAtom;
661 }
662
663 inline bool Element::hasAttributesWithoutUpdate() const
664 {
665     return attributeData() && !attributeData()->isEmpty();
666 }
667
668 inline const AtomicString& Element::idForStyleResolution() const
669 {
670     ASSERT(hasID());
671     return attributeData()->idForStyleResolution();
672 }
673
674 inline bool Element::isIdAttributeName(const QualifiedName& attributeName) const
675 {
676     // FIXME: This check is probably not correct for the case where the document has an id attribute
677     // with a non-null namespace, because it will return false, a false negative, if the prefixes
678     // don't match but the local name and namespace both do. However, since this has been like this
679     // for a while and the code paths may be hot, we'll have to measure performance if we fix it.
680     return attributeName == document()->idAttributeName();
681 }
682
683 inline const AtomicString& Element::getIdAttribute() const
684 {
685     return hasID() ? fastGetAttribute(document()->idAttributeName()) : nullAtom;
686 }
687
688 inline const AtomicString& Element::getNameAttribute() const
689 {
690     return hasName() ? fastGetAttribute(HTMLNames::nameAttr) : nullAtom;
691 }
692
693 inline void Element::setIdAttribute(const AtomicString& value)
694 {
695     setAttribute(document()->idAttributeName(), value);
696 }
697
698 inline size_t Element::attributeCount() const
699 {
700     ASSERT(attributeData());
701     return attributeData()->length();
702 }
703
704 inline const Attribute* Element::attributeItem(unsigned index) const
705 {
706     ASSERT(attributeData());
707     return attributeData()->attributeItem(index);
708 }
709
710 inline const Attribute* Element::getAttributeItem(const QualifiedName& name) const
711 {
712     ASSERT(attributeData());
713     return attributeData()->getAttributeItem(name);
714 }
715
716 inline Attribute* Element::getAttributeItem(const QualifiedName& name)
717 {
718     ASSERT(attributeData());
719     return mutableAttributeData()->getAttributeItem(name);
720 }
721
722 inline void Element::updateInvalidAttributes() const
723 {
724     if (!isStyleAttributeValid())
725         updateStyleAttribute();
726
727 #if ENABLE(SVG)
728     if (!areSVGAttributesValid())
729         updateAnimatedSVGAttribute(anyQName());
730 #endif
731 }
732
733 inline Element* firstElementChild(const ContainerNode* container)
734 {
735     ASSERT_ARG(container, container);
736     Node* child = container->firstChild();
737     while (child && !child->isElementNode())
738         child = child->nextSibling();
739     return static_cast<Element*>(child);
740 }
741
742 inline bool Element::hasID() const
743 {
744     return attributeData() && attributeData()->hasID();
745 }
746
747 inline bool Element::hasClass() const
748 {
749     return attributeData() && attributeData()->hasClass();
750 }
751
752 inline ElementAttributeData* Element::mutableAttributeData()
753 {
754     if (!attributeData() || !attributeData()->isMutable())
755         createMutableAttributeData();
756     return m_attributeData.get();
757 }
758
759 // Put here to make them inline.
760 inline bool Node::hasID() const
761 {
762     return isElementNode() && toElement(this)->hasID();
763 }
764
765 inline bool Node::hasClass() const
766 {
767     return isElementNode() && toElement(this)->hasClass();
768 }
769
770 inline bool isShadowHost(const Node* node)
771 {
772     return node && node->isElementNode() && toElement(node)->shadow();
773 }
774
775 } // namespace
776
777 #endif