1/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4 *           (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010, 2011 Apple Inc. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public License
18 * along with this library; see the file COPYING.LIB.  If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 *
22 */
23
24#ifndef ContainerNode_h
25#define ContainerNode_h
26
27#include "bindings/v8/ExceptionStatePlaceholder.h"
28#include "core/dom/Node.h"
29#include "wtf/OwnPtr.h"
30#include "wtf/Vector.h"
31
32namespace WebCore {
33
34class ExceptionState;
35class FloatPoint;
36class HTMLCollection;
37
38typedef void (*NodeCallback)(Node*);
39
40namespace Private {
41    template<class GenericNode, class GenericNodeContainer>
42    void addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer*);
43};
44
45class NoEventDispatchAssertion {
46public:
47    NoEventDispatchAssertion()
48    {
49#ifndef NDEBUG
50        if (!isMainThread())
51            return;
52        s_count++;
53#endif
54    }
55
56    ~NoEventDispatchAssertion()
57    {
58#ifndef NDEBUG
59        if (!isMainThread())
60            return;
61        ASSERT(s_count);
62        s_count--;
63#endif
64    }
65
66#ifndef NDEBUG
67    static bool isEventDispatchForbidden()
68    {
69        if (!isMainThread())
70            return false;
71        return s_count;
72    }
73#endif
74
75private:
76#ifndef NDEBUG
77    static unsigned s_count;
78#endif
79};
80
81class ContainerNode : public Node {
82    friend class PostAttachCallbackDisabler;
83public:
84    virtual ~ContainerNode();
85
86    Node* firstChild() const { return m_firstChild; }
87    Node* lastChild() const { return m_lastChild; }
88    bool hasChildNodes() const { return m_firstChild; }
89
90    // ParentNode interface API
91    PassRefPtr<HTMLCollection> children();
92    Element* firstElementChild() const;
93    Element* lastElementChild() const;
94    unsigned childElementCount() const;
95
96    unsigned childNodeCount() const;
97    Node* childNode(unsigned index) const;
98
99    void insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachNow);
100    void replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachNow);
101    void removeChild(Node* child, ExceptionState& = ASSERT_NO_EXCEPTION);
102    void appendChild(PassRefPtr<Node> newChild, ExceptionState& = ASSERT_NO_EXCEPTION, AttachBehavior = AttachNow);
103
104    // These methods are only used during parsing.
105    // They don't send DOM mutation events or handle reparenting.
106    // However, arbitrary code may be run by beforeload handlers.
107    void parserAppendChild(PassRefPtr<Node>);
108    void parserRemoveChild(Node*);
109    void parserInsertBefore(PassRefPtr<Node> newChild, Node* refChild);
110
111    void removeChildren();
112    void takeAllChildrenFrom(ContainerNode*);
113
114    void cloneChildNodes(ContainerNode* clone);
115
116    virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
117    virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
118    virtual LayoutRect boundingBox() const OVERRIDE;
119    virtual void setFocus(bool) OVERRIDE;
120    virtual void setActive(bool active = true, bool pause = false) OVERRIDE;
121    virtual void setHovered(bool = true) OVERRIDE;
122
123    // -----------------------------------------------------------------------------
124    // Notification of document structure changes (see core/dom/Node.h for more notification methods)
125
126    // Notifies the node that it's list of children have changed (either by adding or removing child nodes), or a child
127    // node that is of the type CDATA_SECTION_NODE, TEXT_NODE or COMMENT_NODE has changed its value.
128    virtual void childrenChanged(bool createdByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
129
130    void disconnectDescendantFrames();
131
132    virtual bool childShouldCreateRenderer(const NodeRenderingContext&) const { return true; }
133
134protected:
135    ContainerNode(TreeScope*, ConstructionType = CreateContainer);
136
137    static void queuePostAttachCallback(NodeCallback, Node*);
138    static bool postAttachCallbacksAreSuspended();
139
140    template<class GenericNode, class GenericNodeContainer>
141    friend void appendChildToContainer(GenericNode* child, GenericNodeContainer*);
142
143    template<class GenericNode, class GenericNodeContainer>
144    friend void Private::addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer*);
145
146    void removeDetachedChildren();
147    void setFirstChild(Node* child) { m_firstChild = child; }
148    void setLastChild(Node* child) { m_lastChild = child; }
149
150private:
151    void removeBetween(Node* previousChild, Node* nextChild, Node* oldChild);
152    void insertBeforeCommon(Node* nextChild, Node* oldChild);
153
154    void attachChildren(const AttachContext& = AttachContext());
155    void detachChildren(const AttachContext& = AttachContext());
156
157    static void dispatchPostAttachCallbacks();
158
159    void suspendPostAttachCallbacks();
160    void resumePostAttachCallbacks();
161
162    bool getUpperLeftCorner(FloatPoint&) const;
163    bool getLowerRightCorner(FloatPoint&) const;
164
165    Node* m_firstChild;
166    Node* m_lastChild;
167};
168
169#ifndef NDEBUG
170bool childAttachedAllowedWhenAttachingChildren(ContainerNode*);
171#endif
172
173inline ContainerNode* toContainerNode(Node* node)
174{
175    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isContainerNode());
176    return static_cast<ContainerNode*>(node);
177}
178
179inline const ContainerNode* toContainerNode(const Node* node)
180{
181    ASSERT_WITH_SECURITY_IMPLICATION(!node || node->isContainerNode());
182    return static_cast<const ContainerNode*>(node);
183}
184
185// This will catch anyone doing an unnecessary cast.
186void toContainerNode(const ContainerNode*);
187
188inline ContainerNode::ContainerNode(TreeScope* treeScope, ConstructionType type)
189    : Node(treeScope, type)
190    , m_firstChild(0)
191    , m_lastChild(0)
192{
193}
194
195inline void ContainerNode::attachChildren(const AttachContext& context)
196{
197    AttachContext childrenContext(context);
198    childrenContext.resolvedStyle = 0;
199
200    for (Node* child = firstChild(); child; child = child->nextSibling()) {
201        ASSERT(!child->attached() || childAttachedAllowedWhenAttachingChildren(this));
202        if (!child->attached())
203            child->attach(childrenContext);
204    }
205}
206
207inline void ContainerNode::detachChildren(const AttachContext& context)
208{
209    AttachContext childrenContext(context);
210    childrenContext.resolvedStyle = 0;
211
212    for (Node* child = firstChild(); child; child = child->nextSibling())
213        child->detach(childrenContext);
214}
215
216inline unsigned Node::childNodeCount() const
217{
218    if (!isContainerNode())
219        return 0;
220    return toContainerNode(this)->childNodeCount();
221}
222
223inline Node* Node::childNode(unsigned index) const
224{
225    if (!isContainerNode())
226        return 0;
227    return toContainerNode(this)->childNode(index);
228}
229
230inline Node* Node::firstChild() const
231{
232    if (!isContainerNode())
233        return 0;
234    return toContainerNode(this)->firstChild();
235}
236
237inline Node* Node::lastChild() const
238{
239    if (!isContainerNode())
240        return 0;
241    return toContainerNode(this)->lastChild();
242}
243
244inline Node* Node::highestAncestor() const
245{
246    Node* node = const_cast<Node*>(this);
247    Node* highest = node;
248    for (; node; node = node->parentNode())
249        highest = node;
250    return highest;
251}
252
253// This constant controls how much buffer is initially allocated
254// for a Node Vector that is used to store child Nodes of a given Node.
255// FIXME: Optimize the value.
256const int initialNodeVectorSize = 11;
257typedef Vector<RefPtr<Node>, initialNodeVectorSize> NodeVector;
258
259inline void getChildNodes(Node* node, NodeVector& nodes)
260{
261    ASSERT(!nodes.size());
262    for (Node* child = node->firstChild(); child; child = child->nextSibling())
263        nodes.append(child);
264}
265
266class ChildNodesLazySnapshot {
267    WTF_MAKE_NONCOPYABLE(ChildNodesLazySnapshot);
268    WTF_MAKE_FAST_ALLOCATED;
269public:
270    explicit ChildNodesLazySnapshot(Node* parentNode)
271        : m_currentNode(parentNode->firstChild())
272        , m_currentIndex(0)
273    {
274        m_nextSnapshot = latestSnapshot;
275        latestSnapshot = this;
276    }
277
278    ~ChildNodesLazySnapshot()
279    {
280        latestSnapshot = m_nextSnapshot;
281    }
282
283    // Returns 0 if there is no next Node.
284    PassRefPtr<Node> nextNode()
285    {
286        if (LIKELY(!hasSnapshot())) {
287            RefPtr<Node> node = m_currentNode;
288            if (node)
289                m_currentNode = node->nextSibling();
290            return node.release();
291        }
292        Vector<RefPtr<Node> >& nodeVector = *m_childNodes;
293        if (m_currentIndex >= nodeVector.size())
294            return 0;
295        return nodeVector[m_currentIndex++];
296    }
297
298    void takeSnapshot()
299    {
300        if (hasSnapshot())
301            return;
302        m_childNodes = adoptPtr(new Vector<RefPtr<Node> >());
303        Node* node = m_currentNode.get();
304        while (node) {
305            m_childNodes->append(node);
306            node = node->nextSibling();
307        }
308    }
309
310    ChildNodesLazySnapshot* nextSnapshot() { return m_nextSnapshot; }
311    bool hasSnapshot() { return !!m_childNodes.get(); }
312
313    static void takeChildNodesLazySnapshot()
314    {
315        ChildNodesLazySnapshot* snapshot = latestSnapshot;
316        while (snapshot && !snapshot->hasSnapshot()) {
317            snapshot->takeSnapshot();
318            snapshot = snapshot->nextSnapshot();
319        }
320    }
321
322private:
323    static ChildNodesLazySnapshot* latestSnapshot;
324
325    RefPtr<Node> m_currentNode;
326    unsigned m_currentIndex;
327    OwnPtr<Vector<RefPtr<Node> > > m_childNodes; // Lazily instantiated.
328    ChildNodesLazySnapshot* m_nextSnapshot;
329};
330
331class PostAttachCallbackDisabler {
332public:
333    PostAttachCallbackDisabler(ContainerNode* node)
334        : m_node(node)
335    {
336        ASSERT(m_node);
337        m_node->suspendPostAttachCallbacks();
338    }
339
340    ~PostAttachCallbackDisabler()
341    {
342        m_node->resumePostAttachCallbacks();
343    }
344
345private:
346    ContainerNode* m_node;
347};
348
349} // namespace WebCore
350
351#endif // ContainerNode_h
352