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