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