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.
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.
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.
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.
24 #ifndef ContainerNode_h
25 #define ContainerNode_h
27 #include "bindings/v8/ExceptionStatePlaceholder.h"
28 #include "core/dom/Node.h"
29 #include "wtf/OwnPtr.h"
30 #include "wtf/Vector.h"
39 template<class GenericNode, class GenericNodeContainer>
40 void addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&);
43 class NoEventDispatchAssertion {
45 NoEventDispatchAssertion()
54 ~NoEventDispatchAssertion()
65 static bool isEventDispatchForbidden()
75 static unsigned s_count;
79 enum DynamicRestyleFlags {
80 ChildrenAffectedByFocus = 1 << 0,
81 ChildrenAffectedByHover = 1 << 1,
82 ChildrenAffectedByActive = 1 << 2,
83 ChildrenAffectedByDrag = 1 << 3,
84 ChildrenAffectedByFirstChildRules = 1 << 4,
85 ChildrenAffectedByLastChildRules = 1 << 5,
86 ChildrenAffectedByDirectAdjacentRules = 1 << 6,
87 ChildrenAffectedByIndirectAdjacentRules = 1 << 7,
88 ChildrenAffectedByForwardPositionalRules = 1 << 8,
89 ChildrenAffectedByBackwardPositionalRules = 1 << 9,
91 NumberOfDynamicRestyleFlags = 10,
94 class ContainerNode : public Node {
96 virtual ~ContainerNode();
98 Node* firstChild() const { return m_firstChild; }
99 Node* lastChild() const { return m_lastChild; }
100 bool hasChildren() const { return m_firstChild; }
102 bool hasOneChild() const { return m_firstChild && !m_firstChild->nextSibling(); }
103 bool hasOneTextChild() const { return hasOneChild() && m_firstChild->isTextNode(); }
104 bool hasChildCount(unsigned) const;
106 PassRefPtr<HTMLCollection> children();
108 unsigned countChildren() const;
109 Node* traverseToChildAt(unsigned index) const;
111 PassRefPtr<Element> querySelector(const AtomicString& selectors, ExceptionState&);
112 PassRefPtr<NodeList> querySelectorAll(const AtomicString& selectors, ExceptionState&);
114 void insertBefore(PassRefPtr<Node> newChild, Node* refChild, ExceptionState& = ASSERT_NO_EXCEPTION);
115 void replaceChild(PassRefPtr<Node> newChild, Node* oldChild, ExceptionState& = ASSERT_NO_EXCEPTION);
116 void removeChild(Node* child, ExceptionState& = ASSERT_NO_EXCEPTION);
117 void appendChild(PassRefPtr<Node> newChild, ExceptionState& = ASSERT_NO_EXCEPTION);
119 Element* getElementById(const AtomicString& id) const;
120 PassRefPtr<HTMLCollection> getElementsByTagName(const AtomicString&);
121 PassRefPtr<HTMLCollection> getElementsByTagNameNS(const AtomicString& namespaceURI, const AtomicString& localName);
122 PassRefPtr<NodeList> getElementsByName(const AtomicString& elementName);
123 PassRefPtr<HTMLCollection> getElementsByClassName(const AtomicString& classNames);
124 PassRefPtr<RadioNodeList> radioNodeList(const AtomicString&, bool onlyMatchImgElements = false);
126 // These methods are only used during parsing.
127 // They don't send DOM mutation events or handle reparenting.
128 void parserAppendChild(PassRefPtr<Node>);
129 void parserRemoveChild(Node&);
130 void parserInsertBefore(PassRefPtr<Node> newChild, Node& refChild);
131 void parserTakeAllChildrenFrom(ContainerNode&);
133 void removeChildren();
135 void cloneChildNodes(ContainerNode* clone);
137 virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
138 virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
139 virtual LayoutRect boundingBox() const OVERRIDE FINAL;
140 virtual void setFocus(bool) OVERRIDE;
141 void focusStateChanged();
142 virtual void setActive(bool = true) OVERRIDE;
143 virtual void setHovered(bool = true) OVERRIDE;
145 bool childrenAffectedByFocus() const { return hasRestyleFlag(ChildrenAffectedByFocus); }
146 void setChildrenAffectedByFocus() { setRestyleFlag(ChildrenAffectedByFocus); }
148 bool childrenAffectedByHover() const { return hasRestyleFlag(ChildrenAffectedByHover); }
149 void setChildrenAffectedByHover() { setRestyleFlag(ChildrenAffectedByHover); }
151 bool childrenAffectedByActive() const { return hasRestyleFlag(ChildrenAffectedByActive); }
152 void setChildrenAffectedByActive() { setRestyleFlag(ChildrenAffectedByActive); }
154 bool childrenAffectedByDrag() const { return hasRestyleFlag(ChildrenAffectedByDrag); }
155 void setChildrenAffectedByDrag() { setRestyleFlag(ChildrenAffectedByDrag); }
157 bool childrenAffectedByPositionalRules() const { return hasRestyleFlag(ChildrenAffectedByForwardPositionalRules) || hasRestyleFlag(ChildrenAffectedByBackwardPositionalRules); }
159 bool childrenAffectedByFirstChildRules() const { return hasRestyleFlag(ChildrenAffectedByFirstChildRules); }
160 void setChildrenAffectedByFirstChildRules() { setRestyleFlag(ChildrenAffectedByFirstChildRules); }
162 bool childrenAffectedByLastChildRules() const { return hasRestyleFlag(ChildrenAffectedByLastChildRules); }
163 void setChildrenAffectedByLastChildRules() { setRestyleFlag(ChildrenAffectedByLastChildRules); }
165 bool childrenAffectedByDirectAdjacentRules() const { return hasRestyleFlag(ChildrenAffectedByDirectAdjacentRules); }
166 void setChildrenAffectedByDirectAdjacentRules() { setRestyleFlag(ChildrenAffectedByDirectAdjacentRules); }
168 bool childrenAffectedByIndirectAdjacentRules() const { return hasRestyleFlag(ChildrenAffectedByIndirectAdjacentRules); }
169 void setChildrenAffectedByIndirectAdjacentRules() { setRestyleFlag(ChildrenAffectedByIndirectAdjacentRules); }
171 bool childrenAffectedByForwardPositionalRules() const { return hasRestyleFlag(ChildrenAffectedByForwardPositionalRules); }
172 void setChildrenAffectedByForwardPositionalRules() { setRestyleFlag(ChildrenAffectedByForwardPositionalRules); }
174 bool childrenAffectedByBackwardPositionalRules() const { return hasRestyleFlag(ChildrenAffectedByBackwardPositionalRules); }
175 void setChildrenAffectedByBackwardPositionalRules() { setRestyleFlag(ChildrenAffectedByBackwardPositionalRules); }
177 // FIXME: These methods should all be renamed to something better than "check",
178 // since it's not clear that they alter the style bits of siblings and children.
179 void checkForChildrenAdjacentRuleChanges();
180 void checkForSiblingStyleChanges(bool finishedParsingCallback, Node* beforeChange, Node* afterChange, int childCountDelta);
182 bool childrenSupportStyleSharing() const { return !hasRestyleFlags(); }
184 // -----------------------------------------------------------------------------
185 // Notification of document structure changes (see core/dom/Node.h for more notification methods)
187 // Notifies the node that it's list of children have changed (either by adding or removing child nodes), or a child
188 // node that is of the type CDATA_SECTION_NODE, TEXT_NODE or COMMENT_NODE has changed its value.
189 virtual void childrenChanged(bool createdByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
191 void disconnectDescendantFrames();
193 virtual void trace(Visitor*) OVERRIDE;
196 ContainerNode(TreeScope*, ConstructionType = CreateContainer);
198 template<class GenericNode, class GenericNodeContainer>
199 friend void appendChildToContainer(GenericNode& child, GenericNodeContainer&);
201 template<class GenericNode, class GenericNodeContainer>
202 friend void Private::addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&);
205 void removeDetachedChildren();
208 void setFirstChild(Node* child) { m_firstChild = child; }
209 void setLastChild(Node* child) { m_lastChild = child; }
212 void removeBetween(Node* previousChild, Node* nextChild, Node& oldChild);
213 void insertBeforeCommon(Node& nextChild, Node& oldChild);
214 void updateTreeAfterInsertion(Node& child);
215 void willRemoveChildren();
216 void willRemoveChild(Node& child);
218 bool hasRestyleFlag(DynamicRestyleFlags mask) const { return hasRareData() && hasRestyleFlagInternal(mask); }
219 bool hasRestyleFlags() const { return hasRareData() && hasRestyleFlagsInternal(); }
220 void setRestyleFlag(DynamicRestyleFlags);
221 bool hasRestyleFlagInternal(DynamicRestyleFlags) const;
222 bool hasRestyleFlagsInternal() const;
224 inline bool checkAcceptChildGuaranteedNodeTypes(const Node& newChild, ExceptionState&) const;
225 inline bool checkAcceptChild(const Node* newChild, const Node* oldChild, ExceptionState&) const;
226 inline bool containsConsideringHostElements(const Node&) const;
227 inline bool isChildTypeAllowed(const Node& child) const;
229 void attachChildren(const AttachContext& = AttachContext());
230 void detachChildren(const AttachContext& = AttachContext());
232 bool getUpperLeftCorner(FloatPoint&) const;
233 bool getLowerRightCorner(FloatPoint&) const;
235 RawPtrWillBeMember<Node> m_firstChild;
236 RawPtrWillBeMember<Node> m_lastChild;
240 bool childAttachedAllowedWhenAttachingChildren(ContainerNode*);
243 DEFINE_NODE_TYPE_CASTS(ContainerNode, isContainerNode());
245 inline bool ContainerNode::hasChildCount(unsigned count) const
247 Node* child = m_firstChild;
248 while (count && child) {
249 child = child->nextSibling();
252 return !count && !child;
255 inline ContainerNode::ContainerNode(TreeScope* treeScope, ConstructionType type)
256 : Node(treeScope, type)
257 , m_firstChild(nullptr)
258 , m_lastChild(nullptr)
262 inline void ContainerNode::attachChildren(const AttachContext& context)
264 AttachContext childrenContext(context);
265 childrenContext.resolvedStyle = 0;
267 for (Node* child = firstChild(); child; child = child->nextSibling()) {
268 ASSERT(child->needsAttach() || childAttachedAllowedWhenAttachingChildren(this));
269 if (child->needsAttach())
270 child->attach(childrenContext);
274 inline void ContainerNode::detachChildren(const AttachContext& context)
276 AttachContext childrenContext(context);
277 childrenContext.resolvedStyle = 0;
279 for (Node* child = firstChild(); child; child = child->nextSibling())
280 child->detach(childrenContext);
283 inline unsigned Node::countChildren() const
285 if (!isContainerNode())
287 return toContainerNode(this)->countChildren();
290 inline Node* Node::traverseToChildAt(unsigned index) const
292 if (!isContainerNode())
294 return toContainerNode(this)->traverseToChildAt(index);
297 inline Node* Node::firstChild() const
299 if (!isContainerNode())
301 return toContainerNode(this)->firstChild();
304 inline Node* Node::lastChild() const
306 if (!isContainerNode())
308 return toContainerNode(this)->lastChild();
311 inline Node& Node::highestAncestorOrSelf() const
313 Node* node = const_cast<Node*>(this);
314 Node* highest = node;
315 for (; node; node = node->parentNode())
320 inline ContainerNode* Node::parentElementOrShadowRoot() const
322 ContainerNode* parent = parentNode();
323 return parent && (parent->isElementNode() || parent->isShadowRoot()) ? parent : 0;
326 // This constant controls how much buffer is initially allocated
327 // for a Node Vector that is used to store child Nodes of a given Node.
328 // FIXME: Optimize the value.
329 const int initialNodeVectorSize = 11;
330 typedef Vector<RefPtr<Node>, initialNodeVectorSize> NodeVector;
332 inline void getChildNodes(Node& node, NodeVector& nodes)
334 ASSERT(!nodes.size());
335 for (Node* child = node.firstChild(); child; child = child->nextSibling())
339 class ChildNodesLazySnapshot {
340 WTF_MAKE_NONCOPYABLE(ChildNodesLazySnapshot);
341 WTF_MAKE_FAST_ALLOCATED;
343 explicit ChildNodesLazySnapshot(Node& parentNode)
344 : m_currentNode(parentNode.firstChild())
347 m_nextSnapshot = latestSnapshot;
348 latestSnapshot = this;
351 ~ChildNodesLazySnapshot()
353 latestSnapshot = m_nextSnapshot;
356 // Returns 0 if there is no next Node.
357 PassRefPtr<Node> nextNode()
359 if (LIKELY(!hasSnapshot())) {
360 RefPtr<Node> node = m_currentNode;
362 m_currentNode = node->nextSibling();
363 return node.release();
365 Vector<RefPtr<Node> >& nodeVector = *m_childNodes;
366 if (m_currentIndex >= nodeVector.size())
368 return nodeVector[m_currentIndex++];
375 m_childNodes = adoptPtr(new Vector<RefPtr<Node> >());
376 Node* node = m_currentNode.get();
378 m_childNodes->append(node);
379 node = node->nextSibling();
383 ChildNodesLazySnapshot* nextSnapshot() { return m_nextSnapshot; }
384 bool hasSnapshot() { return !!m_childNodes.get(); }
386 static void takeChildNodesLazySnapshot()
388 ChildNodesLazySnapshot* snapshot = latestSnapshot;
389 while (snapshot && !snapshot->hasSnapshot()) {
390 snapshot->takeSnapshot();
391 snapshot = snapshot->nextSnapshot();
396 static ChildNodesLazySnapshot* latestSnapshot;
398 RefPtr<Node> m_currentNode;
399 unsigned m_currentIndex;
400 OwnPtr<Vector<RefPtr<Node> > > m_childNodes; // Lazily instantiated.
401 ChildNodesLazySnapshot* m_nextSnapshot;
404 } // namespace WebCore
406 #endif // ContainerNode_h