Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / dom / ContainerNode.h
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:
45     NoEventDispatchAssertion()
46     {
47 #ifndef NDEBUG
48         if (!isMainThread())
49             return;
50         s_count++;
51 #endif
52     }
53
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
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 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,
90
91     NumberOfDynamicRestyleFlags = 10,
92 };
93
94 class ContainerNode : public Node {
95 public:
96     virtual ~ContainerNode();
97
98     Node* firstChild() const { return m_firstChild; }
99     Node* lastChild() const { return m_lastChild; }
100     bool hasChildren() const { return m_firstChild; }
101
102     bool hasOneChild() const { return m_firstChild && !m_firstChild->nextSibling(); }
103     bool hasOneTextChild() const { return hasOneChild() && m_firstChild->isTextNode(); }
104     bool hasChildCount(unsigned) const;
105
106     PassRefPtr<HTMLCollection> children();
107
108     unsigned countChildren() const;
109     Node* traverseToChildAt(unsigned index) const;
110
111     PassRefPtr<Element> querySelector(const AtomicString& selectors, ExceptionState&);
112     PassRefPtr<NodeList> querySelectorAll(const AtomicString& selectors, ExceptionState&);
113
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);
118
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);
125
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&);
132
133     void removeChildren();
134
135     void cloneChildNodes(ContainerNode* clone);
136
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;
144
145     bool childrenAffectedByFocus() const { return hasRestyleFlag(ChildrenAffectedByFocus); }
146     void setChildrenAffectedByFocus() { setRestyleFlag(ChildrenAffectedByFocus); }
147
148     bool childrenAffectedByHover() const { return hasRestyleFlag(ChildrenAffectedByHover); }
149     void setChildrenAffectedByHover() { setRestyleFlag(ChildrenAffectedByHover); }
150
151     bool childrenAffectedByActive() const { return hasRestyleFlag(ChildrenAffectedByActive); }
152     void setChildrenAffectedByActive() { setRestyleFlag(ChildrenAffectedByActive); }
153
154     bool childrenAffectedByDrag() const { return hasRestyleFlag(ChildrenAffectedByDrag); }
155     void setChildrenAffectedByDrag() { setRestyleFlag(ChildrenAffectedByDrag); }
156
157     bool childrenAffectedByPositionalRules() const { return hasRestyleFlag(ChildrenAffectedByForwardPositionalRules) || hasRestyleFlag(ChildrenAffectedByBackwardPositionalRules); }
158
159     bool childrenAffectedByFirstChildRules() const { return hasRestyleFlag(ChildrenAffectedByFirstChildRules); }
160     void setChildrenAffectedByFirstChildRules() { setRestyleFlag(ChildrenAffectedByFirstChildRules); }
161
162     bool childrenAffectedByLastChildRules() const { return hasRestyleFlag(ChildrenAffectedByLastChildRules); }
163     void setChildrenAffectedByLastChildRules() { setRestyleFlag(ChildrenAffectedByLastChildRules); }
164
165     bool childrenAffectedByDirectAdjacentRules() const { return hasRestyleFlag(ChildrenAffectedByDirectAdjacentRules); }
166     void setChildrenAffectedByDirectAdjacentRules() { setRestyleFlag(ChildrenAffectedByDirectAdjacentRules); }
167
168     bool childrenAffectedByIndirectAdjacentRules() const { return hasRestyleFlag(ChildrenAffectedByIndirectAdjacentRules); }
169     void setChildrenAffectedByIndirectAdjacentRules() { setRestyleFlag(ChildrenAffectedByIndirectAdjacentRules); }
170
171     bool childrenAffectedByForwardPositionalRules() const { return hasRestyleFlag(ChildrenAffectedByForwardPositionalRules); }
172     void setChildrenAffectedByForwardPositionalRules() { setRestyleFlag(ChildrenAffectedByForwardPositionalRules); }
173
174     bool childrenAffectedByBackwardPositionalRules() const { return hasRestyleFlag(ChildrenAffectedByBackwardPositionalRules); }
175     void setChildrenAffectedByBackwardPositionalRules() { setRestyleFlag(ChildrenAffectedByBackwardPositionalRules); }
176
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);
181
182     bool childrenSupportStyleSharing() const { return !hasRestyleFlags(); }
183
184     // -----------------------------------------------------------------------------
185     // Notification of document structure changes (see core/dom/Node.h for more notification methods)
186
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);
190
191     void disconnectDescendantFrames();
192
193     virtual void trace(Visitor*) OVERRIDE;
194
195 protected:
196     ContainerNode(TreeScope*, ConstructionType = CreateContainer);
197
198     template<class GenericNode, class GenericNodeContainer>
199     friend void appendChildToContainer(GenericNode& child, GenericNodeContainer&);
200
201     template<class GenericNode, class GenericNodeContainer>
202     friend void Private::addChildNodesToDeletionQueue(GenericNode*& head, GenericNode*& tail, GenericNodeContainer&);
203
204 #if !ENABLE(OILPAN)
205     void removeDetachedChildren();
206 #endif
207
208     void setFirstChild(Node* child) { m_firstChild = child; }
209     void setLastChild(Node* child) { m_lastChild = child; }
210
211 private:
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);
217
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;
223
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;
228
229     void attachChildren(const AttachContext& = AttachContext());
230     void detachChildren(const AttachContext& = AttachContext());
231
232     bool getUpperLeftCorner(FloatPoint&) const;
233     bool getLowerRightCorner(FloatPoint&) const;
234
235     RawPtrWillBeMember<Node> m_firstChild;
236     RawPtrWillBeMember<Node> m_lastChild;
237 };
238
239 #ifndef NDEBUG
240 bool childAttachedAllowedWhenAttachingChildren(ContainerNode*);
241 #endif
242
243 DEFINE_NODE_TYPE_CASTS(ContainerNode, isContainerNode());
244
245 inline bool ContainerNode::hasChildCount(unsigned count) const
246 {
247     Node* child = m_firstChild;
248     while (count && child) {
249         child = child->nextSibling();
250         --count;
251     }
252     return !count && !child;
253 }
254
255 inline ContainerNode::ContainerNode(TreeScope* treeScope, ConstructionType type)
256     : Node(treeScope, type)
257     , m_firstChild(nullptr)
258     , m_lastChild(nullptr)
259 {
260 }
261
262 inline void ContainerNode::attachChildren(const AttachContext& context)
263 {
264     AttachContext childrenContext(context);
265     childrenContext.resolvedStyle = 0;
266
267     for (Node* child = firstChild(); child; child = child->nextSibling()) {
268         ASSERT(child->needsAttach() || childAttachedAllowedWhenAttachingChildren(this));
269         if (child->needsAttach())
270             child->attach(childrenContext);
271     }
272 }
273
274 inline void ContainerNode::detachChildren(const AttachContext& context)
275 {
276     AttachContext childrenContext(context);
277     childrenContext.resolvedStyle = 0;
278
279     for (Node* child = firstChild(); child; child = child->nextSibling())
280         child->detach(childrenContext);
281 }
282
283 inline unsigned Node::countChildren() const
284 {
285     if (!isContainerNode())
286         return 0;
287     return toContainerNode(this)->countChildren();
288 }
289
290 inline Node* Node::traverseToChildAt(unsigned index) const
291 {
292     if (!isContainerNode())
293         return 0;
294     return toContainerNode(this)->traverseToChildAt(index);
295 }
296
297 inline Node* Node::firstChild() const
298 {
299     if (!isContainerNode())
300         return 0;
301     return toContainerNode(this)->firstChild();
302 }
303
304 inline Node* Node::lastChild() const
305 {
306     if (!isContainerNode())
307         return 0;
308     return toContainerNode(this)->lastChild();
309 }
310
311 inline Node& Node::highestAncestorOrSelf() const
312 {
313     Node* node = const_cast<Node*>(this);
314     Node* highest = node;
315     for (; node; node = node->parentNode())
316         highest = node;
317     return *highest;
318 }
319
320 inline ContainerNode* Node::parentElementOrShadowRoot() const
321 {
322     ContainerNode* parent = parentNode();
323     return parent && (parent->isElementNode() || parent->isShadowRoot()) ? parent : 0;
324 }
325
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;
331
332 inline void getChildNodes(Node& node, NodeVector& nodes)
333 {
334     ASSERT(!nodes.size());
335     for (Node* child = node.firstChild(); child; child = child->nextSibling())
336         nodes.append(child);
337 }
338
339 class ChildNodesLazySnapshot {
340     WTF_MAKE_NONCOPYABLE(ChildNodesLazySnapshot);
341     WTF_MAKE_FAST_ALLOCATED;
342 public:
343     explicit ChildNodesLazySnapshot(Node& parentNode)
344         : m_currentNode(parentNode.firstChild())
345         , m_currentIndex(0)
346     {
347         m_nextSnapshot = latestSnapshot;
348         latestSnapshot = this;
349     }
350
351     ~ChildNodesLazySnapshot()
352     {
353         latestSnapshot = m_nextSnapshot;
354     }
355
356     // Returns 0 if there is no next Node.
357     PassRefPtr<Node> nextNode()
358     {
359         if (LIKELY(!hasSnapshot())) {
360             RefPtr<Node> node = m_currentNode;
361             if (node)
362                 m_currentNode = node->nextSibling();
363             return node.release();
364         }
365         Vector<RefPtr<Node> >& nodeVector = *m_childNodes;
366         if (m_currentIndex >= nodeVector.size())
367             return nullptr;
368         return nodeVector[m_currentIndex++];
369     }
370
371     void takeSnapshot()
372     {
373         if (hasSnapshot())
374             return;
375         m_childNodes = adoptPtr(new Vector<RefPtr<Node> >());
376         Node* node = m_currentNode.get();
377         while (node) {
378             m_childNodes->append(node);
379             node = node->nextSibling();
380         }
381     }
382
383     ChildNodesLazySnapshot* nextSnapshot() { return m_nextSnapshot; }
384     bool hasSnapshot() { return !!m_childNodes.get(); }
385
386     static void takeChildNodesLazySnapshot()
387     {
388         ChildNodesLazySnapshot* snapshot = latestSnapshot;
389         while (snapshot && !snapshot->hasSnapshot()) {
390             snapshot->takeSnapshot();
391             snapshot = snapshot->nextSnapshot();
392         }
393     }
394
395 private:
396     static ChildNodesLazySnapshot* latestSnapshot;
397
398     RefPtr<Node> m_currentNode;
399     unsigned m_currentIndex;
400     OwnPtr<Vector<RefPtr<Node> > > m_childNodes; // Lazily instantiated.
401     ChildNodesLazySnapshot* m_nextSnapshot;
402 };
403
404 } // namespace WebCore
405
406 #endif // ContainerNode_h