1/*
2 * Copyright (C) 2011 Google Inc. All Rights Reserved.
3 * Copyright (C) 2012, 2013 Apple Inc. All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#ifndef TreeScope_h
28#define TreeScope_h
29
30#include "DocumentOrderedMap.h"
31#include <wtf/Forward.h>
32#include <wtf/text/AtomicString.h>
33
34namespace WebCore {
35
36class ContainerNode;
37class DOMSelection;
38class Document;
39class Element;
40class HTMLLabelElement;
41class HTMLMapElement;
42class LayoutPoint;
43class IdTargetObserverRegistry;
44class Node;
45
46// A class which inherits both Node and TreeScope must call clearRareData() in its destructor
47// so that the Node destructor no longer does problematic NodeList cache manipulation in
48// the destructor.
49class TreeScope {
50    friend class Document;
51    friend class TreeScopeAdopter;
52
53public:
54    TreeScope* parentTreeScope() const { return m_parentTreeScope; }
55    void setParentTreeScope(TreeScope*);
56
57    Element* focusedElement();
58    Element* getElementById(const AtomicString&) const;
59    const Vector<Element*>* getAllElementsById(const AtomicString&) const;
60    bool hasElementWithId(AtomicStringImpl* id) const;
61    bool containsMultipleElementsWithId(const AtomicString& id) const;
62    void addElementById(const AtomicString& elementId, Element*);
63    void removeElementById(const AtomicString& elementId, Element*);
64
65    Element* getElementByName(const AtomicString&) const;
66    bool hasElementWithName(AtomicStringImpl*) const;
67    bool containsMultipleElementsWithName(const AtomicString&) const;
68    void addElementByName(const AtomicString&, Element*);
69    void removeElementByName(const AtomicString&, Element*);
70
71    Document* documentScope() const { return m_documentScope; }
72
73    Node* ancestorInThisScope(Node*) const;
74
75    void addImageMap(HTMLMapElement*);
76    void removeImageMap(HTMLMapElement*);
77    HTMLMapElement* getImageMap(const String& url) const;
78
79    Element* elementFromPoint(int x, int y) const;
80
81    // For accessibility.
82    bool shouldCacheLabelsByForAttribute() const { return m_labelsByForAttribute; }
83    void addLabel(const AtomicString& forAttributeValue, HTMLLabelElement*);
84    void removeLabel(const AtomicString& forAttributeValue, HTMLLabelElement*);
85    HTMLLabelElement* labelElementForId(const AtomicString& forAttributeValue);
86
87    DOMSelection* getSelection() const;
88
89    // Find first anchor with the given name.
90    // First searches for an element with the given ID, but if that fails, then looks
91    // for an anchor with the given name. ID matching is always case sensitive, but
92    // Anchor name matching is case sensitive in strict mode and not case sensitive in
93    // quirks mode for historical compatibility reasons.
94    Element* findAnchor(const String& name);
95
96    virtual bool applyAuthorStyles() const;
97    virtual bool resetStyleInheritance() const;
98
99    // Used by the basic DOM mutation methods (e.g., appendChild()).
100    void adoptIfNeeded(Node*);
101
102    ContainerNode* rootNode() const { return m_rootNode; }
103
104    IdTargetObserverRegistry& idTargetObserverRegistry() const { return *m_idTargetObserverRegistry.get(); }
105
106    static TreeScope* noDocumentInstance()
107    {
108        DEFINE_STATIC_LOCAL(TreeScope, instance, ());
109        return &instance;
110    }
111
112    // Nodes belonging to this scope hold guard references -
113    // these are enough to keep the scope from being destroyed, but
114    // not enough to keep it from removing its children. This allows a
115    // node that outlives its scope to still have a valid document
116    // pointer without introducing reference cycles.
117    void guardRef()
118    {
119        ASSERT(!deletionHasBegun());
120        ++m_guardRefCount;
121    }
122
123    void guardDeref()
124    {
125        ASSERT(!deletionHasBegun());
126        --m_guardRefCount;
127        if (!m_guardRefCount && !refCount() && this != noDocumentInstance()) {
128            beginDeletion();
129            delete this;
130        }
131    }
132
133    void removedLastRefToScope();
134
135protected:
136    TreeScope(ContainerNode*, Document*);
137    TreeScope(Document*);
138    virtual ~TreeScope();
139
140    void destroyTreeScopeData();
141    void clearDocumentScope();
142    void setDocumentScope(Document* document)
143    {
144        ASSERT(document);
145        ASSERT(this != noDocumentInstance());
146        m_documentScope = document;
147    }
148
149    bool hasGuardRefCount() const { return m_guardRefCount; }
150
151private:
152    TreeScope();
153
154    virtual void dispose() { }
155
156    int refCount() const;
157#ifndef NDEBUG
158    bool deletionHasBegun();
159    void beginDeletion();
160#else
161    bool deletionHasBegun() { return false; }
162    void beginDeletion() { }
163#endif
164
165    ContainerNode* m_rootNode;
166    Document* m_documentScope;
167    TreeScope* m_parentTreeScope;
168    int m_guardRefCount;
169
170    OwnPtr<DocumentOrderedMap> m_elementsById;
171    OwnPtr<DocumentOrderedMap> m_elementsByName;
172    OwnPtr<DocumentOrderedMap> m_imageMapsByName;
173    OwnPtr<DocumentOrderedMap> m_labelsByForAttribute;
174
175    OwnPtr<IdTargetObserverRegistry> m_idTargetObserverRegistry;
176
177    mutable RefPtr<DOMSelection> m_selection;
178};
179
180inline bool TreeScope::hasElementWithId(AtomicStringImpl* id) const
181{
182    ASSERT(id);
183    return m_elementsById && m_elementsById->contains(id);
184}
185
186inline bool TreeScope::containsMultipleElementsWithId(const AtomicString& id) const
187{
188    return m_elementsById && m_elementsById->containsMultiple(id.impl());
189}
190
191inline bool TreeScope::hasElementWithName(AtomicStringImpl* id) const
192{
193    ASSERT(id);
194    return m_elementsByName && m_elementsByName->contains(id);
195}
196
197inline bool TreeScope::containsMultipleElementsWithName(const AtomicString& name) const
198{
199    return m_elementsByName && m_elementsByName->containsMultiple(name.impl());
200}
201
202Node* nodeFromPoint(Document*, int x, int y, LayoutPoint* localPoint = 0);
203TreeScope* commonTreeScope(Node*, Node*);
204
205} // namespace WebCore
206
207#endif // TreeScope_h
208