Changeset 158587 in webkit
- Timestamp:
- Nov 4, 2013, 1:31:27 PM (11 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 11 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r158586 r158587 1 2013-11-04 Antti Koivisto <antti@apple.com> 2 3 Make LiveNodeListBase use Elements instead of Nodes 4 https://bugs.webkit.org/show_bug.cgi?id=123745 5 6 Reviewed by Anders Carlsson. 7 8 * WebCore.exp.in: 9 * dom/Element.cpp: 10 (WebCore::Element::firstElementChild): 11 (WebCore::Element::lastElementChild): 12 13 Switch to correct calls. ElementTraversal::previous and previousChild are no longer equivalent. 14 15 * dom/ElementTraversal.h: 16 (WebCore::::lastWithinTemplate): 17 (WebCore::::previousTemplate): 18 19 Fix ElementTraversal::lastWithin and previous. They had no real clients and didn't work correctly. 20 With LiveNodeListBase starting to use these they get excellent test coverage. 21 22 * dom/LiveNodeList.cpp: 23 (WebCore::LiveNodeListBase::invalidateCache): 24 * dom/LiveNodeList.h: 25 (WebCore::LiveNodeListBase::LiveNodeListBase): 26 (WebCore::LiveNodeListBase::isElementCacheValid): 27 (WebCore::LiveNodeListBase::cachedElement): 28 (WebCore::LiveNodeListBase::cachedElementOffset): 29 (WebCore::LiveNodeListBase::setCachedElement): 30 31 Make the cache Element based. 32 Switch to Elements in all helpers. 33 Rename item -> element for clarity. 34 35 * dom/NodeIterator.cpp: 36 (WebCore::NodeIterator::NodePointer::moveToPrevious): 37 (WebCore::NodeIterator::updateForNodeRemoval): 38 39 This code expected the old inconsistent NodeTraversal::previous behavior where the traversal includes 40 the root as the last item. Drop the stayWithin parameter and handle the one case where it is needed here. 41 42 * dom/NodeTraversal.cpp: 43 (WebCore::NodeTraversal::last): 44 (WebCore::NodeTraversal::deepLastChild): 45 * dom/NodeTraversal.h: 46 47 Support ElementTraversal::previous/lastWithin. 48 49 (WebCore::NodeTraversal::previous): 50 51 This was slightly wrong too. 52 53 * html/HTMLCollection.cpp: 54 (WebCore::previousElement): 55 (WebCore::lastElement): 56 (WebCore::LiveNodeListBase::iterateForPreviousElement): 57 (WebCore::LiveNodeListBase::itemBefore): 58 (WebCore::LiveNodeListBase::isLastItemCloserThanLastOrCachedItem): 59 (WebCore::LiveNodeListBase::isFirstItemCloserThanCachedItem): 60 (WebCore::LiveNodeListBase::setCachedElement): 61 (WebCore::LiveNodeListBase::item): 62 (WebCore::LiveNodeListBase::elementBeforeOrAfterCachedElement): 63 * html/HTMLCollection.h: 64 (WebCore::HTMLCollection::isEmpty): 65 (WebCore::HTMLCollection::hasExactlyOneItem): 66 1 67 2013-11-04 Michael Saboff <msaboff@apple.com> 2 68 -
trunk/Source/WebCore/WebCore.exp.in
r158521 r158587 285 285 __ZN7WebCore13JSHTMLElement6s_infoE 286 286 __ZN7WebCore13KeyboardEventC1ERKNS_21PlatformKeyboardEventEPNS_9DOMWindowE 287 __ZN7WebCore13NodeTraversal13deepLastChildEPNS_4NodeE 287 288 __ZN7WebCore13NodeTraversal19nextAncestorSiblingEPKNS_4NodeE 288 __ZN7WebCore13NodeTraversal8previousEPKNS_4NodeES3_289 289 __ZN7WebCore13PageThrottler22reportInterestingEventEv 290 290 __ZN7WebCore13PageThrottlerD1Ev -
trunk/Source/WebCore/dom/Element.cpp
r158569 r158587 2476 2476 Element* Element::firstElementChild() const 2477 2477 { 2478 return ElementTraversal::first Within(this);2478 return ElementTraversal::firstChild(this); 2479 2479 } 2480 2480 2481 2481 Element* Element::lastElementChild() const 2482 2482 { 2483 return ElementTraversal::last Within(this);2483 return ElementTraversal::lastChild(this); 2484 2484 } 2485 2485 -
trunk/Source/WebCore/dom/ElementTraversal.h
r157375 r158587 40 40 static ElementType* lastChild(const ContainerNode*); 41 41 42 // First or last ElementType descendant of the node. For Elements this is always the same as first/last child.42 // First or last ElementType descendant of the node. For Elements firstWithin is always the same as first child. 43 43 static ElementType* firstWithin(const Node*); 44 44 static ElementType* firstWithin(const ContainerNode*); … … 107 107 inline Element* Traversal<Element>::lastWithinTemplate(CurrentType* current) 108 108 { 109 return lastChildTemplate(current); 109 Node* node = NodeTraversal::last(current); 110 while (node && !node->isElementNode()) 111 node = NodeTraversal::previous(node, current); 112 return static_cast<Element*>(node); 110 113 } 111 114 … … 136 139 Node* node = NodeTraversal::previous(current); 137 140 while (node && !node->isElementNode()) 138 node = NodeTraversal::previous SkippingChildren(node);141 node = NodeTraversal::previous(node); 139 142 return static_cast<Element*>(node); 140 143 } … … 146 149 Node* node = NodeTraversal::previous(current, stayWithin); 147 150 while (node && !node->isElementNode()) 148 node = NodeTraversal::previous SkippingChildren(node, stayWithin);151 node = NodeTraversal::previous(node, stayWithin); 149 152 return static_cast<Element*>(node); 150 153 } -
trunk/Source/WebCore/dom/LiveNodeList.cpp
r158569 r158587 39 39 void LiveNodeListBase::invalidateCache() const 40 40 { 41 m_cached Item = 0;41 m_cachedElement = nullptr; 42 42 m_isLengthCacheValid = false; 43 m_is ItemCacheValid = false;43 m_isElementCacheValid = false; 44 44 m_isNameCacheValid = false; 45 45 m_isItemRefElementsCacheValid = false; -
trunk/Source/WebCore/dom/LiveNodeList.h
r158540 r158587 52 52 bool shouldOnlyIncludeDirectChildren, CollectionType collectionType, ItemAfterOverrideType itemAfterOverrideType) 53 53 : m_ownerNode(ownerNode) 54 , m_cached Item(0)54 , m_cachedElement(nullptr) 55 55 , m_isLengthCacheValid(false) 56 , m_is ItemCacheValid(false)56 , m_isElementCacheValid(false) 57 57 , m_rootType(rootType) 58 58 , m_invalidationType(invalidationType) … … 102 102 bool overridesItemAfter() const { return m_overridesItemAfter; } 103 103 104 ALWAYS_INLINE bool is ItemCacheValid() const { return m_isItemCacheValid; }105 ALWAYS_INLINE Node* cachedItem() const { return m_cachedItem; }106 ALWAYS_INLINE unsigned cached ItemOffset() const { return m_cachedItemOffset; }104 ALWAYS_INLINE bool isElementCacheValid() const { return m_isElementCacheValid; } 105 ALWAYS_INLINE Element* cachedElement() const { return m_cachedElement; } 106 ALWAYS_INLINE unsigned cachedElementOffset() const { return m_cachedElementOffset; } 107 107 108 108 ALWAYS_INLINE bool isLengthCacheValid() const { return m_isLengthCacheValid; } … … 113 113 m_isLengthCacheValid = true; 114 114 } 115 ALWAYS_INLINE void set ItemCache(Node* item, unsigned offset) const115 ALWAYS_INLINE void setCachedElement(Element& element, unsigned offset) const 116 116 { 117 ASSERT(item); 118 m_cachedItem = item; 119 m_cachedItemOffset = offset; 120 m_isItemCacheValid = true; 117 m_cachedElement = &element; 118 m_cachedElementOffset = offset; 119 m_isElementCacheValid = true; 121 120 } 122 void set ItemCache(Node* item, unsigned offset, unsigned elementsArrayOffset) const;121 void setCachedElement(Element&, unsigned offset, unsigned elementsArrayOffset) const; 123 122 124 123 ALWAYS_INLINE bool isItemRefElementsCacheValid() const { return m_isItemRefElementsCacheValid; } … … 133 132 134 133 private: 135 Node* itemBeforeOrAfterCachedItem(unsigned offset, ContainerNode* root) const;134 Element* elementBeforeOrAfterCachedElement(unsigned offset, ContainerNode* root) const; 136 135 Element* traverseLiveNodeListFirstElement(ContainerNode* root) const; 137 136 Element* traverseLiveNodeListForwardToOffset(unsigned offset, Element* currentElement, unsigned& currentOffset, ContainerNode* root) const; 138 137 bool isLastItemCloserThanLastOrCachedItem(unsigned offset) const; 139 138 bool isFirstItemCloserThanCachedItem(unsigned offset) const; 140 Node* iterateForPreviousNode(Node* current) const;141 Node* itemBefore(Node* previousItem) const;139 Element* iterateForPreviousElement(Element* current) const; 140 Element* itemBefore(Element* previousItem) const; 142 141 143 142 Ref<ContainerNode> m_ownerNode; 144 mutable Node* m_cachedItem;143 mutable Element* m_cachedElement; 145 144 mutable unsigned m_cachedLength; 146 mutable unsigned m_cached ItemOffset;145 mutable unsigned m_cachedElementOffset; 147 146 mutable unsigned m_isLengthCacheValid : 1; 148 mutable unsigned m_is ItemCacheValid : 1;147 mutable unsigned m_isElementCacheValid : 1; 149 148 const unsigned m_rootType : 2; 150 149 const unsigned m_invalidationType : 4; -
trunk/Source/WebCore/dom/NodeIterator.cpp
r158569 r158587 67 67 return true; 68 68 } 69 node = NodeTraversal::previous(node.get(), root); 69 if (node == root) { 70 node = nullptr; 71 return false; 72 } 73 node = NodeTraversal::previous(node.get()); 70 74 return node; 71 75 } … … 180 184 referenceNode.node = node; 181 185 } else { 182 node = NodeTraversal::previous(removedNode , root());186 node = NodeTraversal::previous(removedNode); 183 187 if (node) { 184 188 // Move out from under the node being removed if the reference node is … … 186 190 if (willRemoveReferenceNodeAncestor) { 187 191 while (node && node->isDescendantOf(removedNode)) 188 node = NodeTraversal::previous(node , root());192 node = NodeTraversal::previous(node); 189 193 } 190 194 if (node) { … … 198 202 } 199 203 } else { 200 Node* node = NodeTraversal::previous(removedNode , root());204 Node* node = NodeTraversal::previous(removedNode); 201 205 if (node) { 202 206 // Move out from under the node being removed if the reference node is … … 204 208 if (willRemoveReferenceNodeAncestor) { 205 209 while (node && node->isDescendantOf(removedNode)) 206 node = NodeTraversal::previous(node , root());210 node = NodeTraversal::previous(node); 207 211 } 208 212 if (node) … … 215 219 if (willRemoveReferenceNodeAncestor) { 216 220 while (node && node->isDescendantOf(removedNode)) 217 node = NodeTraversal::previous(node , root());221 node = NodeTraversal::previous(node); 218 222 } 219 223 if (node) -
trunk/Source/WebCore/dom/NodeTraversal.cpp
r158569 r158587 104 104 } 105 105 106 Node* previous(const Node* current, const Node* stayWithin)106 Node* last(const ContainerNode* current) 107 107 { 108 if (current == stayWithin) 109 return 0; 110 if (current->previousSibling()) { 111 Node* previous = current->previousSibling(); 112 while (previous->lastChild()) 113 previous = previous->lastChild(); 114 return previous; 115 } 116 return current->parentNode(); 108 Node* node = current->lastChild(); 109 if (!node) 110 return nullptr; 111 while (node->lastChild()) 112 node = node->lastChild(); 113 return node; 114 } 115 116 Node* deepLastChild(Node* node) 117 { 118 while (node->lastChild()) 119 node = node->lastChild(); 120 return node; 117 121 } 118 122 -
trunk/Source/WebCore/dom/NodeTraversal.h
r154240 r158587 26 26 #define NodeTraversal_h 27 27 28 #include " Node.h"28 #include "ContainerNode.h" 29 29 #include "Text.h" 30 30 … … 50 50 51 51 // Does a reverse pre-order traversal to find the node that comes before the current one in document order 52 Node* last(const ContainerNode*); 52 53 Node* previous(const Node*, const Node* stayWithin = 0); 53 54 … … 73 74 Node* nextAncestorSibling(const Node*); 74 75 Node* nextAncestorSibling(const Node*, const Node* stayWithin); 76 Node* deepLastChild(Node*); 75 77 76 78 template <class NodeType> … … 125 127 inline Node* next(const Text* current, const Node* stayWithin) { return traverseNextSkippingChildrenTemplate(current, stayWithin); } 126 128 129 inline Node* previous(const Node* current, const Node* stayWithin) 130 { 131 if (Node* previous = current->previousSibling()) 132 return deepLastChild(previous); 133 if (current->parentNode() == stayWithin) 134 return nullptr; 135 return current->parentNode(); 136 } 137 127 138 } 128 139 } -
trunk/Source/WebCore/html/HTMLCollection.cpp
r158540 r158587 252 252 } 253 253 254 static Node* previousNode(Node& base, Node* previous, bool onlyIncludeDirectChildren)255 { 256 return onlyIncludeDirectChildren ? previous->previousSibling() : NodeTraversal::previous(previous, &base);257 } 258 259 static Node* lastNode(Node& rootNode, bool onlyIncludeDirectChildren)260 { 261 return onlyIncludeDirectChildren ? rootNode.lastChild() : rootNode.lastDescendant();262 } 263 264 ALWAYS_INLINE Node* LiveNodeListBase::iterateForPreviousNode(Node* current) const254 static Element* previousElement(ContainerNode& base, Element* previous, bool onlyIncludeDirectChildren) 255 { 256 return onlyIncludeDirectChildren ? ElementTraversal::previousSibling(previous) : ElementTraversal::previous(previous, &base); 257 } 258 259 static Element* lastElement(ContainerNode& rootNode, bool onlyIncludeDirectChildren) 260 { 261 return onlyIncludeDirectChildren ? ElementTraversal::lastChild(&rootNode) : ElementTraversal::lastWithin(&rootNode); 262 } 263 264 ALWAYS_INLINE Element* LiveNodeListBase::iterateForPreviousElement(Element* current) const 265 265 { 266 266 bool onlyIncludeDirectChildren = shouldOnlyIncludeDirectChildren(); 267 267 CollectionType collectionType = type(); 268 Node& rootNode = this->rootNode();269 for (; current; current = previous Node(rootNode, current, onlyIncludeDirectChildren)) {268 ContainerNode& rootNode = this->rootNode(); 269 for (; current; current = previousElement(rootNode, current, onlyIncludeDirectChildren)) { 270 270 if (isNodeList(collectionType)) { 271 if ( current->isElementNode() && isMatchingElement(static_cast<const LiveNodeList*>(this), toElement(current)))272 return toElement(current);271 if (isMatchingElement(static_cast<const LiveNodeList*>(this), current)) 272 return current; 273 273 } else { 274 if ( current->isElementNode() && isMatchingElement(static_cast<const HTMLCollection*>(this), toElement(current)))275 return toElement(current);274 if (isMatchingElement(static_cast<const HTMLCollection*>(this), current)) 275 return current; 276 276 } 277 277 } … … 279 279 } 280 280 281 ALWAYS_INLINE Node* LiveNodeListBase::itemBefore(Node* previous) const282 { 283 Node* current;281 ALWAYS_INLINE Element* LiveNodeListBase::itemBefore(Element* previous) const 282 { 283 Element* current; 284 284 if (LIKELY(!!previous)) // Without this LIKELY, length() and item() can be 10% slower. 285 current = previous Node(rootNode(), previous, shouldOnlyIncludeDirectChildren());285 current = previousElement(rootNode(), previous, shouldOnlyIncludeDirectChildren()); 286 286 else 287 current = last Node(rootNode(), shouldOnlyIncludeDirectChildren());288 289 return iterateForPrevious Node(current);287 current = lastElement(rootNode(), shouldOnlyIncludeDirectChildren()); 288 289 return iterateForPreviousElement(current); 290 290 } 291 291 … … 345 345 ASSERT(isLengthCacheValid()); 346 346 unsigned distanceFromLastItem = cachedLength() - offset; 347 if (!is ItemCacheValid())347 if (!isElementCacheValid()) 348 348 return distanceFromLastItem < offset; 349 349 350 return cached ItemOffset() < offset && distanceFromLastItem < offset - cachedItemOffset();350 return cachedElementOffset() < offset && distanceFromLastItem < offset - cachedElementOffset(); 351 351 } 352 352 353 353 bool ALWAYS_INLINE LiveNodeListBase::isFirstItemCloserThanCachedItem(unsigned offset) const 354 354 { 355 ASSERT(is ItemCacheValid());356 if (cached ItemOffset() < offset)355 ASSERT(isElementCacheValid()); 356 if (cachedElementOffset() < offset) 357 357 return false; 358 358 359 unsigned distanceFromCachedItem = cached ItemOffset() - offset;359 unsigned distanceFromCachedItem = cachedElementOffset() - offset; 360 360 return offset < distanceFromCachedItem; 361 361 } 362 362 363 ALWAYS_INLINE void LiveNodeListBase::setItemCache(Node* item, unsigned offset, unsigned elementsArrayOffset) const 364 { 365 setItemCache(item, offset); 366 if (overridesItemAfter()) { 367 ASSERT_WITH_SECURITY_IMPLICATION(item->isElementNode()); 363 ALWAYS_INLINE void LiveNodeListBase::setCachedElement(Element& element, unsigned offset, unsigned elementsArrayOffset) const 364 { 365 setCachedElement(element, offset); 366 if (overridesItemAfter()) 368 367 static_cast<const HTMLCollection*>(this)->m_cachedElementsArrayOffset = elementsArrayOffset; 369 } else 370 ASSERT(!elementsArrayOffset);368 369 ASSERT(overridesItemAfter() || !elementsArrayOffset); 371 370 } 372 371 … … 385 384 Node* LiveNodeListBase::item(unsigned offset) const 386 385 { 387 if (is ItemCacheValid() && cachedItemOffset() == offset)388 return cached Item();386 if (isElementCacheValid() && cachedElementOffset() == offset) 387 return cachedElement(); 389 388 390 389 if (isLengthCacheValid() && cachedLength() <= offset) … … 394 393 395 394 if (isLengthCacheValid() && !overridesItemAfter() && isLastItemCloserThanLastOrCachedItem(offset)) { 396 Node* lastItem = itemBefore(0);395 Element* lastItem = itemBefore(0); 397 396 ASSERT(lastItem); 398 set ItemCache(lastItem, cachedLength() - 1, 0);399 } else if (!is ItemCacheValid() || isFirstItemCloserThanCachedItem(offset) || (overridesItemAfter() && offset < cachedItemOffset())) {397 setCachedElement(*lastItem, cachedLength() - 1, 0); 398 } else if (!isElementCacheValid() || isFirstItemCloserThanCachedItem(offset) || (overridesItemAfter() && offset < cachedElementOffset())) { 400 399 unsigned offsetInArray = 0; 401 Node* firstItem;400 Element* firstItem; 402 401 if (isNodeList(type())) 403 402 firstItem = traverseLiveNodeListFirstElement(&root); … … 409 408 return 0; 410 409 } 411 set ItemCache(firstItem, 0, offsetInArray);412 ASSERT(!cached ItemOffset());413 } 414 415 if (cached ItemOffset() == offset)416 return cached Item();417 418 return itemBeforeOrAfterCachedItem(offset, &root);419 } 420 421 inline Node* LiveNodeListBase::itemBeforeOrAfterCachedItem(unsigned offset, ContainerNode* root) const422 { 423 unsigned currentOffset = cached ItemOffset();424 Node* currentItem = cachedItem();410 setCachedElement(*firstItem, 0, offsetInArray); 411 ASSERT(!cachedElementOffset()); 412 } 413 414 if (cachedElementOffset() == offset) 415 return cachedElement(); 416 417 return elementBeforeOrAfterCachedElement(offset, &root); 418 } 419 420 inline Element* LiveNodeListBase::elementBeforeOrAfterCachedElement(unsigned offset, ContainerNode* root) const 421 { 422 unsigned currentOffset = cachedElementOffset(); 423 Element* currentItem = cachedElement(); 425 424 ASSERT(currentItem); 426 425 ASSERT(currentOffset != offset); 427 426 428 if (offset < cached ItemOffset()) {427 if (offset < cachedElementOffset()) { 429 428 ASSERT(!overridesItemAfter()); 430 429 while ((currentItem = itemBefore(currentItem))) { … … 432 431 currentOffset--; 433 432 if (currentOffset == offset) { 434 set ItemCache(currentItem, currentOffset, 0);433 setCachedElement(*currentItem, currentOffset, 0); 435 434 return currentItem; 436 435 } … … 442 441 unsigned offsetInArray = 0; 443 442 if (isNodeList(type())) 444 currentItem = traverseLiveNodeListForwardToOffset(offset, toElement(currentItem), currentOffset, root);443 currentItem = traverseLiveNodeListForwardToOffset(offset, currentItem, currentOffset, root); 445 444 else 446 currentItem = static_cast<const HTMLCollection*>(this)->traverseForwardToOffset(offset, toElement(currentItem), currentOffset, offsetInArray, root);445 currentItem = static_cast<const HTMLCollection*>(this)->traverseForwardToOffset(offset, currentItem, currentOffset, offsetInArray, root); 447 446 448 447 if (!currentItem) { … … 451 450 return 0; 452 451 } 453 set ItemCache(currentItem, currentOffset, offsetInArray);452 setCachedElement(*currentItem, currentOffset, offsetInArray); 454 453 return currentItem; 455 454 } -
trunk/Source/WebCore/html/HTMLCollection.h
r158540 r158587 49 49 if (isLengthCacheValid()) 50 50 return !cachedLength(); 51 if (is ItemCacheValid())52 return !cached Item();51 if (isElementCacheValid()) 52 return !cachedElement(); 53 53 return !item(0); 54 54 } … … 57 57 if (isLengthCacheValid()) 58 58 return cachedLength() == 1; 59 if (is ItemCacheValid())60 return cached Item() && !cachedItemOffset() && !item(1);59 if (isElementCacheValid()) 60 return cachedElement() && !cachedElementOffset() && !item(1); 61 61 return item(0) && !item(1); 62 62 }
Note:
See TracChangeset
for help on using the changeset viewer.