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