• 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 ClassCollection;
35 class ExceptionState;
36 class FloatPoint;
37 class HTMLCollection;
38 class StaticNodeList;
39 class TagCollection;
40 
41 namespace Private {
42     template<class GenericNode, class GenericNodeContainer>
43     void addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&);
44 }
45 
46 enum DynamicRestyleFlags {
47     ChildrenOrSiblingsAffectedByFocus = 1 << 0,
48     ChildrenOrSiblingsAffectedByHover = 1 << 1,
49     ChildrenOrSiblingsAffectedByActive = 1 << 2,
50     ChildrenOrSiblingsAffectedByDrag = 1 << 3,
51     ChildrenAffectedByFirstChildRules = 1 << 4,
52     ChildrenAffectedByLastChildRules = 1 << 5,
53     ChildrenAffectedByDirectAdjacentRules = 1 << 6,
54     ChildrenAffectedByIndirectAdjacentRules = 1 << 7,
55     ChildrenAffectedByForwardPositionalRules = 1 << 8,
56     ChildrenAffectedByBackwardPositionalRules = 1 << 9,
57 
58     NumberOfDynamicRestyleFlags = 10,
59 };
60 
61 // This constant controls how much buffer is initially allocated
62 // for a Node Vector that is used to store child Nodes of a given Node.
63 // FIXME: Optimize the value.
64 const int initialNodeVectorSize = 11;
65 typedef WillBeHeapVector<RefPtrWillBeMember<Node>, initialNodeVectorSize> NodeVector;
66 
67 class ContainerNode : public Node {
68 public:
69     virtual ~ContainerNode();
70 
firstChild()71     Node* firstChild() const { return m_firstChild; }
lastChild()72     Node* lastChild() const { return m_lastChild; }
hasChildren()73     bool hasChildren() const { return m_firstChild; }
74 
hasOneChild()75     bool hasOneChild() const { return m_firstChild && !m_firstChild->nextSibling(); }
hasOneTextChild()76     bool hasOneTextChild() const { return hasOneChild() && m_firstChild->isTextNode(); }
77     bool hasChildCount(unsigned) const;
78 
79     PassRefPtrWillBeRawPtr<HTMLCollection> children();
80 
81     unsigned countChildren() const;
82     Node* traverseToChildAt(unsigned index) const;
83 
84     PassRefPtrWillBeRawPtr<Element> querySelector(const AtomicString& selectors, ExceptionState&);
85     PassRefPtrWillBeRawPtr<StaticNodeList> querySelectorAll(const AtomicString& selectors, ExceptionState&);
86 
87     void insertBefore(PassRefPtrWillBeRawPtr<Node> newChild, Node* refChild, ExceptionState& = ASSERT_NO_EXCEPTION);
88     void replaceChild(PassRefPtrWillBeRawPtr<Node> newChild, Node* oldChild, ExceptionState& = ASSERT_NO_EXCEPTION);
89     void removeChild(Node* child, ExceptionState& = ASSERT_NO_EXCEPTION);
90     void appendChild(PassRefPtrWillBeRawPtr<Node> newChild, ExceptionState& = ASSERT_NO_EXCEPTION);
91 
92     Element* getElementById(const AtomicString& id) const;
93     PassRefPtrWillBeRawPtr<TagCollection> getElementsByTagName(const AtomicString&);
94     PassRefPtrWillBeRawPtr<TagCollection> getElementsByTagNameNS(const AtomicString& namespaceURI, const AtomicString& localName);
95     PassRefPtrWillBeRawPtr<NameNodeList> getElementsByName(const AtomicString& elementName);
96     PassRefPtrWillBeRawPtr<ClassCollection> getElementsByClassName(const AtomicString& classNames);
97     PassRefPtrWillBeRawPtr<RadioNodeList> radioNodeList(const AtomicString&, bool onlyMatchImgElements = false);
98 
99     // These methods are only used during parsing.
100     // They don't send DOM mutation events or handle reparenting.
101     void parserAppendChild(PassRefPtrWillBeRawPtr<Node>);
102     void parserRemoveChild(Node&);
103     void parserInsertBefore(PassRefPtrWillBeRawPtr<Node> newChild, Node& refChild);
104     void parserTakeAllChildrenFrom(ContainerNode&);
105 
106     void removeChildren();
107 
108     void cloneChildNodes(ContainerNode* clone);
109 
110     virtual void attach(const AttachContext& = AttachContext()) OVERRIDE;
111     virtual void detach(const AttachContext& = AttachContext()) OVERRIDE;
112     virtual LayoutRect boundingBox() const OVERRIDE FINAL;
113     virtual void setFocus(bool) OVERRIDE;
114     void focusStateChanged();
115     virtual void setActive(bool = true) OVERRIDE;
116     virtual void setHovered(bool = true) OVERRIDE;
117 
childrenOrSiblingsAffectedByFocus()118     bool childrenOrSiblingsAffectedByFocus() const { return hasRestyleFlag(ChildrenOrSiblingsAffectedByFocus); }
setChildrenOrSiblingsAffectedByFocus()119     void setChildrenOrSiblingsAffectedByFocus() { setRestyleFlag(ChildrenOrSiblingsAffectedByFocus); }
120 
childrenOrSiblingsAffectedByHover()121     bool childrenOrSiblingsAffectedByHover() const { return hasRestyleFlag(ChildrenOrSiblingsAffectedByHover); }
setChildrenOrSiblingsAffectedByHover()122     void setChildrenOrSiblingsAffectedByHover() { setRestyleFlag(ChildrenOrSiblingsAffectedByHover); }
123 
childrenOrSiblingsAffectedByActive()124     bool childrenOrSiblingsAffectedByActive() const { return hasRestyleFlag(ChildrenOrSiblingsAffectedByActive); }
setChildrenOrSiblingsAffectedByActive()125     void setChildrenOrSiblingsAffectedByActive() { setRestyleFlag(ChildrenOrSiblingsAffectedByActive); }
126 
childrenOrSiblingsAffectedByDrag()127     bool childrenOrSiblingsAffectedByDrag() const { return hasRestyleFlag(ChildrenOrSiblingsAffectedByDrag); }
setChildrenOrSiblingsAffectedByDrag()128     void setChildrenOrSiblingsAffectedByDrag() { setRestyleFlag(ChildrenOrSiblingsAffectedByDrag); }
129 
childrenAffectedByPositionalRules()130     bool childrenAffectedByPositionalRules() const { return hasRestyleFlag(ChildrenAffectedByForwardPositionalRules) || hasRestyleFlag(ChildrenAffectedByBackwardPositionalRules); }
131 
childrenAffectedByFirstChildRules()132     bool childrenAffectedByFirstChildRules() const { return hasRestyleFlag(ChildrenAffectedByFirstChildRules); }
setChildrenAffectedByFirstChildRules()133     void setChildrenAffectedByFirstChildRules() { setRestyleFlag(ChildrenAffectedByFirstChildRules); }
134 
childrenAffectedByLastChildRules()135     bool childrenAffectedByLastChildRules() const { return hasRestyleFlag(ChildrenAffectedByLastChildRules); }
setChildrenAffectedByLastChildRules()136     void setChildrenAffectedByLastChildRules() { setRestyleFlag(ChildrenAffectedByLastChildRules); }
137 
childrenAffectedByDirectAdjacentRules()138     bool childrenAffectedByDirectAdjacentRules() const { return hasRestyleFlag(ChildrenAffectedByDirectAdjacentRules); }
setChildrenAffectedByDirectAdjacentRules()139     void setChildrenAffectedByDirectAdjacentRules() { setRestyleFlag(ChildrenAffectedByDirectAdjacentRules); }
140 
childrenAffectedByIndirectAdjacentRules()141     bool childrenAffectedByIndirectAdjacentRules() const { return hasRestyleFlag(ChildrenAffectedByIndirectAdjacentRules); }
setChildrenAffectedByIndirectAdjacentRules()142     void setChildrenAffectedByIndirectAdjacentRules() { setRestyleFlag(ChildrenAffectedByIndirectAdjacentRules); }
143 
childrenAffectedByForwardPositionalRules()144     bool childrenAffectedByForwardPositionalRules() const { return hasRestyleFlag(ChildrenAffectedByForwardPositionalRules); }
setChildrenAffectedByForwardPositionalRules()145     void setChildrenAffectedByForwardPositionalRules() { setRestyleFlag(ChildrenAffectedByForwardPositionalRules); }
146 
childrenAffectedByBackwardPositionalRules()147     bool childrenAffectedByBackwardPositionalRules() const { return hasRestyleFlag(ChildrenAffectedByBackwardPositionalRules); }
setChildrenAffectedByBackwardPositionalRules()148     void setChildrenAffectedByBackwardPositionalRules() { setRestyleFlag(ChildrenAffectedByBackwardPositionalRules); }
149 
150     // FIXME: These methods should all be renamed to something better than "check",
151     // since it's not clear that they alter the style bits of siblings and children.
152     void checkForChildrenAdjacentRuleChanges();
153     void checkForSiblingStyleChanges(bool finishedParsingCallback, Node* beforeChange, Node* afterChange, int childCountDelta);
154 
childrenSupportStyleSharing()155     bool childrenSupportStyleSharing() const { return !hasRestyleFlags(); }
156 
157     // -----------------------------------------------------------------------------
158     // Notification of document structure changes (see core/dom/Node.h for more notification methods)
159 
160     // Notifies the node that it's list of children have changed (either by adding or removing child nodes), or a child
161     // node that is of the type CDATA_SECTION_NODE, TEXT_NODE or COMMENT_NODE has changed its value.
162     virtual void childrenChanged(bool createdByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
163 
164     void disconnectDescendantFrames();
165 
166     virtual void trace(Visitor*) OVERRIDE;
167 
168     enum ChildrenChangeSource { ChildrenChangeSourceAPI, ChildrenChangeSourceParser };
169     void notifyNodeInserted(Node&, ChildrenChangeSource = ChildrenChangeSourceAPI);
170     void notifyNodeRemoved(Node&);
171 
172 protected:
173     ContainerNode(TreeScope*, ConstructionType = CreateContainer);
174 
175     template<class GenericNode, class GenericNodeContainer>
176     friend void Private::addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&);
177 
178 #if !ENABLE(OILPAN)
179     void removeDetachedChildren();
180 #endif
181 
setFirstChild(Node * child)182     void setFirstChild(Node* child) { m_firstChild = child; }
setLastChild(Node * child)183     void setLastChild(Node* child) { m_lastChild = child; }
184 
185 private:
186     void removeBetween(Node* previousChild, Node* nextChild, Node& oldChild);
187     void insertBeforeCommon(Node& nextChild, Node& oldChild);
188     void appendChildCommon(Node& child);
189     void updateTreeAfterInsertion(Node& child);
190     void willRemoveChildren();
191     void willRemoveChild(Node& child);
192 
193     void notifyNodeInsertedInternal(Node&, NodeVector& postInsertionNotificationTargets);
194 
hasRestyleFlag(DynamicRestyleFlags mask)195     bool hasRestyleFlag(DynamicRestyleFlags mask) const { return hasRareData() && hasRestyleFlagInternal(mask); }
hasRestyleFlags()196     bool hasRestyleFlags() const { return hasRareData() && hasRestyleFlagsInternal(); }
197     void setRestyleFlag(DynamicRestyleFlags);
198     bool hasRestyleFlagInternal(DynamicRestyleFlags) const;
199     bool hasRestyleFlagsInternal() const;
200 
201     inline bool checkAcceptChildGuaranteedNodeTypes(const Node& newChild, ExceptionState&) const;
202     inline bool checkAcceptChild(const Node* newChild, const Node* oldChild, ExceptionState&) const;
203     inline bool containsConsideringHostElements(const Node&) const;
204     inline bool isChildTypeAllowed(const Node& child) const;
205 
206     void attachChildren(const AttachContext& = AttachContext());
207     void detachChildren(const AttachContext& = AttachContext());
208 
209     bool getUpperLeftCorner(FloatPoint&) const;
210     bool getLowerRightCorner(FloatPoint&) const;
211 
212     RawPtrWillBeMember<Node> m_firstChild;
213     RawPtrWillBeMember<Node> m_lastChild;
214 };
215 
216 #ifndef NDEBUG
217 bool childAttachedAllowedWhenAttachingChildren(ContainerNode*);
218 #endif
219 
220 DEFINE_NODE_TYPE_CASTS(ContainerNode, isContainerNode());
221 
hasChildCount(unsigned count)222 inline bool ContainerNode::hasChildCount(unsigned count) const
223 {
224     Node* child = m_firstChild;
225     while (count && child) {
226         child = child->nextSibling();
227         --count;
228     }
229     return !count && !child;
230 }
231 
ContainerNode(TreeScope * treeScope,ConstructionType type)232 inline ContainerNode::ContainerNode(TreeScope* treeScope, ConstructionType type)
233     : Node(treeScope, type)
234     , m_firstChild(nullptr)
235     , m_lastChild(nullptr)
236 {
237 }
238 
attachChildren(const AttachContext & context)239 inline void ContainerNode::attachChildren(const AttachContext& context)
240 {
241     AttachContext childrenContext(context);
242     childrenContext.resolvedStyle = 0;
243 
244     for (Node* child = firstChild(); child; child = child->nextSibling()) {
245         ASSERT(child->needsAttach() || childAttachedAllowedWhenAttachingChildren(this));
246         if (child->needsAttach())
247             child->attach(childrenContext);
248     }
249 }
250 
detachChildren(const AttachContext & context)251 inline void ContainerNode::detachChildren(const AttachContext& context)
252 {
253     AttachContext childrenContext(context);
254     childrenContext.resolvedStyle = 0;
255 
256     for (Node* child = firstChild(); child; child = child->nextSibling())
257         child->detach(childrenContext);
258 }
259 
countChildren()260 inline unsigned Node::countChildren() const
261 {
262     if (!isContainerNode())
263         return 0;
264     return toContainerNode(this)->countChildren();
265 }
266 
traverseToChildAt(unsigned index)267 inline Node* Node::traverseToChildAt(unsigned index) const
268 {
269     if (!isContainerNode())
270         return 0;
271     return toContainerNode(this)->traverseToChildAt(index);
272 }
273 
firstChild()274 inline Node* Node::firstChild() const
275 {
276     if (!isContainerNode())
277         return 0;
278     return toContainerNode(this)->firstChild();
279 }
280 
lastChild()281 inline Node* Node::lastChild() const
282 {
283     if (!isContainerNode())
284         return 0;
285     return toContainerNode(this)->lastChild();
286 }
287 
highestAncestorOrSelf()288 inline Node& Node::highestAncestorOrSelf() const
289 {
290     Node* node = const_cast<Node*>(this);
291     Node* highest = node;
292     for (; node; node = node->parentNode())
293         highest = node;
294     return *highest;
295 }
296 
parentElementOrShadowRoot()297 inline ContainerNode* Node::parentElementOrShadowRoot() const
298 {
299     ContainerNode* parent = parentNode();
300     return parent && (parent->isElementNode() || parent->isShadowRoot()) ? parent : 0;
301 }
302 
parentElementOrDocumentFragment()303 inline ContainerNode* Node::parentElementOrDocumentFragment() const
304 {
305     ContainerNode* parent = parentNode();
306     return parent && (parent->isElementNode() || parent->isDocumentFragment()) ? parent : 0;
307 }
308 
getChildNodes(Node & node,NodeVector & nodes)309 inline void getChildNodes(Node& node, NodeVector& nodes)
310 {
311     ASSERT(!nodes.size());
312     for (Node* child = node.firstChild(); child; child = child->nextSibling())
313         nodes.append(child);
314 }
315 
316 } // namespace WebCore
317 
318 #endif // ContainerNode_h
319