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 |