Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(19)

Side by Side Diff: Source/core/html/HTMLCollection.cpp

Issue 113653006: Remove complexity related to m_cachedElementsArrayOffset from LiveNodeListBase (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Rebase Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 return adoptRef(new HTMLCollection(base, type, DoesNotOverrideItemAfter)); 172 return adoptRef(new HTMLCollection(base, type, DoesNotOverrideItemAfter));
173 } 173 }
174 174
175 HTMLCollection::~HTMLCollection() 175 HTMLCollection::~HTMLCollection()
176 { 176 {
177 // HTMLNameCollection removes cache by itself. 177 // HTMLNameCollection removes cache by itself.
178 if (type() != WindowNamedItems && type() != DocumentNamedItems) 178 if (type() != WindowNamedItems && type() != DocumentNamedItems)
179 ownerNode()->nodeLists()->removeCacheWithAtomicName(this, type()); 179 ownerNode()->nodeLists()->removeCacheWithAtomicName(this, type());
180 } 180 }
181 181
182 void HTMLCollection::invalidateCache() const
183 {
184 LiveNodeListBase::invalidateCache();
185 invalidateIdNameCacheMaps();
186 }
187
182 template <class NodeListType> 188 template <class NodeListType>
183 inline bool isMatchingElement(const NodeListType*, Element*); 189 inline bool isMatchingElement(const NodeListType*, Element*);
184 190
185 template <> inline bool isMatchingElement(const HTMLCollection* htmlCollection, Element* element) 191 template <> inline bool isMatchingElement(const HTMLCollection* htmlCollection, Element* element)
186 { 192 {
187 CollectionType type = htmlCollection->type(); 193 CollectionType type = htmlCollection->type();
188 if (!element->isHTMLElement() && !(type == DocAll || type == NodeChildren || type == WindowNamedItems)) 194 if (!element->isHTMLElement() && !(type == DocAll || type == NodeChildren || type == WindowNamedItems))
189 return false; 195 return false;
190 196
191 switch (type) { 197 switch (type) {
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after
385 bool ALWAYS_INLINE LiveNodeListBase::isFirstItemCloserThanCachedItem(unsigned of fset) const 391 bool ALWAYS_INLINE LiveNodeListBase::isFirstItemCloserThanCachedItem(unsigned of fset) const
386 { 392 {
387 ASSERT(isItemCacheValid()); 393 ASSERT(isItemCacheValid());
388 if (cachedItemOffset() < offset) 394 if (cachedItemOffset() < offset)
389 return false; 395 return false;
390 396
391 unsigned distanceFromCachedItem = cachedItemOffset() - offset; 397 unsigned distanceFromCachedItem = cachedItemOffset() - offset;
392 return offset < distanceFromCachedItem; 398 return offset < distanceFromCachedItem;
393 } 399 }
394 400
395 ALWAYS_INLINE void LiveNodeListBase::setItemCache(Node* item, unsigned offset, u nsigned elementsArrayOffset) const
396 {
397 setItemCache(item, offset);
398 if (overridesItemAfter()) {
399 ASSERT_WITH_SECURITY_IMPLICATION(item->isElementNode());
400 static_cast<const HTMLCollection*>(this)->m_cachedElementsArrayOffset = elementsArrayOffset;
401 } else
402 ASSERT(!elementsArrayOffset);
403 }
404
405 unsigned LiveNodeListBase::length() const 401 unsigned LiveNodeListBase::length() const
406 { 402 {
407 if (isLengthCacheValid()) 403 if (isLengthCacheValid())
408 return cachedLength(); 404 return cachedLength();
409 405
410 item(UINT_MAX); 406 item(UINT_MAX);
411 ASSERT(isLengthCacheValid()); 407 ASSERT(isLengthCacheValid());
412 408
413 return cachedLength(); 409 return cachedLength();
414 } 410 }
(...skipping 10 matching lines...) Expand all
425 ContainerNode* root = rootContainerNode(); 421 ContainerNode* root = rootContainerNode();
426 if (!root) { 422 if (!root) {
427 // FIMXE: In someTextNode.childNodes case the root is Text. We shouldn't even make a LiveNodeList for that. 423 // FIMXE: In someTextNode.childNodes case the root is Text. We shouldn't even make a LiveNodeList for that.
428 setLengthCache(0); 424 setLengthCache(0);
429 return 0; 425 return 0;
430 } 426 }
431 427
432 if (isLengthCacheValid() && !overridesItemAfter() && isLastItemCloserThanLas tOrCachedItem(offset)) { 428 if (isLengthCacheValid() && !overridesItemAfter() && isLastItemCloserThanLas tOrCachedItem(offset)) {
433 Node* lastItem = itemBefore(0); 429 Node* lastItem = itemBefore(0);
434 ASSERT(lastItem); 430 ASSERT(lastItem);
435 setItemCache(lastItem, cachedLength() - 1, 0); 431 setItemCache(lastItem, cachedLength() - 1);
436 } else if (!isItemCacheValid() || isFirstItemCloserThanCachedItem(offset) || (overridesItemAfter() && offset < cachedItemOffset())) { 432 } else if (!isItemCacheValid() || isFirstItemCloserThanCachedItem(offset) || (overridesItemAfter() && offset < cachedItemOffset())) {
437 unsigned offsetInArray = 0;
438 Node* firstItem; 433 Node* firstItem;
439 if (type() == ChildNodeListType) 434 if (type() == ChildNodeListType)
440 firstItem = root->firstChild(); 435 firstItem = root->firstChild();
441 else if (isNodeList(type())) 436 else if (isNodeList(type()))
442 firstItem = traverseLiveNodeListFirstElement(*root); 437 firstItem = traverseLiveNodeListFirstElement(*root);
443 else 438 else
444 firstItem = static_cast<const HTMLCollection*>(this)->traverseFirstE lement(offsetInArray, *root); 439 firstItem = static_cast<const HTMLCollection*>(this)->traverseFirstE lement(*root);
445 440
446 if (!firstItem) { 441 if (!firstItem) {
447 setLengthCache(0); 442 setLengthCache(0);
448 return 0; 443 return 0;
449 } 444 }
450 setItemCache(firstItem, 0, offsetInArray); 445 setItemCache(firstItem, 0);
451 ASSERT(!cachedItemOffset()); 446 ASSERT(!cachedItemOffset());
452 } 447 }
453 448
454 if (cachedItemOffset() == offset) 449 if (cachedItemOffset() == offset)
455 return cachedItem(); 450 return cachedItem();
456 451
457 return itemBeforeOrAfterCachedItem(offset, root); 452 return itemBeforeOrAfterCachedItem(offset, root);
458 } 453 }
459 454
460 inline Node* LiveNodeListBase::itemBeforeOrAfterCachedItem(unsigned offset, Cont ainerNode* root) const 455 inline Node* LiveNodeListBase::itemBeforeOrAfterCachedItem(unsigned offset, Cont ainerNode* root) const
461 { 456 {
462 unsigned currentOffset = cachedItemOffset(); 457 unsigned currentOffset = cachedItemOffset();
463 Node* currentItem = cachedItem(); 458 Node* currentItem = cachedItem();
464 ASSERT(currentItem); 459 ASSERT(currentItem);
465 ASSERT(currentOffset != offset); 460 ASSERT(currentOffset != offset);
466 461
467 if (offset < cachedItemOffset()) { 462 if (offset < cachedItemOffset()) {
468 ASSERT(!overridesItemAfter()); 463 ASSERT(!overridesItemAfter());
469 while ((currentItem = itemBefore(currentItem))) { 464 while ((currentItem = itemBefore(currentItem))) {
470 ASSERT(currentOffset); 465 ASSERT(currentOffset);
471 currentOffset--; 466 currentOffset--;
472 if (currentOffset == offset) { 467 if (currentOffset == offset) {
473 setItemCache(currentItem, currentOffset, 0); 468 setItemCache(currentItem, currentOffset);
474 return currentItem; 469 return currentItem;
475 } 470 }
476 } 471 }
477 ASSERT_NOT_REACHED(); 472 ASSERT_NOT_REACHED();
478 return 0; 473 return 0;
479 } 474 }
480 475
481 unsigned offsetInArray = 0;
482 if (type() == ChildNodeListType) 476 if (type() == ChildNodeListType)
483 currentItem = traverseChildNodeListForwardToOffset(offset, currentItem, currentOffset); 477 currentItem = traverseChildNodeListForwardToOffset(offset, currentItem, currentOffset);
484 else if (isNodeList(type())) 478 else if (isNodeList(type()))
485 currentItem = traverseLiveNodeListForwardToOffset(offset, toElement(*cur rentItem), currentOffset, root); 479 currentItem = traverseLiveNodeListForwardToOffset(offset, toElement(*cur rentItem), currentOffset, root);
486 else 480 else
487 currentItem = static_cast<const HTMLCollection*>(this)->traverseForwardT oOffset(offset, toElement(*currentItem), currentOffset, offsetInArray, root); 481 currentItem = static_cast<const HTMLCollection*>(this)->traverseForwardT oOffset(offset, toElement(*currentItem), currentOffset, root);
488 482
489 if (!currentItem) { 483 if (!currentItem) {
490 // Did not find the item. On plus side, we now know the length. 484 // Did not find the item. On plus side, we now know the length.
491 setLengthCache(currentOffset + 1); 485 setLengthCache(currentOffset + 1);
492 return 0; 486 return 0;
493 } 487 }
494 setItemCache(currentItem, currentOffset, offsetInArray); 488 setItemCache(currentItem, currentOffset);
495 return currentItem; 489 return currentItem;
496 } 490 }
497 491
498 Element* HTMLCollection::virtualItemAfter(unsigned&, Element*) const 492 Element* HTMLCollection::virtualItemAfter(Element*) const
499 { 493 {
500 ASSERT_NOT_REACHED(); 494 ASSERT_NOT_REACHED();
501 return 0; 495 return 0;
502 } 496 }
503 497
504 static inline bool nameShouldBeVisibleInDocumentAll(HTMLElement* element) 498 static inline bool nameShouldBeVisibleInDocumentAll(HTMLElement* element)
505 { 499 {
506 // The document.all collection returns only certain types of elements by nam e, 500 // The document.all collection returns only certain types of elements by nam e,
507 // although it returns any type of element by id. 501 // although it returns any type of element by id.
508 return element->hasLocalName(appletTag) 502 return element->hasLocalName(appletTag)
(...skipping 30 matching lines...) Expand all
539 533
540 inline Element* nextMatchingChildElement(const HTMLCollection* nodeList, Element & current, ContainerNode* root) 534 inline Element* nextMatchingChildElement(const HTMLCollection* nodeList, Element & current, ContainerNode* root)
541 { 535 {
542 Element* next = &current; 536 Element* next = &current;
543 do { 537 do {
544 next = ElementTraversal::nextSkippingChildren(*next, root); 538 next = ElementTraversal::nextSkippingChildren(*next, root);
545 } while (next && !isMatchingElement(nodeList, next)); 539 } while (next && !isMatchingElement(nodeList, next));
546 return next; 540 return next;
547 } 541 }
548 542
549 inline Element* HTMLCollection::traverseFirstElement(unsigned& offsetInArray, Co ntainerNode& root) const 543 inline Element* HTMLCollection::traverseFirstElement(ContainerNode& root) const
550 { 544 {
551 if (overridesItemAfter()) 545 if (overridesItemAfter())
552 return virtualItemAfter(offsetInArray, 0); 546 return virtualItemAfter(0);
553 ASSERT(!offsetInArray);
554 if (shouldOnlyIncludeDirectChildren()) 547 if (shouldOnlyIncludeDirectChildren())
555 return firstMatchingChildElement(static_cast<const HTMLCollection*>(this ), root); 548 return firstMatchingChildElement(static_cast<const HTMLCollection*>(this ), root);
556 return firstMatchingElement(static_cast<const HTMLCollection*>(this), root); 549 return firstMatchingElement(static_cast<const HTMLCollection*>(this), root);
557 } 550 }
558 551
559 inline Element* HTMLCollection::traverseNextElement(unsigned& offsetInArray, Ele ment& previous, ContainerNode* root) const 552 inline Element* HTMLCollection::traverseNextElement(Element& previous, Container Node* root) const
560 { 553 {
561 if (overridesItemAfter()) 554 if (overridesItemAfter())
562 return virtualItemAfter(offsetInArray, &previous); 555 return virtualItemAfter(&previous);
563 ASSERT(!offsetInArray);
564 if (shouldOnlyIncludeDirectChildren()) 556 if (shouldOnlyIncludeDirectChildren())
565 return nextMatchingChildElement(this, previous, root); 557 return nextMatchingChildElement(this, previous, root);
566 return nextMatchingElement(this, previous, root); 558 return nextMatchingElement(this, previous, root);
567 } 559 }
568 560
569 inline Element* HTMLCollection::traverseForwardToOffset(unsigned offset, Element & currentElement, unsigned& currentOffset, unsigned& offsetInArray, ContainerNod e* root) const 561 inline Element* HTMLCollection::traverseForwardToOffset(unsigned offset, Element & currentElement, unsigned& currentOffset, ContainerNode* root) const
570 { 562 {
571 ASSERT(currentOffset < offset); 563 ASSERT(currentOffset < offset);
572 if (overridesItemAfter()) { 564 if (overridesItemAfter()) {
573 offsetInArray = m_cachedElementsArrayOffset;
574 Element* next = &currentElement; 565 Element* next = &currentElement;
575 while ((next = virtualItemAfter(offsetInArray, next))) { 566 while ((next = virtualItemAfter(next))) {
576 if (++currentOffset == offset) 567 if (++currentOffset == offset)
577 return next; 568 return next;
578 } 569 }
579 return 0; 570 return 0;
580 } 571 }
581 if (shouldOnlyIncludeDirectChildren()) { 572 if (shouldOnlyIncludeDirectChildren()) {
582 Element* next = &currentElement; 573 Element* next = &currentElement;
583 while ((next = nextMatchingChildElement(this, *next, root))) { 574 while ((next = nextMatchingChildElement(this, *next, root))) {
584 if (++currentOffset == offset) 575 if (++currentOffset == offset)
585 return next; 576 return next;
586 } 577 }
587 return 0; 578 return 0;
588 } 579 }
589 return traverseMatchingElementsForwardToOffset(this, offset, currentElement, currentOffset, root); 580 return traverseMatchingElementsForwardToOffset(this, offset, currentElement, currentOffset, root);
590 } 581 }
591 582
592 Node* HTMLCollection::namedItem(const AtomicString& name) const 583 Node* HTMLCollection::namedItem(const AtomicString& name) const
593 { 584 {
594 // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/namedit em.asp 585 // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/namedit em.asp
595 // This method first searches for an object with a matching id 586 // This method first searches for an object with a matching id
596 // attribute. If a match is not found, the method then searches for an 587 // attribute. If a match is not found, the method then searches for an
597 // object with a matching name attribute, but only on those elements 588 // object with a matching name attribute, but only on those elements
598 // that are allowed a name attribute. 589 // that are allowed a name attribute.
599 590
600 ContainerNode* root = rootContainerNode(); 591 ContainerNode* root = rootContainerNode();
601 if (!root) 592 if (!root)
602 return 0; 593 return 0;
603 594
604 unsigned arrayOffset = 0;
605 unsigned i = 0; 595 unsigned i = 0;
606 for (Element* element = traverseFirstElement(arrayOffset, *root); element; e lement = traverseNextElement(arrayOffset, *element, root)) { 596 for (Element* element = traverseFirstElement(*root); element; element = trav erseNextElement(*element, root)) {
607 if (checkForNameMatch(element, /* checkName */ false, name)) { 597 if (checkForNameMatch(element, /* checkName */ false, name)) {
608 setItemCache(element, i, arrayOffset); 598 setItemCache(element, i);
609 return element; 599 return element;
610 } 600 }
611 i++; 601 i++;
612 } 602 }
613 603
614 i = 0; 604 i = 0;
615 for (Element* element = traverseFirstElement(arrayOffset, *root); element; e lement = traverseNextElement(arrayOffset, *element, root)) { 605 for (Element* element = traverseFirstElement(*root); element; element = trav erseNextElement(*element, root)) {
616 if (checkForNameMatch(element, /* checkName */ true, name)) { 606 if (checkForNameMatch(element, /* checkName */ true, name)) {
617 setItemCache(element, i, arrayOffset); 607 setItemCache(element, i);
618 return element; 608 return element;
619 } 609 }
620 i++; 610 i++;
621 } 611 }
622 612
623 return 0; 613 return 0;
624 } 614 }
625 615
626 void HTMLCollection::updateNameCache() const 616 void HTMLCollection::updateNameCache() const
627 { 617 {
628 if (hasNameCache()) 618 if (hasNameCache())
629 return; 619 return;
630 620
631 ContainerNode* root = rootContainerNode(); 621 ContainerNode* root = rootContainerNode();
632 if (!root) 622 if (!root)
633 return; 623 return;
634 624
635 unsigned arrayOffset = 0; 625 for (Element* element = traverseFirstElement(*root); element; element = trav erseNextElement(*element, root)) {
636 for (Element* element = traverseFirstElement(arrayOffset, *root); element; e lement = traverseNextElement(arrayOffset, *element, root)) {
637 const AtomicString& idAttrVal = element->getIdAttribute(); 626 const AtomicString& idAttrVal = element->getIdAttribute();
638 if (!idAttrVal.isEmpty()) 627 if (!idAttrVal.isEmpty())
639 appendIdCache(idAttrVal, element); 628 appendIdCache(idAttrVal, element);
640 if (!element->isHTMLElement()) 629 if (!element->isHTMLElement())
641 continue; 630 continue;
642 const AtomicString& nameAttrVal = element->getNameAttribute(); 631 const AtomicString& nameAttrVal = element->getNameAttribute();
643 if (!nameAttrVal.isEmpty() && idAttrVal != nameAttrVal && (type() != Doc All || nameShouldBeVisibleInDocumentAll(toHTMLElement(element)))) 632 if (!nameAttrVal.isEmpty() && idAttrVal != nameAttrVal && (type() != Doc All || nameShouldBeVisibleInDocumentAll(toHTMLElement(element))))
644 appendNameCache(nameAttrVal, element); 633 appendNameCache(nameAttrVal, element);
645 } 634 }
646 635
(...skipping 20 matching lines...) Expand all
667 656
668 void HTMLCollection::append(NodeCacheMap& map, const AtomicString& key, Element* element) 657 void HTMLCollection::append(NodeCacheMap& map, const AtomicString& key, Element* element)
669 { 658 {
670 OwnPtr<Vector<Element*> >& vector = map.add(key.impl(), nullptr).iterator->v alue; 659 OwnPtr<Vector<Element*> >& vector = map.add(key.impl(), nullptr).iterator->v alue;
671 if (!vector) 660 if (!vector)
672 vector = adoptPtr(new Vector<Element*>); 661 vector = adoptPtr(new Vector<Element*>);
673 vector->append(element); 662 vector->append(element);
674 } 663 }
675 664
676 } // namespace WebCore 665 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698