diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-07-23 09:28:44 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-07-23 09:28:44 +0200 |
commit | 815f1ed417bd26fbe2abbdf20ac5d3423b30796c (patch) | |
tree | 923c9a9e2834ccab60f5caecfb8f0ac410c1dd9e /Source/WebCore/html/HTMLCollection.cpp | |
parent | b4ad5d9d2b96baacd0180ead50de5195ca78af2d (diff) | |
download | qtwebkit-815f1ed417bd26fbe2abbdf20ac5d3423b30796c.tar.gz |
Imported WebKit commit e65cbc5b6ac32627c797e7fc7f46eb7794410c92 (http://svn.webkit.org/repository/webkit/trunk@123308)
New snapshot with better configure tests
Diffstat (limited to 'Source/WebCore/html/HTMLCollection.cpp')
-rw-r--r-- | Source/WebCore/html/HTMLCollection.cpp | 171 |
1 files changed, 100 insertions, 71 deletions
diff --git a/Source/WebCore/html/HTMLCollection.cpp b/Source/WebCore/html/HTMLCollection.cpp index 2b53edd98..57953ac98 100644 --- a/Source/WebCore/html/HTMLCollection.cpp +++ b/Source/WebCore/html/HTMLCollection.cpp @@ -69,7 +69,7 @@ static bool shouldOnlyIncludeDirectChildren(CollectionType type) case TSectionRows: case TableTBodies: return true; - case InvalidCollectionType: + case NodeListCollectionType: break; } ASSERT_NOT_REACHED(); @@ -104,7 +104,7 @@ static NodeListRootType rootTypeFromCollectionType(CollectionType type) case SelectedOptions: case DataListOptions: case MapAreas: - case InvalidCollectionType: + case NodeListCollectionType: return NodeListIsRootedAtNode; } ASSERT_NOT_REACHED(); @@ -144,7 +144,7 @@ static NodeListInvalidationType invalidationTypeExcludingIdAndNameAttributes(Col #endif case FormControls: return InvalidateForFormControls; - case InvalidCollectionType: + case NodeListCollectionType: break; } ASSERT_NOT_REACHED(); @@ -152,17 +152,16 @@ static NodeListInvalidationType invalidationTypeExcludingIdAndNameAttributes(Col } -HTMLCollection::HTMLCollection(Node* base, CollectionType type, ItemBeforeSupportType itemBeforeSupportType) - : HTMLCollectionCacheBase(rootTypeFromCollectionType(type), invalidationTypeExcludingIdAndNameAttributes(type), type, itemBeforeSupportType) - , m_base(base) +HTMLCollection::HTMLCollection(Node* ownerNode, CollectionType type, ItemAfterOverrideType itemAfterOverrideType) + : HTMLCollectionCacheBase(ownerNode, rootTypeFromCollectionType(type), invalidationTypeExcludingIdAndNameAttributes(type), + WebCore::shouldOnlyIncludeDirectChildren(type), type, itemAfterOverrideType) { - ASSERT(m_base); - m_base->document()->registerNodeListCache(this); + document()->registerNodeListCache(this); } PassRefPtr<HTMLCollection> HTMLCollection::create(Node* base, CollectionType type) { - return adoptRef(new HTMLCollection(base, type, SupportItemBefore)); + return adoptRef(new HTMLCollection(base, type, DoesNotOverrideItemAfter)); } HTMLCollection::~HTMLCollection() @@ -176,7 +175,7 @@ HTMLCollection::~HTMLCollection() } else // HTMLNameCollection removes cache by itself. ASSERT(type() == WindowNamedItems || type() == DocumentNamedItems); - m_base->document()->unregisterNodeListCache(this); + document()->unregisterNodeListCache(this); } static inline bool isAcceptableElement(CollectionType type, Element* element) @@ -231,7 +230,7 @@ static inline bool isAcceptableElement(CollectionType type, Element* element) case DocumentNamedItems: case TableRows: case WindowNamedItems: - case InvalidCollectionType: + case NodeListCollectionType: ASSERT_NOT_REACHED(); } return false; @@ -254,41 +253,65 @@ static inline Node* lastDescendent(Node* node) return node; } -template<bool forward> -static Element* itemBeforeOrAfter(CollectionType type, Node* base, unsigned& offsetInArray, Node* previous) +static Node* firstNode(bool forward, Node* rootNode, bool onlyIncludeDirectChildren) { - ASSERT_UNUSED(offsetInArray, !offsetInArray); - bool onlyIncludeDirectChildren = shouldOnlyIncludeDirectChildren(type); - Node* rootNode = base; - Node* current; - if (previous) - current = nextNode<forward>(rootNode, previous, onlyIncludeDirectChildren); - else { - if (forward) - current = rootNode->firstChild(); - else - current = onlyIncludeDirectChildren ? rootNode->lastChild() : lastDescendent(rootNode); - } + if (forward) + return rootNode->firstChild(); + else + return onlyIncludeDirectChildren ? rootNode->lastChild() : lastDescendent(rootNode); +} +template <bool forward> +Node* DynamicNodeListCacheBase::iterateForNextNode(Node* current) const +{ + bool onlyIncludeDirectChildren = shouldOnlyIncludeDirectChildren(); + CollectionType collectionType = type(); + Node* rootNode = this->rootNode(); for (; current; current = nextNode<forward>(rootNode, current, onlyIncludeDirectChildren)) { - if (current->isElementNode() && isAcceptableElement(type, toElement(current))) - return toElement(current); + if (collectionType == NodeListCollectionType) { + if (current->isElementNode() && static_cast<const DynamicNodeList*>(this)->nodeMatches(toElement(current))) + return toElement(current); + } else { + if (current->isElementNode() && isAcceptableElement(collectionType, toElement(current))) + return toElement(current); + } } return 0; } -Element* HTMLCollection::itemBefore(unsigned& offsetInArray, Element* previous) const +// Without this ALWAYS_INLINE, length() and item() can be 100% slower. +template<bool forward> ALWAYS_INLINE +Node* DynamicNodeListCacheBase::itemBeforeOrAfter(Node* previous) const +{ + Node* current; + if (LIKELY(!!previous)) // Without this LIKELY, length() and item() can be 10% slower. + current = nextNode<forward>(rootNode(), previous, shouldOnlyIncludeDirectChildren()); + else + current = firstNode(forward, rootNode(), previous); + + if (type() == NodeListCollectionType && shouldOnlyIncludeDirectChildren()) // ChildNodeList + return current; + + return iterateForNextNode<forward>(current); +} + +// Without this ALWAYS_INLINE, length() and item() can be 100% slower. +ALWAYS_INLINE Node* DynamicNodeListCacheBase::itemBefore(Node* previous) const { - return itemBeforeOrAfter<false>(type(), base(), offsetInArray, previous); + return itemBeforeOrAfter<false>(previous); } -Element* HTMLCollection::itemAfter(unsigned& offsetInArray, Element* previous) const +// Without this ALWAYS_INLINE, length() and item() can be 100% slower. +ALWAYS_INLINE Node* DynamicNodeListCacheBase::itemAfter(unsigned& offsetInArray, Node* previous) const { - return itemBeforeOrAfter<true>(type(), base(), offsetInArray, previous); + if (UNLIKELY(overridesItemAfter())) // Without this UNLIKELY, length() can be 100% slower. + return static_cast<const HTMLCollection*>(this)->virtualItemAfter(offsetInArray, toElement(previous)); + ASSERT(!offsetInArray); + return itemBeforeOrAfter<true>(previous); } -bool ALWAYS_INLINE HTMLCollection::isLastItemCloserThanLastOrCachedItem(unsigned offset) const +bool ALWAYS_INLINE DynamicNodeListCacheBase::isLastItemCloserThanLastOrCachedItem(unsigned offset) const { ASSERT(isLengthCacheValid()); unsigned distanceFromLastItem = cachedLength() - offset; @@ -298,7 +321,7 @@ bool ALWAYS_INLINE HTMLCollection::isLastItemCloserThanLastOrCachedItem(unsigned return cachedItemOffset() < offset && distanceFromLastItem < offset - cachedItemOffset(); } -bool ALWAYS_INLINE HTMLCollection::isFirstItemCloserThanCachedItem(unsigned offset) const +bool ALWAYS_INLINE DynamicNodeListCacheBase::isFirstItemCloserThanCachedItem(unsigned offset) const { ASSERT(isItemCacheValid()); if (cachedItemOffset() < offset) @@ -308,28 +331,33 @@ bool ALWAYS_INLINE HTMLCollection::isFirstItemCloserThanCachedItem(unsigned offs return offset < distanceFromCachedItem; } -unsigned HTMLCollection::length() const +ALWAYS_INLINE void DynamicNodeListCacheBase::setItemCache(Node* item, unsigned offset, unsigned elementsArrayOffset) const +{ + setItemCache(item, offset); + if (overridesItemAfter()) { + ASSERT(item->isElementNode()); + static_cast<const HTMLCollectionCacheBase*>(this)->m_cachedElementsArrayOffset = elementsArrayOffset; + } else + ASSERT(!elementsArrayOffset); +} + +ALWAYS_INLINE unsigned DynamicNodeListCacheBase::cachedElementsArrayOffset() const +{ + return overridesItemAfter() ? static_cast<const HTMLCollectionCacheBase*>(this)->m_cachedElementsArrayOffset : 0; +} + +unsigned DynamicNodeListCacheBase::lengthCommon() const { if (isLengthCacheValid()) return cachedLength(); - if (!isItemCacheValid() && !item(0)) { - ASSERT(isLengthCacheValid()); - return 0; - } - - ASSERT(isItemCacheValid()); - ASSERT(cachedItem()); - unsigned offset = cachedItemOffset(); - do { - offset++; - } while (itemBeforeOrAfterCachedItem(offset)); + itemCommon(UINT_MAX); ASSERT(isLengthCacheValid()); - - return offset; + + return cachedLength(); } -Node* HTMLCollection::item(unsigned offset) const +Node* DynamicNodeListCacheBase::itemCommon(unsigned offset) const { if (isItemCacheValid() && cachedItemOffset() == offset) return cachedItem(); @@ -342,14 +370,11 @@ Node* HTMLCollection::item(unsigned offset) const static_cast<const HTMLPropertiesCollection*>(this)->updateRefElements(); #endif - if (isLengthCacheValid() && supportsItemBefore() && isLastItemCloserThanLastOrCachedItem(offset)) { - // FIXME: Need to figure out the last offset in array for HTMLFormCollection and HTMLPropertiesCollection - unsigned unusedOffsetInArray = 0; - Node* lastItem = itemBefore(unusedOffsetInArray, 0); - ASSERT(!unusedOffsetInArray); + if (isLengthCacheValid() && !overridesItemAfter() && isLastItemCloserThanLastOrCachedItem(offset)) { + Node* lastItem = itemBefore(0); ASSERT(lastItem); setItemCache(lastItem, cachedLength() - 1, 0); - } else if (!isItemCacheValid() || isFirstItemCloserThanCachedItem(offset) || (!supportsItemBefore() && offset < cachedItemOffset())) { + } else if (!isItemCacheValid() || isFirstItemCloserThanCachedItem(offset) || (overridesItemAfter() && offset < cachedItemOffset())) { unsigned offsetInArray = 0; Node* firstItem = itemAfter(offsetInArray, 0); if (!firstItem) { @@ -366,22 +391,19 @@ Node* HTMLCollection::item(unsigned offset) const return itemBeforeOrAfterCachedItem(offset); } -Element* HTMLCollection::itemBeforeOrAfterCachedItem(unsigned offset) const +Node* DynamicNodeListCacheBase::itemBeforeOrAfterCachedItem(unsigned offset) const { unsigned currentOffset = cachedItemOffset(); - ASSERT(cachedItem()->isElementNode()); - Element* currentItem = toElement(cachedItem()); + Node* currentItem = cachedItem(); ASSERT(currentOffset != offset); - unsigned offsetInArray = cachedElementsArrayOffset(); - if (offset < cachedItemOffset()) { - ASSERT(supportsItemBefore()); - while ((currentItem = itemBefore(offsetInArray, currentItem))) { + ASSERT(!overridesItemAfter()); + while ((currentItem = itemBefore(currentItem))) { ASSERT(currentOffset); currentOffset--; if (currentOffset == offset) { - setItemCache(currentItem, currentOffset, offsetInArray); + setItemCache(currentItem, currentOffset, 0); return currentItem; } } @@ -389,6 +411,7 @@ Element* HTMLCollection::itemBeforeOrAfterCachedItem(unsigned offset) const return 0; } + unsigned offsetInArray = cachedElementsArrayOffset(); while ((currentItem = itemAfter(offsetInArray, currentItem))) { currentOffset++; if (currentOffset == offset) { @@ -403,6 +426,12 @@ Element* HTMLCollection::itemBeforeOrAfterCachedItem(unsigned offset) const return 0; } +Element* HTMLCollection::virtualItemAfter(unsigned&, Element*) const +{ + ASSERT_NOT_REACHED(); + return 0; +} + static inline bool nameShouldBeVisibleInDocumentAll(HTMLElement* element) { // The document.all collection returns only certain types of elements by name, @@ -441,8 +470,8 @@ Node* HTMLCollection::namedItem(const AtomicString& name) const unsigned arrayOffset = 0; unsigned i = 0; - for (Element* e = itemAfter(arrayOffset, 0); e; e = itemAfter(arrayOffset, e)) { - if (checkForNameMatch(e, /* checkName */ false, name)) { + for (Node* e = itemAfter(arrayOffset, 0); e; e = itemAfter(arrayOffset, e)) { + if (checkForNameMatch(toElement(e), /* checkName */ false, name)) { setItemCache(e, i, arrayOffset); return e; } @@ -450,10 +479,10 @@ Node* HTMLCollection::namedItem(const AtomicString& name) const } i = 0; - for (Element* e = itemAfter(arrayOffset, 0); e; e = itemAfter(arrayOffset, e)) { - if (checkForNameMatch(e, /* checkName */ true, name)) { + for (Node* e = itemAfter(arrayOffset, 0); e; e = itemAfter(arrayOffset, e)) { + if (checkForNameMatch(toElement(e), /* checkName */ true, name)) { setItemCache(e, i, arrayOffset); - return e; + return toElement(e); } i++; } @@ -467,10 +496,10 @@ void HTMLCollection::updateNameCache() const return; unsigned arrayOffset = 0; - for (Element* element = itemAfter(arrayOffset, 0); element; element = itemAfter(arrayOffset, element)) { - if (!element->isHTMLElement()) + for (Node* node = itemAfter(arrayOffset, 0); node; node = itemAfter(arrayOffset, node)) { + if (!node->isHTMLElement()) continue; - HTMLElement* e = toHTMLElement(element); + HTMLElement* e = toHTMLElement(node); const AtomicString& idAttrVal = e->getIdAttribute(); const AtomicString& nameAttrVal = e->getNameAttribute(); if (!idAttrVal.isEmpty()) @@ -522,7 +551,7 @@ void HTMLCollection::namedItems(const AtomicString& name, Vector<RefPtr<Node> >& PassRefPtr<NodeList> HTMLCollection::tags(const String& name) { - return m_base->getElementsByTagName(name); + return ownerNode()->getElementsByTagName(name); } void HTMLCollectionCacheBase::append(NodeCacheMap& map, const AtomicString& key, Element* element) |