| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All r
ights reserved. | 4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All r
ights reserved. |
| 5 * | 5 * |
| 6 * This library is free software; you can redistribute it and/or | 6 * This library is free software; you can redistribute it and/or |
| 7 * modify it under the terms of the GNU Library General Public | 7 * modify it under the terms of the GNU Library General Public |
| 8 * License as published by the Free Software Foundation; either | 8 * License as published by the Free Software Foundation; either |
| 9 * version 2 of the License, or (at your option) any later version. | 9 * version 2 of the License, or (at your option) any later version. |
| 10 * | 10 * |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 case HTMLTagNodeListType: | 153 case HTMLTagNodeListType: |
| 154 case RadioNodeListType: | 154 case RadioNodeListType: |
| 155 case RadioImgNodeListType: | 155 case RadioImgNodeListType: |
| 156 case LabelsNodeListType: | 156 case LabelsNodeListType: |
| 157 break; | 157 break; |
| 158 } | 158 } |
| 159 ASSERT_NOT_REACHED(); | 159 ASSERT_NOT_REACHED(); |
| 160 return DoNotInvalidateOnAttributeChanges; | 160 return DoNotInvalidateOnAttributeChanges; |
| 161 } | 161 } |
| 162 | 162 |
| 163 HTMLCollection::HTMLCollection(Node* ownerNode, CollectionType type, ItemAfterOv
errideType itemAfterOverrideType) | 163 HTMLCollection::HTMLCollection(ContainerNode* ownerNode, CollectionType type, It
emAfterOverrideType itemAfterOverrideType) |
| 164 : LiveNodeListBase(ownerNode, rootTypeFromCollectionType(type), invalidation
TypeExcludingIdAndNameAttributes(type), | 164 : LiveNodeListBase(ownerNode, rootTypeFromCollectionType(type), invalidation
TypeExcludingIdAndNameAttributes(type), |
| 165 WebCore::shouldOnlyIncludeDirectChildren(type), type, itemAfterOverrideT
ype) | 165 WebCore::shouldOnlyIncludeDirectChildren(type), type, itemAfterOverrideT
ype) |
| 166 , m_isNameCacheValid(false) | 166 , m_isNameCacheValid(false) |
| 167 { | 167 { |
| 168 ScriptWrappable::init(this); | 168 ScriptWrappable::init(this); |
| 169 } | 169 } |
| 170 | 170 |
| 171 PassRefPtr<HTMLCollection> HTMLCollection::create(Node* base, CollectionType typ
e) | 171 PassRefPtr<HTMLCollection> HTMLCollection::create(ContainerNode* base, Collectio
nType type) |
| 172 { | 172 { |
| 173 return adoptRef(new HTMLCollection(base, type, DoesNotOverrideItemAfter)); | 173 return adoptRef(new HTMLCollection(base, type, DoesNotOverrideItemAfter)); |
| 174 } | 174 } |
| 175 | 175 |
| 176 HTMLCollection::~HTMLCollection() | 176 HTMLCollection::~HTMLCollection() |
| 177 { | 177 { |
| 178 // HTMLNameCollection removes cache by itself. | 178 // HTMLNameCollection removes cache by itself. |
| 179 if (type() != WindowNamedItems && type() != DocumentNamedItems) | 179 if (type() != WindowNamedItems && type() != DocumentNamedItems) |
| 180 ownerNode()->nodeLists()->removeCacheWithAtomicName(this, type()); | 180 ownerNode()->nodeLists()->removeCacheWithAtomicName(this, type()); |
| 181 } | 181 } |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 template <class NodeListType> | 315 template <class NodeListType> |
| 316 inline Element* firstMatchingElement(const NodeListType* nodeList, ContainerNode
& root) | 316 inline Element* firstMatchingElement(const NodeListType* nodeList, ContainerNode
& root) |
| 317 { | 317 { |
| 318 Element* element = ElementTraversal::firstWithin(root); | 318 Element* element = ElementTraversal::firstWithin(root); |
| 319 while (element && !isMatchingElement(nodeList, element)) | 319 while (element && !isMatchingElement(nodeList, element)) |
| 320 element = ElementTraversal::next(*element, &root); | 320 element = ElementTraversal::next(*element, &root); |
| 321 return element; | 321 return element; |
| 322 } | 322 } |
| 323 | 323 |
| 324 template <class NodeListType> | 324 template <class NodeListType> |
| 325 inline Element* nextMatchingElement(const NodeListType* nodeList, Element& curre
nt, ContainerNode* root) | 325 inline Element* nextMatchingElement(const NodeListType* nodeList, Element& curre
nt, ContainerNode& root) |
| 326 { | 326 { |
| 327 Element* next = ¤t; | 327 Element* next = ¤t; |
| 328 do { | 328 do { |
| 329 next = ElementTraversal::next(*next, root); | 329 next = ElementTraversal::next(*next, &root); |
| 330 } while (next && !isMatchingElement(nodeList, next)); | 330 } while (next && !isMatchingElement(nodeList, next)); |
| 331 return next; | 331 return next; |
| 332 } | 332 } |
| 333 | 333 |
| 334 template <class NodeListType> | 334 template <class NodeListType> |
| 335 inline Element* traverseMatchingElementsForwardToOffset(const NodeListType* node
List, unsigned offset, Element& currentElement, unsigned& currentOffset, Contain
erNode* root) | 335 inline Element* traverseMatchingElementsForwardToOffset(const NodeListType* node
List, unsigned offset, Element& currentElement, unsigned& currentOffset, Contain
erNode& root) |
| 336 { | 336 { |
| 337 ASSERT(currentOffset < offset); | 337 ASSERT(currentOffset < offset); |
| 338 Element* next = ¤tElement; | 338 Element* next = ¤tElement; |
| 339 while ((next = nextMatchingElement(nodeList, *next, root))) { | 339 while ((next = nextMatchingElement(nodeList, *next, root))) { |
| 340 if (++currentOffset == offset) | 340 if (++currentOffset == offset) |
| 341 return next; | 341 return next; |
| 342 } | 342 } |
| 343 return 0; | 343 return 0; |
| 344 } | 344 } |
| 345 | 345 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 366 return firstMatchingElement(static_cast<const HTMLTagNodeList*>(this), r
oot); | 366 return firstMatchingElement(static_cast<const HTMLTagNodeList*>(this), r
oot); |
| 367 case ClassNodeListType: | 367 case ClassNodeListType: |
| 368 return firstMatchingElement(static_cast<const ClassNodeList*>(this), roo
t); | 368 return firstMatchingElement(static_cast<const ClassNodeList*>(this), roo
t); |
| 369 default: | 369 default: |
| 370 return firstMatchingElement(static_cast<const LiveNodeList*>(this), root
); | 370 return firstMatchingElement(static_cast<const LiveNodeList*>(this), root
); |
| 371 } | 371 } |
| 372 } | 372 } |
| 373 | 373 |
| 374 // FIXME: This should be in LiveNodeList.cpp but it needs to stay here until tra
verseMatchingElementsForwardToOffset() | 374 // FIXME: This should be in LiveNodeList.cpp but it needs to stay here until tra
verseMatchingElementsForwardToOffset() |
| 375 // and others are moved to a separate header. | 375 // and others are moved to a separate header. |
| 376 inline Node* LiveNodeList::traverseForwardToOffset(unsigned offset, Node& curren
tNode, unsigned& currentOffset, ContainerNode* root) const | 376 inline Node* LiveNodeList::traverseForwardToOffset(unsigned offset, Node& curren
tNode, unsigned& currentOffset, ContainerNode& root) const |
| 377 { | 377 { |
| 378 switch (type()) { | 378 switch (type()) { |
| 379 case ChildNodeListType: | 379 case ChildNodeListType: |
| 380 return traverseSiblingsForwardToOffset(offset, currentNode, currentOffse
t); | 380 return traverseSiblingsForwardToOffset(offset, currentNode, currentOffse
t); |
| 381 case HTMLTagNodeListType: | 381 case HTMLTagNodeListType: |
| 382 return traverseMatchingElementsForwardToOffset(static_cast<const HTMLTag
NodeList*>(this), offset, toElement(currentNode), currentOffset, root); | 382 return traverseMatchingElementsForwardToOffset(static_cast<const HTMLTag
NodeList*>(this), offset, toElement(currentNode), currentOffset, root); |
| 383 case ClassNodeListType: | 383 case ClassNodeListType: |
| 384 return traverseMatchingElementsForwardToOffset(static_cast<const ClassNo
deList*>(this), offset, toElement(currentNode), currentOffset, root); | 384 return traverseMatchingElementsForwardToOffset(static_cast<const ClassNo
deList*>(this), offset, toElement(currentNode), currentOffset, root); |
| 385 default: | 385 default: |
| 386 return traverseMatchingElementsForwardToOffset(this, offset, toElement(c
urrentNode), currentOffset, root); | 386 return traverseMatchingElementsForwardToOffset(this, offset, toElement(c
urrentNode), currentOffset, root); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 | 420 |
| 421 // FIXME: It is silly that these functions are in HTMLCollection.cpp. | 421 // FIXME: It is silly that these functions are in HTMLCollection.cpp. |
| 422 Node* LiveNodeListBase::item(unsigned offset) const | 422 Node* LiveNodeListBase::item(unsigned offset) const |
| 423 { | 423 { |
| 424 if (isItemCacheValid() && cachedItemOffset() == offset) | 424 if (isItemCacheValid() && cachedItemOffset() == offset) |
| 425 return cachedItem(); | 425 return cachedItem(); |
| 426 | 426 |
| 427 if (isLengthCacheValid() && cachedLength() <= offset) | 427 if (isLengthCacheValid() && cachedLength() <= offset) |
| 428 return 0; | 428 return 0; |
| 429 | 429 |
| 430 ContainerNode* root = rootContainerNode(); | 430 ContainerNode& root = rootNode(); |
| 431 if (!root) { | |
| 432 // FIMXE: In someTextNode.childNodes case the root is Text. We shouldn't
even make a LiveNodeList for that. | |
| 433 setLengthCache(0); | |
| 434 return 0; | |
| 435 } | |
| 436 | |
| 437 if (isLengthCacheValid() && !overridesItemAfter() && isLastItemCloserThanLas
tOrCachedItem(offset)) { | 431 if (isLengthCacheValid() && !overridesItemAfter() && isLastItemCloserThanLas
tOrCachedItem(offset)) { |
| 438 Node* lastItem = itemBefore(0); | 432 Node* lastItem = itemBefore(0); |
| 439 ASSERT(lastItem); | 433 ASSERT(lastItem); |
| 440 setItemCache(lastItem, cachedLength() - 1); | 434 setItemCache(lastItem, cachedLength() - 1); |
| 441 } else if (!isItemCacheValid() || isFirstItemCloserThanCachedItem(offset) ||
(overridesItemAfter() && offset < cachedItemOffset())) { | 435 } else if (!isItemCacheValid() || isFirstItemCloserThanCachedItem(offset) ||
(overridesItemAfter() && offset < cachedItemOffset())) { |
| 442 Node* firstItem; | 436 Node* firstItem; |
| 443 if (isLiveNodeListType(type())) | 437 if (isLiveNodeListType(type())) |
| 444 firstItem = static_cast<const LiveNodeList*>(this)->traverseToFirstE
lement(*root); | 438 firstItem = static_cast<const LiveNodeList*>(this)->traverseToFirstE
lement(root); |
| 445 else | 439 else |
| 446 firstItem = static_cast<const HTMLCollection*>(this)->traverseToFirs
tElement(*root); | 440 firstItem = static_cast<const HTMLCollection*>(this)->traverseToFirs
tElement(root); |
| 447 | 441 |
| 448 if (!firstItem) { | 442 if (!firstItem) { |
| 449 setLengthCache(0); | 443 setLengthCache(0); |
| 450 return 0; | 444 return 0; |
| 451 } | 445 } |
| 452 setItemCache(firstItem, 0); | 446 setItemCache(firstItem, 0); |
| 453 ASSERT(!cachedItemOffset()); | 447 ASSERT(!cachedItemOffset()); |
| 454 } | 448 } |
| 455 | 449 |
| 456 if (cachedItemOffset() == offset) | 450 if (cachedItemOffset() == offset) |
| 457 return cachedItem(); | 451 return cachedItem(); |
| 458 | 452 |
| 459 return itemBeforeOrAfterCachedItem(offset, root); | 453 return itemBeforeOrAfterCachedItem(offset, root); |
| 460 } | 454 } |
| 461 | 455 |
| 462 inline Node* LiveNodeListBase::itemBeforeOrAfterCachedItem(unsigned offset, Cont
ainerNode* root) const | 456 inline Node* LiveNodeListBase::itemBeforeOrAfterCachedItem(unsigned offset, Cont
ainerNode& root) const |
| 463 { | 457 { |
| 464 unsigned currentOffset = cachedItemOffset(); | 458 unsigned currentOffset = cachedItemOffset(); |
| 465 Node* currentItem = cachedItem(); | 459 Node* currentItem = cachedItem(); |
| 466 ASSERT(currentItem); | 460 ASSERT(currentItem); |
| 467 ASSERT(currentOffset != offset); | 461 ASSERT(currentOffset != offset); |
| 468 | 462 |
| 469 if (offset < cachedItemOffset()) { | 463 if (offset < cachedItemOffset()) { |
| 470 ASSERT(!overridesItemAfter()); | 464 ASSERT(!overridesItemAfter()); |
| 471 while ((currentItem = itemBefore(currentItem))) { | 465 while ((currentItem = itemBefore(currentItem))) { |
| 472 ASSERT(currentOffset); | 466 ASSERT(currentOffset); |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 529 } | 523 } |
| 530 | 524 |
| 531 inline Element* firstMatchingChildElement(const HTMLCollection* nodeList, Contai
nerNode& root) | 525 inline Element* firstMatchingChildElement(const HTMLCollection* nodeList, Contai
nerNode& root) |
| 532 { | 526 { |
| 533 Element* element = ElementTraversal::firstWithin(root); | 527 Element* element = ElementTraversal::firstWithin(root); |
| 534 while (element && !isMatchingElement(nodeList, element)) | 528 while (element && !isMatchingElement(nodeList, element)) |
| 535 element = ElementTraversal::nextSkippingChildren(*element, &root); | 529 element = ElementTraversal::nextSkippingChildren(*element, &root); |
| 536 return element; | 530 return element; |
| 537 } | 531 } |
| 538 | 532 |
| 539 inline Element* nextMatchingChildElement(const HTMLCollection* nodeList, Element
& current, ContainerNode* root) | 533 inline Element* nextMatchingChildElement(const HTMLCollection* nodeList, Element
& current, ContainerNode& root) |
| 540 { | 534 { |
| 541 Element* next = ¤t; | 535 Element* next = ¤t; |
| 542 do { | 536 do { |
| 543 next = ElementTraversal::nextSkippingChildren(*next, root); | 537 next = ElementTraversal::nextSkippingChildren(*next, &root); |
| 544 } while (next && !isMatchingElement(nodeList, next)); | 538 } while (next && !isMatchingElement(nodeList, next)); |
| 545 return next; | 539 return next; |
| 546 } | 540 } |
| 547 | 541 |
| 548 inline Element* HTMLCollection::traverseToFirstElement(ContainerNode& root) cons
t | 542 inline Element* HTMLCollection::traverseToFirstElement(ContainerNode& root) cons
t |
| 549 { | 543 { |
| 550 if (overridesItemAfter()) | 544 if (overridesItemAfter()) |
| 551 return virtualItemAfter(0); | 545 return virtualItemAfter(0); |
| 552 if (shouldOnlyIncludeDirectChildren()) | 546 if (shouldOnlyIncludeDirectChildren()) |
| 553 return firstMatchingChildElement(static_cast<const HTMLCollection*>(this
), root); | 547 return firstMatchingChildElement(static_cast<const HTMLCollection*>(this
), root); |
| 554 return firstMatchingElement(static_cast<const HTMLCollection*>(this), root); | 548 return firstMatchingElement(static_cast<const HTMLCollection*>(this), root); |
| 555 } | 549 } |
| 556 | 550 |
| 557 inline Element* HTMLCollection::traverseNextElement(Element& previous, Container
Node* root) const | 551 inline Element* HTMLCollection::traverseNextElement(Element& previous, Container
Node& root) const |
| 558 { | 552 { |
| 559 if (overridesItemAfter()) | 553 if (overridesItemAfter()) |
| 560 return virtualItemAfter(&previous); | 554 return virtualItemAfter(&previous); |
| 561 if (shouldOnlyIncludeDirectChildren()) | 555 if (shouldOnlyIncludeDirectChildren()) |
| 562 return nextMatchingChildElement(this, previous, root); | 556 return nextMatchingChildElement(this, previous, root); |
| 563 return nextMatchingElement(this, previous, root); | 557 return nextMatchingElement(this, previous, root); |
| 564 } | 558 } |
| 565 | 559 |
| 566 inline Element* HTMLCollection::traverseForwardToOffset(unsigned offset, Element
& currentElement, unsigned& currentOffset, ContainerNode* root) const | 560 inline Element* HTMLCollection::traverseForwardToOffset(unsigned offset, Element
& currentElement, unsigned& currentOffset, ContainerNode& root) const |
| 567 { | 561 { |
| 568 ASSERT(currentOffset < offset); | 562 ASSERT(currentOffset < offset); |
| 569 if (overridesItemAfter()) { | 563 if (overridesItemAfter()) { |
| 570 Element* next = ¤tElement; | 564 Element* next = ¤tElement; |
| 571 while ((next = virtualItemAfter(next))) { | 565 while ((next = virtualItemAfter(next))) { |
| 572 if (++currentOffset == offset) | 566 if (++currentOffset == offset) |
| 573 return next; | 567 return next; |
| 574 } | 568 } |
| 575 return 0; | 569 return 0; |
| 576 } | 570 } |
| 577 if (shouldOnlyIncludeDirectChildren()) { | 571 if (shouldOnlyIncludeDirectChildren()) { |
| 578 Element* next = ¤tElement; | 572 Element* next = ¤tElement; |
| 579 while ((next = nextMatchingChildElement(this, *next, root))) { | 573 while ((next = nextMatchingChildElement(this, *next, root))) { |
| 580 if (++currentOffset == offset) | 574 if (++currentOffset == offset) |
| 581 return next; | 575 return next; |
| 582 } | 576 } |
| 583 return 0; | 577 return 0; |
| 584 } | 578 } |
| 585 return traverseMatchingElementsForwardToOffset(this, offset, currentElement,
currentOffset, root); | 579 return traverseMatchingElementsForwardToOffset(this, offset, currentElement,
currentOffset, root); |
| 586 } | 580 } |
| 587 | 581 |
| 588 Node* HTMLCollection::namedItem(const AtomicString& name) const | 582 Node* HTMLCollection::namedItem(const AtomicString& name) const |
| 589 { | 583 { |
| 590 // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/namedit
em.asp | 584 // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/namedit
em.asp |
| 591 // This method first searches for an object with a matching id | 585 // This method first searches for an object with a matching id |
| 592 // attribute. If a match is not found, the method then searches for an | 586 // attribute. If a match is not found, the method then searches for an |
| 593 // object with a matching name attribute, but only on those elements | 587 // object with a matching name attribute, but only on those elements |
| 594 // that are allowed a name attribute. | 588 // that are allowed a name attribute. |
| 595 | 589 |
| 596 ContainerNode* root = rootContainerNode(); | 590 ContainerNode& root = rootNode(); |
| 597 if (!root) | |
| 598 return 0; | |
| 599 | |
| 600 unsigned i = 0; | 591 unsigned i = 0; |
| 601 for (Element* element = traverseToFirstElement(*root); element; element = tr
averseNextElement(*element, root)) { | 592 for (Element* element = traverseToFirstElement(root); element; element = tra
verseNextElement(*element, root)) { |
| 602 if (checkForNameMatch(element, /* checkName */ false, name)) { | 593 if (checkForNameMatch(element, /* checkName */ false, name)) { |
| 603 setItemCache(element, i); | 594 setItemCache(element, i); |
| 604 return element; | 595 return element; |
| 605 } | 596 } |
| 606 i++; | 597 i++; |
| 607 } | 598 } |
| 608 | 599 |
| 609 i = 0; | 600 i = 0; |
| 610 for (Element* element = traverseToFirstElement(*root); element; element = tr
averseNextElement(*element, root)) { | 601 for (Element* element = traverseToFirstElement(root); element; element = tra
verseNextElement(*element, root)) { |
| 611 if (checkForNameMatch(element, /* checkName */ true, name)) { | 602 if (checkForNameMatch(element, /* checkName */ true, name)) { |
| 612 setItemCache(element, i); | 603 setItemCache(element, i); |
| 613 return element; | 604 return element; |
| 614 } | 605 } |
| 615 i++; | 606 i++; |
| 616 } | 607 } |
| 617 | 608 |
| 618 return 0; | 609 return 0; |
| 619 } | 610 } |
| 620 | 611 |
| 621 void HTMLCollection::updateNameCache() const | 612 void HTMLCollection::updateNameCache() const |
| 622 { | 613 { |
| 623 if (hasNameCache()) | 614 if (hasNameCache()) |
| 624 return; | 615 return; |
| 625 | 616 |
| 626 ContainerNode* root = rootContainerNode(); | 617 ContainerNode& root = rootNode(); |
| 627 if (!root) | 618 for (Element* element = traverseToFirstElement(root); element; element = tra
verseNextElement(*element, root)) { |
| 628 return; | |
| 629 | |
| 630 for (Element* element = traverseToFirstElement(*root); element; element = tr
averseNextElement(*element, root)) { | |
| 631 const AtomicString& idAttrVal = element->getIdAttribute(); | 619 const AtomicString& idAttrVal = element->getIdAttribute(); |
| 632 if (!idAttrVal.isEmpty()) | 620 if (!idAttrVal.isEmpty()) |
| 633 appendIdCache(idAttrVal, element); | 621 appendIdCache(idAttrVal, element); |
| 634 if (!element->isHTMLElement()) | 622 if (!element->isHTMLElement()) |
| 635 continue; | 623 continue; |
| 636 const AtomicString& nameAttrVal = element->getNameAttribute(); | 624 const AtomicString& nameAttrVal = element->getNameAttribute(); |
| 637 if (!nameAttrVal.isEmpty() && idAttrVal != nameAttrVal && (type() != Doc
All || nameShouldBeVisibleInDocumentAll(toHTMLElement(element)))) | 625 if (!nameAttrVal.isEmpty() && idAttrVal != nameAttrVal && (type() != Doc
All || nameShouldBeVisibleInDocumentAll(toHTMLElement(element)))) |
| 638 appendNameCache(nameAttrVal, element); | 626 appendNameCache(nameAttrVal, element); |
| 639 } | 627 } |
| 640 | 628 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 661 | 649 |
| 662 void HTMLCollection::append(NodeCacheMap& map, const AtomicString& key, Element*
element) | 650 void HTMLCollection::append(NodeCacheMap& map, const AtomicString& key, Element*
element) |
| 663 { | 651 { |
| 664 OwnPtr<Vector<Element*> >& vector = map.add(key.impl(), nullptr).iterator->v
alue; | 652 OwnPtr<Vector<Element*> >& vector = map.add(key.impl(), nullptr).iterator->v
alue; |
| 665 if (!vector) | 653 if (!vector) |
| 666 vector = adoptPtr(new Vector<Element*>); | 654 vector = adoptPtr(new Vector<Element*>); |
| 667 vector->append(element); | 655 vector->append(element); |
| 668 } | 656 } |
| 669 | 657 |
| 670 } // namespace WebCore | 658 } // namespace WebCore |
| OLD | NEW |