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, 2013 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 "Attribute.h"
29#include "CollectionType.h"
30#include "Document.h"
31#include "HTMLNames.h"
32#include "ScrollTypes.h"
33#include "SpaceSplitString.h"
34
35namespace WebCore {
36
37class Attr;
38class ClientRect;
39class ClientRectList;
40class DOMStringMap;
41class DOMTokenList;
42class Element;
43class ElementRareData;
44class ElementShadow;
45class HTMLDocument;
46class ShareableElementData;
47class IntSize;
48class Locale;
49class UniqueElementData;
50class PseudoElement;
51class RenderRegion;
52class ShadowRoot;
53class StylePropertySet;
54
55class ElementData : public RefCounted<ElementData> {
56    WTF_MAKE_FAST_ALLOCATED;
57public:
58    // Override RefCounted's deref() to ensure operator delete is called on
59    // the appropriate subclass type.
60    void deref();
61
62    static const unsigned attributeNotFound = static_cast<unsigned>(-1);
63
64    void clearClass() const { m_classNames.clear(); }
65    void setClass(const AtomicString& className, bool shouldFoldCase) const { m_classNames.set(className, shouldFoldCase); }
66    const SpaceSplitString& classNames() const { return m_classNames; }
67
68    const AtomicString& idForStyleResolution() const { return m_idForStyleResolution; }
69    void setIdForStyleResolution(const AtomicString& newId) const { m_idForStyleResolution = newId; }
70
71    const StylePropertySet* inlineStyle() const { return m_inlineStyle.get(); }
72
73    const StylePropertySet* presentationAttributeStyle() const;
74
75    unsigned length() const;
76    bool isEmpty() const { return !length(); }
77
78    const Attribute* attributeItem(unsigned index) const;
79    const Attribute* getAttributeItem(const QualifiedName&) const;
80    unsigned getAttributeItemIndex(const QualifiedName&) const;
81    unsigned getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
82    unsigned getAttributeItemIndexForAttributeNode(const Attr*) const;
83
84    bool hasID() const { return !m_idForStyleResolution.isNull(); }
85    bool hasClass() const { return !m_classNames.isNull(); }
86    bool hasName() const { return m_hasNameAttribute; }
87
88    bool isEquivalent(const ElementData* other) const;
89
90    bool isUnique() const { return m_isUnique; }
91
92protected:
93    ElementData();
94    ElementData(unsigned arraySize);
95    ElementData(const ElementData&, bool isUnique);
96
97    unsigned m_isUnique : 1;
98    unsigned m_arraySize : 27;
99    mutable unsigned m_hasNameAttribute : 1;
100    mutable unsigned m_presentationAttributeStyleIsDirty : 1;
101    mutable unsigned m_styleAttributeIsDirty : 1;
102#if ENABLE(SVG)
103    mutable unsigned m_animatedSVGAttributesAreDirty : 1;
104#endif
105
106    mutable RefPtr<StylePropertySet> m_inlineStyle;
107    mutable SpaceSplitString m_classNames;
108    mutable AtomicString m_idForStyleResolution;
109
110private:
111    friend class Element;
112    friend class StyledElement;
113    friend class ShareableElementData;
114    friend class UniqueElementData;
115#if ENABLE(SVG)
116    friend class SVGElement;
117#endif
118
119    const Attribute* attributeBase() const;
120    const Attribute* getAttributeItem(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
121    unsigned getAttributeItemIndexSlowCase(const AtomicString& name, bool shouldIgnoreAttributeCase) const;
122
123    PassRefPtr<UniqueElementData> makeUniqueCopy() const;
124};
125
126#if COMPILER(MSVC)
127#pragma warning(push)
128#pragma warning(disable: 4200) // Disable "zero-sized array in struct/union" warning
129#endif
130
131class ShareableElementData : public ElementData {
132public:
133    static PassRefPtr<ShareableElementData> createWithAttributes(const Vector<Attribute>&);
134
135    explicit ShareableElementData(const Vector<Attribute>&);
136    explicit ShareableElementData(const UniqueElementData&);
137    ~ShareableElementData();
138
139    Attribute m_attributeArray[0];
140};
141
142#if COMPILER(MSVC)
143#pragma warning(pop)
144#endif
145
146class UniqueElementData : public ElementData {
147public:
148    static PassRefPtr<UniqueElementData> create();
149    PassRefPtr<ShareableElementData> makeShareableCopy() const;
150
151    // These functions do no error/duplicate checking.
152    void addAttribute(const QualifiedName&, const AtomicString&);
153    void removeAttribute(unsigned index);
154
155    Attribute* attributeItem(unsigned index);
156    Attribute* getAttributeItem(const QualifiedName&);
157
158    UniqueElementData();
159    explicit UniqueElementData(const ShareableElementData&);
160    explicit UniqueElementData(const UniqueElementData&);
161
162    mutable RefPtr<StylePropertySet> m_presentationAttributeStyle;
163    Vector<Attribute, 4> m_attributeVector;
164};
165
166enum AffectedSelectorType {
167    AffectedSelectorChecked = 1,
168    AffectedSelectorEnabled = 1 << 1,
169    AffectedSelectorDisabled = 1 << 2,
170    AffectedSelectorIndeterminate = 1 << 3,
171    AffectedSelectorLink = 1 << 4,
172    AffectedSelectorTarget = 1 << 5,
173    AffectedSelectorVisited = 1 << 6
174};
175typedef int AffectedSelectorMask;
176
177enum SpellcheckAttributeState {
178    SpellcheckAttributeTrue,
179    SpellcheckAttributeFalse,
180    SpellcheckAttributeDefault
181};
182
183class Element : public ContainerNode {
184public:
185    static PassRefPtr<Element> create(const QualifiedName&, Document*);
186    virtual ~Element();
187
188    DEFINE_ATTRIBUTE_EVENT_LISTENER(abort);
189    DEFINE_ATTRIBUTE_EVENT_LISTENER(change);
190    DEFINE_ATTRIBUTE_EVENT_LISTENER(click);
191    DEFINE_ATTRIBUTE_EVENT_LISTENER(contextmenu);
192    DEFINE_ATTRIBUTE_EVENT_LISTENER(dblclick);
193    DEFINE_ATTRIBUTE_EVENT_LISTENER(dragenter);
194    DEFINE_ATTRIBUTE_EVENT_LISTENER(dragover);
195    DEFINE_ATTRIBUTE_EVENT_LISTENER(dragleave);
196    DEFINE_ATTRIBUTE_EVENT_LISTENER(drop);
197    DEFINE_ATTRIBUTE_EVENT_LISTENER(dragstart);
198    DEFINE_ATTRIBUTE_EVENT_LISTENER(drag);
199    DEFINE_ATTRIBUTE_EVENT_LISTENER(dragend);
200    DEFINE_ATTRIBUTE_EVENT_LISTENER(input);
201    DEFINE_ATTRIBUTE_EVENT_LISTENER(invalid);
202    DEFINE_ATTRIBUTE_EVENT_LISTENER(keydown);
203    DEFINE_ATTRIBUTE_EVENT_LISTENER(keypress);
204    DEFINE_ATTRIBUTE_EVENT_LISTENER(keyup);
205    DEFINE_ATTRIBUTE_EVENT_LISTENER(mousedown);
206    DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseenter);
207    DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseleave);
208    DEFINE_ATTRIBUTE_EVENT_LISTENER(mousemove);
209    DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseout);
210    DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseover);
211    DEFINE_ATTRIBUTE_EVENT_LISTENER(mouseup);
212    DEFINE_ATTRIBUTE_EVENT_LISTENER(mousewheel);
213    DEFINE_ATTRIBUTE_EVENT_LISTENER(scroll);
214    DEFINE_ATTRIBUTE_EVENT_LISTENER(select);
215    DEFINE_ATTRIBUTE_EVENT_LISTENER(submit);
216
217    // These four attribute event handler attributes are overridden by HTMLBodyElement
218    // and HTMLFrameSetElement to forward to the DOMWindow.
219    DECLARE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(blur);
220    DECLARE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(error);
221    DECLARE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(focus);
222    DECLARE_VIRTUAL_ATTRIBUTE_EVENT_LISTENER(load);
223
224    // WebKit extensions
225    DEFINE_ATTRIBUTE_EVENT_LISTENER(beforecut);
226    DEFINE_ATTRIBUTE_EVENT_LISTENER(cut);
227    DEFINE_ATTRIBUTE_EVENT_LISTENER(beforecopy);
228    DEFINE_ATTRIBUTE_EVENT_LISTENER(copy);
229    DEFINE_ATTRIBUTE_EVENT_LISTENER(beforepaste);
230    DEFINE_ATTRIBUTE_EVENT_LISTENER(paste);
231    DEFINE_ATTRIBUTE_EVENT_LISTENER(reset);
232    DEFINE_ATTRIBUTE_EVENT_LISTENER(search);
233    DEFINE_ATTRIBUTE_EVENT_LISTENER(selectstart);
234#if ENABLE(TOUCH_EVENTS)
235    DEFINE_ATTRIBUTE_EVENT_LISTENER(touchstart);
236    DEFINE_ATTRIBUTE_EVENT_LISTENER(touchmove);
237    DEFINE_ATTRIBUTE_EVENT_LISTENER(touchend);
238    DEFINE_ATTRIBUTE_EVENT_LISTENER(touchcancel);
239#endif
240#if ENABLE(FULLSCREEN_API)
241    DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitfullscreenchange);
242    DEFINE_ATTRIBUTE_EVENT_LISTENER(webkitfullscreenerror);
243#endif
244
245    bool hasAttribute(const QualifiedName&) const;
246    const AtomicString& getAttribute(const QualifiedName&) const;
247    void setAttribute(const QualifiedName&, const AtomicString& value);
248    void setSynchronizedLazyAttribute(const QualifiedName&, const AtomicString& value);
249    void removeAttribute(const QualifiedName&);
250
251    // Typed getters and setters for language bindings.
252    int getIntegralAttribute(const QualifiedName& attributeName) const;
253    void setIntegralAttribute(const QualifiedName& attributeName, int value);
254    unsigned getUnsignedIntegralAttribute(const QualifiedName& attributeName) const;
255    void setUnsignedIntegralAttribute(const QualifiedName& attributeName, unsigned value);
256
257    // Call this to get the value of an attribute that is known not to be the style
258    // attribute or one of the SVG animatable attributes.
259    bool fastHasAttribute(const QualifiedName&) const;
260    const AtomicString& fastGetAttribute(const QualifiedName&) const;
261#ifndef NDEBUG
262    bool fastAttributeLookupAllowed(const QualifiedName&) const;
263#endif
264
265#ifdef DUMP_NODE_STATISTICS
266    bool hasNamedNodeMap() const;
267#endif
268    bool hasAttributes() const;
269    // This variant will not update the potentially invalid attributes. To be used when not interested
270    // in style attribute or one of the SVG animation attributes.
271    bool hasAttributesWithoutUpdate() const;
272
273    bool hasAttribute(const AtomicString& name) const;
274    bool hasAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const;
275
276    const AtomicString& getAttribute(const AtomicString& name) const;
277    const AtomicString& getAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName) const;
278
279    void setAttribute(const AtomicString& name, const AtomicString& value, ExceptionCode&);
280    static bool parseAttributeName(QualifiedName&, const AtomicString& namespaceURI, const AtomicString& qualifiedName, ExceptionCode&);
281    void setAttributeNS(const AtomicString& namespaceURI, const AtomicString& qualifiedName, const AtomicString& value, ExceptionCode&);
282
283    bool isIdAttributeName(const QualifiedName&) const;
284    const AtomicString& getIdAttribute() const;
285    void setIdAttribute(const AtomicString&);
286
287    const AtomicString& getNameAttribute() const;
288
289    // Call this to get the value of the id attribute for style resolution purposes.
290    // The value will already be lowercased if the document is in compatibility mode,
291    // so this function is not suitable for non-style uses.
292    const AtomicString& idForStyleResolution() const;
293
294    // Internal methods that assume the existence of attribute storage, one should use hasAttributes()
295    // before calling them.
296    unsigned attributeCount() const;
297    const Attribute* attributeItem(unsigned index) const;
298    const Attribute* getAttributeItem(const QualifiedName&) const;
299    unsigned getAttributeItemIndex(const QualifiedName& name) const { return elementData()->getAttributeItemIndex(name); }
300    unsigned getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const { return elementData()->getAttributeItemIndex(name, shouldIgnoreAttributeCase); }
301
302    void scrollIntoView(bool alignToTop = true);
303    void scrollIntoViewIfNeeded(bool centerIfNeeded = true);
304
305    void scrollByLines(int lines);
306    void scrollByPages(int pages);
307
308    int offsetLeft();
309    int offsetTop();
310    int offsetWidth();
311    int offsetHeight();
312
313    // FIXME: Replace uses of offsetParent in the platform with calls
314    // to the render layer and merge bindingsOffsetParent and offsetParent.
315    Element* bindingsOffsetParent();
316
317    Element* offsetParent();
318    int clientLeft();
319    int clientTop();
320    int clientWidth();
321    int clientHeight();
322    virtual int scrollLeft();
323    virtual int scrollTop();
324    virtual void setScrollLeft(int);
325    virtual void setScrollTop(int);
326    virtual int scrollWidth();
327    virtual int scrollHeight();
328
329    IntRect boundsInRootViewSpace();
330
331    PassRefPtr<ClientRectList> getClientRects();
332    PassRefPtr<ClientRect> getBoundingClientRect();
333
334    // Returns the absolute bounding box translated into screen coordinates:
335    IntRect screenRect() const;
336
337    void removeAttribute(const AtomicString& name);
338    void removeAttributeNS(const AtomicString& namespaceURI, const AtomicString& localName);
339
340    PassRefPtr<Attr> detachAttribute(unsigned index);
341
342    PassRefPtr<Attr> getAttributeNode(const AtomicString& name);
343    PassRefPtr<Attr> getAttributeNodeNS(const AtomicString& namespaceURI, const AtomicString& localName);
344    PassRefPtr<Attr> setAttributeNode(Attr*, ExceptionCode&);
345    PassRefPtr<Attr> setAttributeNodeNS(Attr*, ExceptionCode&);
346    PassRefPtr<Attr> removeAttributeNode(Attr*, ExceptionCode&);
347
348    PassRefPtr<Attr> attrIfExists(const QualifiedName&);
349    PassRefPtr<Attr> ensureAttr(const QualifiedName&);
350
351    const Vector<RefPtr<Attr> >& attrNodeList();
352
353    virtual CSSStyleDeclaration* style();
354
355    const QualifiedName& tagQName() const { return m_tagName; }
356    String tagName() const { return nodeName(); }
357    bool hasTagName(const QualifiedName& tagName) const { return m_tagName.matches(tagName); }
358
359    // A fast function for checking the local name against another atomic string.
360    bool hasLocalName(const AtomicString& other) const { return m_tagName.localName() == other; }
361    bool hasLocalName(const QualifiedName& other) const { return m_tagName.localName() == other.localName(); }
362
363    virtual const AtomicString& localName() const OVERRIDE FINAL { return m_tagName.localName(); }
364    virtual const AtomicString& prefix() const OVERRIDE FINAL { return m_tagName.prefix(); }
365    virtual const AtomicString& namespaceURI() const OVERRIDE FINAL { return m_tagName.namespaceURI(); }
366
367    virtual KURL baseURI() const OVERRIDE FINAL;
368
369    virtual String nodeName() const;
370
371    PassRefPtr<Element> cloneElementWithChildren();
372    PassRefPtr<Element> cloneElementWithoutChildren();
373
374    void normalizeAttributes();
375    String nodeNamePreservingCase() const;
376
377    void setBooleanAttribute(const QualifiedName& name, bool);
378
379    // For exposing to DOM only.
380    NamedNodeMap* attributes() const;
381
382    enum AttributeModificationReason {
383        ModifiedDirectly,
384        ModifiedByCloning
385    };
386
387    // This method is called whenever an attribute is added, changed or removed.
388    virtual void attributeChanged(const QualifiedName&, const AtomicString&, AttributeModificationReason = ModifiedDirectly);
389    virtual void parseAttribute(const QualifiedName&, const AtomicString&) { }
390
391    // Only called by the parser immediately after element construction.
392    void parserSetAttributes(const Vector<Attribute>&);
393
394    // Remove attributes that might introduce scripting from the vector leaving the element unchanged.
395    void stripScriptingAttributes(Vector<Attribute>&) const;
396
397    const ElementData* elementData() const { return m_elementData.get(); }
398    UniqueElementData* ensureUniqueElementData();
399
400    void synchronizeAllAttributes() const;
401
402    // Clones attributes only.
403    void cloneAttributesFromElement(const Element&);
404
405    // Clones all attribute-derived data, including subclass specifics (through copyNonAttributeProperties.)
406    void cloneDataFromElement(const Element&);
407
408    bool hasEquivalentAttributes(const Element* other) const;
409
410    virtual void copyNonAttributePropertiesFromElement(const Element&) { }
411
412    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
413    virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
414    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*);
415    virtual bool rendererIsNeeded(const NodeRenderingContext&);
416    void recalcStyle(StyleChange = NoChange);
417    void didAffectSelector(AffectedSelectorMask);
418
419    ElementShadow* shadow() const;
420    ElementShadow* ensureShadow();
421    PassRefPtr<ShadowRoot> createShadowRoot(ExceptionCode&);
422    ShadowRoot* authorShadowRoot() const;
423
424    bool hasAuthorShadowRoot() const { return authorShadowRoot(); }
425
426    ShadowRoot* userAgentShadowRoot() const;
427    ShadowRoot* ensureUserAgentShadowRoot();
428
429    virtual const AtomicString& shadowPseudoId() const;
430
431    bool inActiveChain() const { return isUserActionElement() && isUserActionElementInActiveChain(); }
432    bool active() const { return isUserActionElement() && isUserActionElementActive(); }
433    bool hovered() const { return isUserActionElement() && isUserActionElementHovered(); }
434    bool focused() const { return isUserActionElement() && isUserActionElementFocused(); }
435
436    virtual void setActive(bool flag = true, bool pause = false);
437    virtual void setHovered(bool flag = true);
438    virtual void setFocus(bool flag);
439
440    virtual bool supportsFocus() const;
441    virtual bool isFocusable() const;
442    virtual bool isKeyboardFocusable(KeyboardEvent*) const;
443    virtual bool isMouseFocusable() const;
444
445    virtual bool shouldUseInputMethod();
446
447    virtual short tabIndex() const;
448    virtual Element* focusDelegate();
449
450    RenderStyle* computedStyle(PseudoId = NOPSEUDO);
451
452    // Methods for indicating the style is affected by dynamic updates (e.g., children changing, our position changing in our sibling list, etc.)
453    bool styleAffectedByEmpty() const { return hasRareData() && rareDataStyleAffectedByEmpty(); }
454    bool childrenAffectedByHover() const { return hasRareData() && rareDataChildrenAffectedByHover(); }
455    bool childrenAffectedByActive() const { return hasRareData() && rareDataChildrenAffectedByActive(); }
456    bool childrenAffectedByDrag() const { return hasRareData() && rareDataChildrenAffectedByDrag(); }
457    bool childrenAffectedByPositionalRules() const { return hasRareData() && (rareDataChildrenAffectedByForwardPositionalRules() || rareDataChildrenAffectedByBackwardPositionalRules()); }
458    bool childrenAffectedByFirstChildRules() const { return hasRareData() && rareDataChildrenAffectedByFirstChildRules(); }
459    bool childrenAffectedByLastChildRules() const { return hasRareData() && rareDataChildrenAffectedByLastChildRules(); }
460    bool childrenAffectedByDirectAdjacentRules() const { return hasRareData() && rareDataChildrenAffectedByDirectAdjacentRules(); }
461    bool childrenAffectedByForwardPositionalRules() const { return hasRareData() && rareDataChildrenAffectedByForwardPositionalRules(); }
462    bool childrenAffectedByBackwardPositionalRules() const { return hasRareData() && rareDataChildrenAffectedByBackwardPositionalRules(); }
463    unsigned childIndex() const { return hasRareData() ? rareDataChildIndex() : 0; }
464
465    bool hasFlagsSetDuringStylingOfChildren() const;
466
467    void setStyleAffectedByEmpty();
468    void setChildrenAffectedByHover(bool);
469    void setChildrenAffectedByActive(bool);
470    void setChildrenAffectedByDrag(bool);
471    void setChildrenAffectedByFirstChildRules();
472    void setChildrenAffectedByLastChildRules();
473    void setChildrenAffectedByDirectAdjacentRules();
474    void setChildrenAffectedByForwardPositionalRules();
475    void setChildrenAffectedByBackwardPositionalRules();
476    void setChildIndex(unsigned);
477
478    void setIsInCanvasSubtree(bool);
479    bool isInCanvasSubtree() const;
480
481    void setIsInsideRegion(bool);
482    bool isInsideRegion() const;
483
484    AtomicString computeInheritedLanguage() const;
485    Locale& locale() const;
486
487    virtual void accessKeyAction(bool /*sendToAnyEvent*/) { }
488
489    virtual bool isURLAttribute(const Attribute&) const { return false; }
490    virtual bool isHTMLContentAttribute(const Attribute&) const { return false; }
491
492    KURL getURLAttribute(const QualifiedName&) const;
493    KURL getNonEmptyURLAttribute(const QualifiedName&) const;
494
495    virtual const AtomicString& imageSourceURL() const;
496    virtual String target() const { return String(); }
497
498    virtual void focus(bool restorePreviousSelection = true, FocusDirection = FocusDirectionNone);
499    virtual void updateFocusAppearance(bool restorePreviousSelection);
500    virtual void blur();
501
502    String innerText();
503    String outerText();
504
505    virtual String title() const;
506
507    const AtomicString& pseudo() const;
508    void setPseudo(const AtomicString&);
509
510    LayoutSize minimumSizeForResizing() const;
511    void setMinimumSizeForResizing(const LayoutSize&);
512
513    // Use Document::registerForDocumentActivationCallbacks() to subscribe to these
514    virtual void documentWillSuspendForPageCache() { }
515    virtual void documentDidResumeFromPageCache() { }
516
517    // Use Document::registerForMediaVolumeCallbacks() to subscribe to this
518    virtual void mediaVolumeDidChange() { }
519
520    // Use Document::registerForPrivateBrowsingStateChangedCallbacks() to subscribe to this.
521    virtual void privateBrowsingStateDidChange() { }
522
523    virtual void didBecomeFullscreenElement() { }
524    virtual void willStopBeingFullscreenElement() { }
525
526#if ENABLE(VIDEO_TRACK)
527    virtual void captionPreferencesChanged() { }
528#endif
529
530    bool isFinishedParsingChildren() const { return isParsingChildrenFinished(); }
531    virtual void finishParsingChildren();
532    virtual void beginParsingChildren() OVERRIDE FINAL;
533
534    bool hasPseudoElements() const;
535    PseudoElement* pseudoElement(PseudoId) const;
536    RenderObject* pseudoElementRenderer(PseudoId) const;
537    bool childNeedsShadowWalker() const;
538    void didShadowTreeAwareChildrenChange();
539
540    // ElementTraversal API
541    Element* firstElementChild() const;
542    Element* lastElementChild() const;
543    Element* previousElementSibling() const;
544    Element* nextElementSibling() const;
545    unsigned childElementCount() const;
546
547    virtual bool matchesReadOnlyPseudoClass() const;
548    virtual bool matchesReadWritePseudoClass() const;
549    bool webkitMatchesSelector(const String& selectors, ExceptionCode&);
550    virtual bool shouldAppearIndeterminate() const;
551
552    DOMTokenList* classList();
553
554    DOMStringMap* dataset();
555
556#if ENABLE(MATHML)
557    virtual bool isMathMLElement() const { return false; }
558#else
559    static bool isMathMLElement() { return false; }
560#endif
561
562#if ENABLE(VIDEO)
563    virtual bool isMediaElement() const { return false; }
564#endif
565
566#if ENABLE(INPUT_SPEECH)
567    virtual bool isInputFieldSpeechButtonElement() const { return false; }
568#endif
569
570    virtual bool isFormControlElement() const { return false; }
571    virtual bool isSpinButtonElement() const { return false; }
572    virtual bool isTextFormControl() const { return false; }
573    virtual bool isOptionalFormControl() const { return false; }
574    virtual bool isRequiredFormControl() const { return false; }
575    virtual bool isDefaultButtonForForm() const { return false; }
576    virtual bool willValidate() const { return false; }
577    virtual bool isValidFormControlElement() { return false; }
578    virtual bool isInRange() const { return false; }
579    virtual bool isOutOfRange() const { return false; }
580    virtual bool isFrameElementBase() const { return false; }
581
582    virtual bool canContainRangeEndPoint() const { return true; }
583
584    // Used for disabled form elements; if true, prevents mouse events from being dispatched
585    // to event listeners, and prevents DOMActivate events from being sent at all.
586    virtual bool isDisabledFormControl() const;
587
588#if ENABLE(DIALOG_ELEMENT)
589    bool isInert() const;
590#endif
591
592#if ENABLE(SVG)
593    virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const;
594    bool hasPendingResources() const;
595    void setHasPendingResources();
596    void clearHasPendingResources();
597    virtual void buildPendingResource() { };
598#endif
599
600#if ENABLE(FULLSCREEN_API)
601    enum {
602        ALLOW_KEYBOARD_INPUT = 1 << 0,
603        LEGACY_MOZILLA_REQUEST = 1 << 1,
604    };
605
606    void webkitRequestFullScreen(unsigned short flags);
607    bool containsFullScreenElement() const;
608    void setContainsFullScreenElement(bool);
609    void setContainsFullScreenElementOnAncestorsCrossingFrameBoundaries(bool);
610
611    // W3C API
612    void webkitRequestFullscreen();
613#endif
614
615#if ENABLE(DIALOG_ELEMENT)
616    bool isInTopLayer() const;
617    void setIsInTopLayer(bool);
618#endif
619
620#if ENABLE(POINTER_LOCK)
621    void webkitRequestPointerLock();
622#endif
623
624    virtual bool isSpellCheckingEnabled() const;
625
626    PassRefPtr<RenderStyle> styleForRenderer();
627
628    RenderRegion* renderRegion() const;
629
630#if ENABLE(CSS_REGIONS)
631    virtual bool shouldMoveToFlowThread(RenderStyle*) const;
632    const AtomicString& webkitRegionOverset() const;
633    Vector<RefPtr<Range> > webkitGetRegionFlowRanges() const;
634#endif
635
636    bool hasID() const;
637    bool hasClass() const;
638    bool hasName() const;
639    const SpaceSplitString& classNames() const;
640
641    IntSize savedLayerScrollOffset() const;
642    void setSavedLayerScrollOffset(const IntSize&);
643
644    void dispatchSimulatedClick(Event* underlyingEvent, SimulatedClickMouseEventOptions = SendNoEvents, SimulatedClickVisualOptions = ShowPressedLook);
645    void dispatchFocusInEvent(const AtomicString& eventType, PassRefPtr<Element> oldFocusedElement);
646    void dispatchFocusOutEvent(const AtomicString& eventType, PassRefPtr<Element> newFocusedElement);
647    virtual void dispatchFocusEvent(PassRefPtr<Element> oldFocusedElement, FocusDirection);
648    virtual void dispatchBlurEvent(PassRefPtr<Element> newFocusedElement);
649
650protected:
651    Element(const QualifiedName& tagName, Document* document, ConstructionType type)
652        : ContainerNode(document, type)
653        , m_tagName(tagName)
654    {
655    }
656
657    virtual InsertionNotificationRequest insertedInto(ContainerNode*) OVERRIDE;
658    virtual void removedFrom(ContainerNode*) OVERRIDE;
659    virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0) OVERRIDE;
660    virtual void removeAllEventListeners() OVERRIDE FINAL;
661
662    virtual bool willRecalcStyle(StyleChange);
663    virtual void didRecalcStyle(StyleChange);
664    virtual PassRefPtr<RenderStyle> customStyleForRenderer();
665
666    void clearTabIndexExplicitlyIfNeeded();
667    void setTabIndexExplicitly(short);
668
669    PassRefPtr<HTMLCollection> ensureCachedHTMLCollection(CollectionType);
670    HTMLCollection* cachedHTMLCollection(CollectionType);
671
672    // classAttributeChanged() exists to share code between
673    // parseAttribute (called via setAttribute()) and
674    // svgAttributeChanged (called when element.className.baseValue is set)
675    void classAttributeChanged(const AtomicString& newClassString);
676
677private:
678    bool isTextNode() const;
679
680    bool isUserActionElementInActiveChain() const;
681    bool isUserActionElementActive() const;
682    bool isUserActionElementFocused() const;
683    bool isUserActionElementHovered() const;
684
685    void updatePseudoElement(PseudoId, StyleChange = NoChange);
686    PassRefPtr<PseudoElement> createPseudoElementIfNeeded(PseudoId);
687    void setPseudoElement(PseudoId, PassRefPtr<PseudoElement>);
688
689    virtual bool areAuthorShadowsAllowed() const { return true; }
690    virtual void didAddUserAgentShadowRoot(ShadowRoot*) { }
691    virtual bool alwaysCreateUserAgentShadowRoot() const { return false; }
692
693    // FIXME: Remove the need for Attr to call willModifyAttribute/didModifyAttribute.
694    friend class Attr;
695
696    enum SynchronizationOfLazyAttribute { NotInSynchronizationOfLazyAttribute = 0, InSynchronizationOfLazyAttribute };
697
698    void didAddAttribute(const QualifiedName&, const AtomicString&);
699    void willModifyAttribute(const QualifiedName&, const AtomicString& oldValue, const AtomicString& newValue);
700    void didModifyAttribute(const QualifiedName&, const AtomicString&);
701    void didRemoveAttribute(const QualifiedName&);
702
703    void synchronizeAttribute(const QualifiedName&) const;
704    void synchronizeAttribute(const AtomicString& localName) const;
705
706    void updateName(const AtomicString& oldName, const AtomicString& newName);
707    void updateNameForTreeScope(TreeScope*, const AtomicString& oldName, const AtomicString& newName);
708    void updateNameForDocument(HTMLDocument*, const AtomicString& oldName, const AtomicString& newName);
709    void updateId(const AtomicString& oldId, const AtomicString& newId);
710    void updateIdForTreeScope(TreeScope*, const AtomicString& oldId, const AtomicString& newId);
711    enum HTMLDocumentNamedItemMapsUpdatingCondition { AlwaysUpdateHTMLDocumentNamedItemMaps, UpdateHTMLDocumentNamedItemMapsOnlyIfDiffersFromNameAttribute };
712    void updateIdForDocument(HTMLDocument*, const AtomicString& oldId, const AtomicString& newId, HTMLDocumentNamedItemMapsUpdatingCondition);
713    void updateLabel(TreeScope*, const AtomicString& oldForAttributeValue, const AtomicString& newForAttributeValue);
714
715    void scrollByUnits(int units, ScrollGranularity);
716
717    virtual void setPrefix(const AtomicString&, ExceptionCode&) OVERRIDE FINAL;
718    virtual NodeType nodeType() const OVERRIDE FINAL;
719    virtual bool childTypeAllowed(NodeType) const OVERRIDE FINAL;
720
721    void setAttributeInternal(unsigned index, const QualifiedName&, const AtomicString& value, SynchronizationOfLazyAttribute);
722    void addAttributeInternal(const QualifiedName&, const AtomicString& value, SynchronizationOfLazyAttribute);
723    void removeAttributeInternal(unsigned index, SynchronizationOfLazyAttribute);
724    void attributeChangedFromParserOrByCloning(const QualifiedName&, const AtomicString&, AttributeModificationReason);
725
726#ifndef NDEBUG
727    virtual void formatForDebugger(char* buffer, unsigned length) const;
728#endif
729
730    bool pseudoStyleCacheIsInvalid(const RenderStyle* currentStyle, RenderStyle* newStyle);
731
732    void cancelFocusAppearanceUpdate();
733
734    virtual RenderStyle* virtualComputedStyle(PseudoId pseudoElementSpecifier = NOPSEUDO) { return computedStyle(pseudoElementSpecifier); }
735
736    // cloneNode is private so that non-virtual cloneElementWithChildren and cloneElementWithoutChildren
737    // are used instead.
738    virtual PassRefPtr<Node> cloneNode(bool deep) OVERRIDE;
739    virtual PassRefPtr<Element> cloneElementWithoutAttributesAndChildren();
740
741    QualifiedName m_tagName;
742    bool rareDataStyleAffectedByEmpty() const;
743    bool rareDataChildrenAffectedByHover() const;
744    bool rareDataChildrenAffectedByActive() const;
745    bool rareDataChildrenAffectedByDrag() const;
746    bool rareDataChildrenAffectedByFirstChildRules() const;
747    bool rareDataChildrenAffectedByLastChildRules() const;
748    bool rareDataChildrenAffectedByDirectAdjacentRules() const;
749    bool rareDataChildrenAffectedByForwardPositionalRules() const;
750    bool rareDataChildrenAffectedByBackwardPositionalRules() const;
751    unsigned rareDataChildIndex() const;
752
753    SpellcheckAttributeState spellcheckAttributeState() const;
754
755    void unregisterNamedFlowContentNode();
756
757    void createUniqueElementData();
758
759    ElementRareData* elementRareData() const;
760    ElementRareData* ensureElementRareData();
761
762    void detachAllAttrNodesFromElement();
763    void detachAttrNodeFromElementWithValue(Attr*, const AtomicString& value);
764
765    void createRendererIfNeeded(const AttachContext&);
766
767    bool isJavaScriptURLAttribute(const Attribute&) const;
768
769    RefPtr<ElementData> m_elementData;
770};
771
772inline Element* toElement(Node* node)
773{
774    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isElementNode());
775    return static_cast<Element*>(node);
776}
777
778inline const Element* toElement(const Node* node)
779{
780    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isElementNode());
781    return static_cast<const Element*>(node);
782}
783
784// This will catch anyone doing an unnecessary cast.
785void toElement(const Element*);
786
787inline bool isDisabledFormControl(const Node* node)
788{
789    return node->isElementNode() && toElement(node)->isDisabledFormControl();
790}
791
792inline bool Node::hasTagName(const QualifiedName& name) const
793{
794    return isElementNode() && toElement(this)->hasTagName(name);
795}
796
797inline bool Node::hasLocalName(const AtomicString& name) const
798{
799    return isElementNode() && toElement(this)->hasLocalName(name);
800}
801
802inline bool Node::hasAttributes() const
803{
804    return isElementNode() && toElement(this)->hasAttributes();
805}
806
807inline NamedNodeMap* Node::attributes() const
808{
809    return isElementNode() ? toElement(this)->attributes() : 0;
810}
811
812inline Element* Node::parentElement() const
813{
814    ContainerNode* parent = parentNode();
815    return parent && parent->isElementNode() ? toElement(parent) : 0;
816}
817
818inline Element* Element::previousElementSibling() const
819{
820    Node* n = previousSibling();
821    while (n && !n->isElementNode())
822        n = n->previousSibling();
823    return static_cast<Element*>(n);
824}
825
826inline Element* Element::nextElementSibling() const
827{
828    Node* n = nextSibling();
829    while (n && !n->isElementNode())
830        n = n->nextSibling();
831    return static_cast<Element*>(n);
832}
833
834inline bool Element::fastHasAttribute(const QualifiedName& name) const
835{
836    ASSERT(fastAttributeLookupAllowed(name));
837    return elementData() && getAttributeItem(name);
838}
839
840inline const AtomicString& Element::fastGetAttribute(const QualifiedName& name) const
841{
842    ASSERT(fastAttributeLookupAllowed(name));
843    if (elementData()) {
844        if (const Attribute* attribute = getAttributeItem(name))
845            return attribute->value();
846    }
847    return nullAtom;
848}
849
850inline bool Element::hasAttributesWithoutUpdate() const
851{
852    return elementData() && !elementData()->isEmpty();
853}
854
855inline const AtomicString& Element::idForStyleResolution() const
856{
857    ASSERT(hasID());
858    return elementData()->idForStyleResolution();
859}
860
861inline bool Element::isIdAttributeName(const QualifiedName& attributeName) const
862{
863    // FIXME: This check is probably not correct for the case where the document has an id attribute
864    // with a non-null namespace, because it will return false, a false negative, if the prefixes
865    // don't match but the local name and namespace both do. However, since this has been like this
866    // for a while and the code paths may be hot, we'll have to measure performance if we fix it.
867    return attributeName == document()->idAttributeName();
868}
869
870inline const AtomicString& Element::getIdAttribute() const
871{
872    return hasID() ? fastGetAttribute(document()->idAttributeName()) : nullAtom;
873}
874
875inline const AtomicString& Element::getNameAttribute() const
876{
877    return hasName() ? fastGetAttribute(HTMLNames::nameAttr) : nullAtom;
878}
879
880inline void Element::setIdAttribute(const AtomicString& value)
881{
882    setAttribute(document()->idAttributeName(), value);
883}
884
885inline const SpaceSplitString& Element::classNames() const
886{
887    ASSERT(hasClass());
888    ASSERT(elementData());
889    return elementData()->classNames();
890}
891
892inline unsigned Element::attributeCount() const
893{
894    ASSERT(elementData());
895    return elementData()->length();
896}
897
898inline const Attribute* Element::attributeItem(unsigned index) const
899{
900    ASSERT(elementData());
901    return elementData()->attributeItem(index);
902}
903
904inline const Attribute* Element::getAttributeItem(const QualifiedName& name) const
905{
906    ASSERT(elementData());
907    return elementData()->getAttributeItem(name);
908}
909
910inline bool Element::hasID() const
911{
912    return elementData() && elementData()->hasID();
913}
914
915inline bool Element::hasClass() const
916{
917    return elementData() && elementData()->hasClass();
918}
919
920inline bool Element::hasName() const
921{
922    return elementData() && elementData()->hasName();
923}
924
925inline UniqueElementData* Element::ensureUniqueElementData()
926{
927    if (!elementData() || !elementData()->isUnique())
928        createUniqueElementData();
929    return static_cast<UniqueElementData*>(m_elementData.get());
930}
931
932inline Node::InsertionNotificationRequest Node::insertedInto(ContainerNode* insertionPoint)
933{
934    ASSERT(insertionPoint->inDocument() || isContainerNode());
935    if (insertionPoint->inDocument())
936        setFlag(InDocumentFlag);
937    if (parentOrShadowHostNode()->isInShadowTree())
938        setFlag(IsInShadowTreeFlag);
939    return InsertionDone;
940}
941
942inline void Node::removedFrom(ContainerNode* insertionPoint)
943{
944    ASSERT(insertionPoint->inDocument() || isContainerNode());
945    if (insertionPoint->inDocument())
946        clearFlag(InDocumentFlag);
947    if (isInShadowTree() && !treeScope()->rootNode()->isShadowRoot())
948        clearFlag(IsInShadowTreeFlag);
949}
950
951inline bool isShadowHost(const Node* node)
952{
953    return node && node->isElementNode() && toElement(node)->shadow();
954}
955
956inline unsigned ElementData::length() const
957{
958    if (isUnique())
959        return static_cast<const UniqueElementData*>(this)->m_attributeVector.size();
960    return m_arraySize;
961}
962
963inline const Attribute* ElementData::attributeBase() const
964{
965    if (m_isUnique)
966        return static_cast<const UniqueElementData*>(this)->m_attributeVector.data();
967    return static_cast<const ShareableElementData*>(this)->m_attributeArray;
968}
969
970inline const StylePropertySet* ElementData::presentationAttributeStyle() const
971{
972    if (!m_isUnique)
973        return 0;
974    return static_cast<const UniqueElementData*>(this)->m_presentationAttributeStyle.get();
975}
976
977inline const Attribute* ElementData::getAttributeItem(const AtomicString& name, bool shouldIgnoreAttributeCase) const
978{
979    unsigned index = getAttributeItemIndex(name, shouldIgnoreAttributeCase);
980    if (index != attributeNotFound)
981        return attributeItem(index);
982    return 0;
983}
984
985inline unsigned ElementData::getAttributeItemIndex(const QualifiedName& name) const
986{
987    const Attribute* attributes = attributeBase();
988    for (unsigned i = 0, count = length(); i < count; ++i) {
989        if (attributes[i].name().matches(name))
990            return i;
991    }
992    return attributeNotFound;
993}
994
995// We use a boolean parameter instead of calling shouldIgnoreAttributeCase so that the caller
996// can tune the behavior (hasAttribute is case sensitive whereas getAttribute is not).
997inline unsigned ElementData::getAttributeItemIndex(const AtomicString& name, bool shouldIgnoreAttributeCase) const
998{
999    const Attribute* attributes = attributeBase();
1000    bool doSlowCheck = shouldIgnoreAttributeCase;
1001    const AtomicString& caseAdjustedName = shouldIgnoreAttributeCase ? name.lower() : name;
1002
1003    // Optimize for the case where the attribute exists and its name exactly matches.
1004    for (unsigned i = 0, count = length(); i < count; ++i) {
1005        if (!attributes[i].name().hasPrefix()) {
1006            if (caseAdjustedName == attributes[i].localName())
1007                return i;
1008        } else
1009            doSlowCheck = true;
1010    }
1011
1012    if (doSlowCheck)
1013        return getAttributeItemIndexSlowCase(name, shouldIgnoreAttributeCase);
1014    return attributeNotFound;
1015}
1016
1017inline const Attribute* ElementData::getAttributeItem(const QualifiedName& name) const
1018{
1019    const Attribute* attributes = attributeBase();
1020    for (unsigned i = 0, count = length(); i < count; ++i) {
1021        if (attributes[i].name().matches(name))
1022            return &attributes[i];
1023    }
1024    return 0;
1025}
1026
1027inline const Attribute* ElementData::attributeItem(unsigned index) const
1028{
1029    RELEASE_ASSERT(index < length());
1030    return attributeBase() + index;
1031}
1032
1033} // namespace
1034
1035#endif
1036