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