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
33namespace WebCore {
34
35class Attribute;
36class ClientRect;
37class ClientRectList;
38class DOMStringMap;
39class DOMTokenList;
40class ElementRareData;
41class IntSize;
42class WebKitAnimationList;
43
44enum SpellcheckAttributeState {
45    SpellcheckAttributeTrue,
46    SpellcheckAttributeFalse,
47    SpellcheckAttributeDefault
48};
49
50class Element : public ContainerNode {
51public:
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
188    const QualifiedName& tagQName() const { return m_tagName; }
189    String tagName() const { return nodeName(); }
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.
193    bool hasLocalName(const AtomicString& other) const { return m_tagName.localName() == other; }
194    bool hasLocalName(const QualifiedName& other) const { return m_tagName.localName() == other.localName(); }
195
196    const AtomicString& localName() const { return m_tagName.localName(); }
197    const AtomicString& prefix() const { return m_tagName.prefix(); }
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);
223    NamedNodeMap* attributeMap() const { return m_attributeMap.get(); }
224
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
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;
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
272    virtual void documentWillBecomeInactive() { }
273    virtual void documentDidBecomeActive() { }
274
275    // Use Document::registerForMediaVolumeCallbacks() to subscribe to this
276    virtual void mediaVolumeDidChange() { }
277
278    // Use Document::registerForPrivateBrowsingStateChangedCallbacks() to subscribe to this.
279    virtual void privateBrowsingStateDidChange() { }
280
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)
301    virtual bool isMathMLElement() const { return false; }
302#else
303    static bool isMathMLElement() { return false; }
304#endif
305
306#if ENABLE(INPUT_SPEECH)
307    virtual bool isInputFieldSpeechButtonElement() const { return false; }
308#endif
309
310    virtual bool isFormControlElement() const { return false; }
311    virtual bool isEnabledFormControl() const { return true; }
312    virtual bool isReadOnlyFormControl() const { return false; }
313    virtual bool isSpinButtonElement() const { return false; }
314    virtual bool isTextFormControl() const { return false; }
315    virtual bool isOptionalFormControl() const { return false; }
316    virtual bool isRequiredFormControl() const { return false; }
317    virtual bool isDefaultButtonForForm() const { return false; }
318    virtual bool willValidate() const { return false; }
319    virtual bool isValidFormControlElement() { return false; }
320    virtual bool hasUnacceptableValue() const { return false; }
321    virtual bool isInRange() const { return false; }
322    virtual bool isOutOfRange() const { return false; }
323
324    virtual bool formControlValueMatchesRenderer() const { return false; }
325    virtual void setFormControlValueMatchesRenderer(bool) { }
326
327    virtual const AtomicString& formControlName() const { return nullAtom; }
328    virtual const AtomicString& formControlType() const { return nullAtom; }
329
330    virtual bool shouldSaveAndRestoreFormControlState() const { return true; }
331    virtual bool saveFormControlState(String&) const { return false; }
332    virtual void restoreFormControlState(const String&) { }
333
334    virtual bool wasChangedSinceLastFormControlChangeEvent() const;
335    virtual void setChangedSinceLastFormControlChangeEvent(bool);
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
354protected:
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
374private:
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
391    virtual void updateStyleAttribute() const { }
392
393#if ENABLE(SVG)
394    virtual void updateAnimatedSVGAttribute(const QualifiedName&) const { }
395#endif
396
397    void cancelFocusAppearanceUpdate();
398
399    virtual const AtomicString& virtualPrefix() const { return prefix(); }
400    virtual const AtomicString& virtualLocalName() const { return localName(); }
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
417private:
418    mutable RefPtr<NamedNodeMap> m_attributeMap;
419};
420
421inline Element* toElement(Node* node)
422{
423    ASSERT(!node || node->isElementNode());
424    return static_cast<Element*>(node);
425}
426
427inline 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.
434void toElement(const Element*);
435
436inline bool Node::hasTagName(const QualifiedName& name) const
437{
438    return isElementNode() && toElement(this)->hasTagName(name);
439}
440
441inline bool Node::hasLocalName(const AtomicString& name) const
442{
443    return isElementNode() && toElement(this)->hasLocalName(name);
444}
445
446inline bool Node::hasAttributes() const
447{
448    return isElementNode() && toElement(this)->hasAttributes();
449}
450
451inline NamedNodeMap* Node::attributes() const
452{
453    return isElementNode() ? toElement(this)->attributes() : 0;
454}
455
456inline Element* Node::parentElement() const
457{
458    ContainerNode* parent = parentNode();
459    return parent && parent->isElementNode() ? toElement(parent) : 0;
460}
461
462inline 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
477inline 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
492inline bool Element::fastHasAttribute(const QualifiedName& name) const
493{
494    return m_attributeMap && m_attributeMap->getAttributeItem(name);
495}
496
497inline 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
506inline const AtomicString& Element::idForStyleResolution() const
507{
508    ASSERT(hasID());
509    return m_attributeMap->idForStyleResolution();
510}
511
512inline 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
521inline const AtomicString& Element::getIdAttribute() const
522{
523    return fastGetAttribute(document()->idAttributeName());
524}
525
526inline void Element::setIdAttribute(const AtomicString& value)
527{
528    setAttribute(document()->idAttributeName(), value);
529}
530
531inline const AtomicString& Element::shadowPseudoId() const
532{
533    return nullAtom;
534}
535
536inline 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