• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
32 namespace WebCore {
33 
34 class ExceptionState;
35 class FloatPoint;
36 class HTMLCollection;
37 
38 namespace Private {
39     template<class GenericNode, class GenericNodeContainer>
40     void addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&);
41 }
42 
43 class NoEventDispatchAssertion {
44 public:
NoEventDispatchAssertion()45     NoEventDispatchAssertion()
46     {
47 #ifndef NDEBUG
48         if (!isMainThread())
49             return;
50         s_count++;
51 #endif
52     }
53 
~NoEventDispatchAssertion()54     ~NoEventDispatchAssertion()
55     {
56 #ifndef NDEBUG
57         if (!isMainThread())
58             return;
59         ASSERT(s_count);
60         s_count--;
61 #endif
62     }
63 
64 #ifndef NDEBUG
isEventDispatchForbidden()65     static bool isEventDispatchForbidden()
66     {
67         if (!isMainThread())
68             return false;
69         return s_count;
70     }
71 #endif
72 
73 private:
74 #ifndef NDEBUG
75     static unsigned s_count;
76 #endif
77 };
78 
79 class ContainerNode : public Node {
80 public:
81     virtual ~ContainerNode();
82 
firstChild()83     Node* firstChild() const { return m_firstChild; }
lastChild()84     Node* lastChild() const { return m_lastChild; }
hasChildNodes()85     bool hasChildNodes() const { return m_firstChild; }
86 
hasOneChild()87     bool hasOneChild() const { return m_firstChild && !m_firstChild->nextSibling(); }
hasOneTextChild()88     bool hasOneTextChild() const { return hasOneChild() && m_firstChild->isTextNode(); }
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);
100     void replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionState& = ASSERT_NO_EXCEPTION);
101     void removeChild(Node* child, ExceptionState& = ASSERT_NO_EXCEPTION);
102     void appendChild(PassRefPtr<Node> newChild, ExceptionState& = ASSERT_NO_EXCEPTION);
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     void parserTakeAllChildrenFrom(ContainerNode&);
111 
112     void removeChildren();
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     void focusStateChanged();
121     virtual void setActive(bool = true) OVERRIDE;
122     virtual void setHovered(bool = true) OVERRIDE;
123 
124     // -----------------------------------------------------------------------------
125     // Notification of document structure changes (see core/dom/Node.h for more notification methods)
126 
127     // Notifies the node that it's list of children have changed (either by adding or removing child nodes), or a child
128     // node that is of the type CDATA_SECTION_NODE, TEXT_NODE or COMMENT_NODE has changed its value.
129     virtual void childrenChanged(bool createdByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
130 
131     void disconnectDescendantFrames();
132 
childShouldCreateRenderer(const Node & child)133     virtual bool childShouldCreateRenderer(const Node& child) const { return true; }
134 
135 protected:
136     ContainerNode(TreeScope*, ConstructionType = CreateContainer);
137 
138     template<class GenericNode, class GenericNodeContainer>
139     friend void appendChildToContainer(GenericNode& child, GenericNodeContainer&);
140 
141     template<class GenericNode, class GenericNodeContainer>
142     friend void Private::addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&);
143 
144     void removeDetachedChildren();
setFirstChild(Node * child)145     void setFirstChild(Node* child) { m_firstChild = child; }
setLastChild(Node * child)146     void setLastChild(Node* child) { m_lastChild = child; }
147 
148 private:
149     void removeBetween(Node* previousChild, Node* nextChild, Node& oldChild);
150     void insertBeforeCommon(Node& nextChild, Node& oldChild);
151     void updateTreeAfterInsertion(Node& child);
152     void willRemoveChildren();
153     void willRemoveChild(Node& child);
154 
155     inline bool checkAcceptChildGuaranteedNodeTypes(const Node& newChild, ExceptionState&) const;
156     inline bool checkAcceptChild(const Node* newChild, const Node* oldChild, ExceptionState&) const;
157     inline bool containsConsideringHostElements(const Node&) const;
158     inline bool isChildTypeAllowed(const Node& child) const;
159 
160     void attachChildren(const AttachContext& = AttachContext());
161     void detachChildren(const AttachContext& = AttachContext());
162 
163     bool getUpperLeftCorner(FloatPoint&) const;
164     bool getLowerRightCorner(FloatPoint&) const;
165 
166     Node* m_firstChild;
167     Node* m_lastChild;
168 };
169 
170 #ifndef NDEBUG
171 bool childAttachedAllowedWhenAttachingChildren(ContainerNode*);
172 #endif
173 
174 DEFINE_NODE_TYPE_CASTS(ContainerNode, isContainerNode());
175 
ContainerNode(TreeScope * treeScope,ConstructionType type)176 inline ContainerNode::ContainerNode(TreeScope* treeScope, ConstructionType type)
177     : Node(treeScope, type)
178     , m_firstChild(0)
179     , m_lastChild(0)
180 {
181 }
182 
attachChildren(const AttachContext & context)183 inline void ContainerNode::attachChildren(const AttachContext& context)
184 {
185     AttachContext childrenContext(context);
186     childrenContext.resolvedStyle = 0;
187 
188     for (Node* child = firstChild(); child; child = child->nextSibling()) {
189         ASSERT(child->needsAttach() || childAttachedAllowedWhenAttachingChildren(this));
190         if (child->needsAttach())
191             child->attach(childrenContext);
192     }
193 }
194 
detachChildren(const AttachContext & context)195 inline void ContainerNode::detachChildren(const AttachContext& context)
196 {
197     AttachContext childrenContext(context);
198     childrenContext.resolvedStyle = 0;
199 
200     for (Node* child = firstChild(); child; child = child->nextSibling())
201         child->detach(childrenContext);
202 }
203 
childNodeCount()204 inline unsigned Node::childNodeCount() const
205 {
206     if (!isContainerNode())
207         return 0;
208     return toContainerNode(this)->childNodeCount();
209 }
210 
childNode(unsigned index)211 inline Node* Node::childNode(unsigned index) const
212 {
213     if (!isContainerNode())
214         return 0;
215     return toContainerNode(this)->childNode(index);
216 }
217 
firstChild()218 inline Node* Node::firstChild() const
219 {
220     if (!isContainerNode())
221         return 0;
222     return toContainerNode(this)->firstChild();
223 }
224 
lastChild()225 inline Node* Node::lastChild() const
226 {
227     if (!isContainerNode())
228         return 0;
229     return toContainerNode(this)->lastChild();
230 }
231 
highestAncestor()232 inline Node* Node::highestAncestor() const
233 {
234     Node* node = const_cast<Node*>(this);
235     Node* highest = node;
236     for (; node; node = node->parentNode())
237         highest = node;
238     return highest;
239 }
240 
241 // This constant controls how much buffer is initially allocated
242 // for a Node Vector that is used to store child Nodes of a given Node.
243 // FIXME: Optimize the value.
244 const int initialNodeVectorSize = 11;
245 typedef Vector<RefPtr<Node>, initialNodeVectorSize> NodeVector;
246 
getChildNodes(Node & node,NodeVector & nodes)247 inline void getChildNodes(Node& node, NodeVector& nodes)
248 {
249     ASSERT(!nodes.size());
250     for (Node* child = node.firstChild(); child; child = child->nextSibling())
251         nodes.append(child);
252 }
253 
254 class ChildNodesLazySnapshot {
255     WTF_MAKE_NONCOPYABLE(ChildNodesLazySnapshot);
256     WTF_MAKE_FAST_ALLOCATED;
257 public:
ChildNodesLazySnapshot(Node & parentNode)258     explicit ChildNodesLazySnapshot(Node& parentNode)
259         : m_currentNode(parentNode.firstChild())
260         , m_currentIndex(0)
261     {
262         m_nextSnapshot = latestSnapshot;
263         latestSnapshot = this;
264     }
265 
~ChildNodesLazySnapshot()266     ~ChildNodesLazySnapshot()
267     {
268         latestSnapshot = m_nextSnapshot;
269     }
270 
271     // Returns 0 if there is no next Node.
nextNode()272     PassRefPtr<Node> nextNode()
273     {
274         if (LIKELY(!hasSnapshot())) {
275             RefPtr<Node> node = m_currentNode;
276             if (node)
277                 m_currentNode = node->nextSibling();
278             return node.release();
279         }
280         Vector<RefPtr<Node> >& nodeVector = *m_childNodes;
281         if (m_currentIndex >= nodeVector.size())
282             return 0;
283         return nodeVector[m_currentIndex++];
284     }
285 
takeSnapshot()286     void takeSnapshot()
287     {
288         if (hasSnapshot())
289             return;
290         m_childNodes = adoptPtr(new Vector<RefPtr<Node> >());
291         Node* node = m_currentNode.get();
292         while (node) {
293             m_childNodes->append(node);
294             node = node->nextSibling();
295         }
296     }
297 
nextSnapshot()298     ChildNodesLazySnapshot* nextSnapshot() { return m_nextSnapshot; }
hasSnapshot()299     bool hasSnapshot() { return !!m_childNodes.get(); }
300 
takeChildNodesLazySnapshot()301     static void takeChildNodesLazySnapshot()
302     {
303         ChildNodesLazySnapshot* snapshot = latestSnapshot;
304         while (snapshot && !snapshot->hasSnapshot()) {
305             snapshot->takeSnapshot();
306             snapshot = snapshot->nextSnapshot();
307         }
308     }
309 
310 private:
311     static ChildNodesLazySnapshot* latestSnapshot;
312 
313     RefPtr<Node> m_currentNode;
314     unsigned m_currentIndex;
315     OwnPtr<Vector<RefPtr<Node> > > m_childNodes; // Lazily instantiated.
316     ChildNodesLazySnapshot* m_nextSnapshot;
317 };
318 
319 } // namespace WebCore
320 
321 #endif // ContainerNode_h
322