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 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 
     71     Node* firstChild() const { return m_firstChild; }
     72     Node* lastChild() const { return m_lastChild; }
     73     bool hasChildren() const { return m_firstChild; }
     74 
     75     bool hasOneChild() const { return m_firstChild && !m_firstChild->nextSibling(); }
     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 
    118     bool childrenOrSiblingsAffectedByFocus() const { return hasRestyleFlag(ChildrenOrSiblingsAffectedByFocus); }
    119     void setChildrenOrSiblingsAffectedByFocus() { setRestyleFlag(ChildrenOrSiblingsAffectedByFocus); }
    120 
    121     bool childrenOrSiblingsAffectedByHover() const { return hasRestyleFlag(ChildrenOrSiblingsAffectedByHover); }
    122     void setChildrenOrSiblingsAffectedByHover() { setRestyleFlag(ChildrenOrSiblingsAffectedByHover); }
    123 
    124     bool childrenOrSiblingsAffectedByActive() const { return hasRestyleFlag(ChildrenOrSiblingsAffectedByActive); }
    125     void setChildrenOrSiblingsAffectedByActive() { setRestyleFlag(ChildrenOrSiblingsAffectedByActive); }
    126 
    127     bool childrenOrSiblingsAffectedByDrag() const { return hasRestyleFlag(ChildrenOrSiblingsAffectedByDrag); }
    128     void setChildrenOrSiblingsAffectedByDrag() { setRestyleFlag(ChildrenOrSiblingsAffectedByDrag); }
    129 
    130     bool childrenAffectedByPositionalRules() const { return hasRestyleFlag(ChildrenAffectedByForwardPositionalRules) || hasRestyleFlag(ChildrenAffectedByBackwardPositionalRules); }
    131 
    132     bool childrenAffectedByFirstChildRules() const { return hasRestyleFlag(ChildrenAffectedByFirstChildRules); }
    133     void setChildrenAffectedByFirstChildRules() { setRestyleFlag(ChildrenAffectedByFirstChildRules); }
    134 
    135     bool childrenAffectedByLastChildRules() const { return hasRestyleFlag(ChildrenAffectedByLastChildRules); }
    136     void setChildrenAffectedByLastChildRules() { setRestyleFlag(ChildrenAffectedByLastChildRules); }
    137 
    138     bool childrenAffectedByDirectAdjacentRules() const { return hasRestyleFlag(ChildrenAffectedByDirectAdjacentRules); }
    139     void setChildrenAffectedByDirectAdjacentRules() { setRestyleFlag(ChildrenAffectedByDirectAdjacentRules); }
    140 
    141     bool childrenAffectedByIndirectAdjacentRules() const { return hasRestyleFlag(ChildrenAffectedByIndirectAdjacentRules); }
    142     void setChildrenAffectedByIndirectAdjacentRules() { setRestyleFlag(ChildrenAffectedByIndirectAdjacentRules); }
    143 
    144     bool childrenAffectedByForwardPositionalRules() const { return hasRestyleFlag(ChildrenAffectedByForwardPositionalRules); }
    145     void setChildrenAffectedByForwardPositionalRules() { setRestyleFlag(ChildrenAffectedByForwardPositionalRules); }
    146 
    147     bool childrenAffectedByBackwardPositionalRules() const { return hasRestyleFlag(ChildrenAffectedByBackwardPositionalRules); }
    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 
    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 
    182     void setFirstChild(Node* child) { m_firstChild = 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 
    195     bool hasRestyleFlag(DynamicRestyleFlags mask) const { return hasRareData() && hasRestyleFlagInternal(mask); }
    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 
    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 
    232 inline ContainerNode::ContainerNode(TreeScope* treeScope, ConstructionType type)
    233     : Node(treeScope, type)
    234     , m_firstChild(nullptr)
    235     , m_lastChild(nullptr)
    236 {
    237 }
    238 
    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 
    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 
    260 inline unsigned Node::countChildren() const
    261 {
    262     if (!isContainerNode())
    263         return 0;
    264     return toContainerNode(this)->countChildren();
    265 }
    266 
    267 inline Node* Node::traverseToChildAt(unsigned index) const
    268 {
    269     if (!isContainerNode())
    270         return 0;
    271     return toContainerNode(this)->traverseToChildAt(index);
    272 }
    273 
    274 inline Node* Node::firstChild() const
    275 {
    276     if (!isContainerNode())
    277         return 0;
    278     return toContainerNode(this)->firstChild();
    279 }
    280 
    281 inline Node* Node::lastChild() const
    282 {
    283     if (!isContainerNode())
    284         return 0;
    285     return toContainerNode(this)->lastChild();
    286 }
    287 
    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 
    297 inline ContainerNode* Node::parentElementOrShadowRoot() const
    298 {
    299     ContainerNode* parent = parentNode();
    300     return parent && (parent->isElementNode() || parent->isShadowRoot()) ? parent : 0;
    301 }
    302 
    303 inline ContainerNode* Node::parentElementOrDocumentFragment() const
    304 {
    305     ContainerNode* parent = parentNode();
    306     return parent && (parent->isElementNode() || parent->isDocumentFragment()) ? parent : 0;
    307 }
    308 
    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