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

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

Issue 134193005: Move caching out of LiveNodeListBase and into a new CollectionIndexCache class (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Rebase Created 6 years, 10 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
« no previous file with comments | « Source/core/html/HTMLCollection.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 }
182 182
183 void HTMLCollection::invalidateCache() const 183 void HTMLCollection::invalidateCache() const
184 { 184 {
185 LiveNodeListBase::invalidateCache(); 185 m_collectionIndexCache.invalidate();
186 invalidateIdNameCacheMaps(); 186 invalidateIdNameCacheMaps();
187 } 187 }
188 188
189 template <class NodeListType> 189 template <class NodeListType>
190 inline bool isMatchingElement(const NodeListType&, const Element&); 190 inline bool isMatchingElement(const NodeListType&, const Element&);
191 191
192 template <> inline bool isMatchingElement(const HTMLCollection& htmlCollection, const Element& element) 192 template <> inline bool isMatchingElement(const HTMLCollection& htmlCollection, const Element& element)
193 { 193 {
194 CollectionType type = htmlCollection.type(); 194 CollectionType type = htmlCollection.type();
195 if (!element.isHTMLElement() && !(type == DocAll || type == NodeChildren || type == WindowNamedItems)) 195 if (!element.isHTMLElement() && !(type == DocAll || type == NodeChildren || type == WindowNamedItems))
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 if (current->isElementNode() && isMatchingElement(static_cast<const LiveNodeList&>(*this), toElement(*current))) 292 if (current->isElementNode() && isMatchingElement(static_cast<const LiveNodeList&>(*this), toElement(*current)))
293 return toElement(current); 293 return toElement(current);
294 } else { 294 } else {
295 if (current->isElementNode() && isMatchingElement(static_cast<const HTMLCollection&>(*this), toElement(*current))) 295 if (current->isElementNode() && isMatchingElement(static_cast<const HTMLCollection&>(*this), toElement(*current)))
296 return toElement(current); 296 return toElement(current);
297 } 297 }
298 } 298 }
299 return 0; 299 return 0;
300 } 300 }
301 301
302 ALWAYS_INLINE Node* LiveNodeListBase::itemBefore(const Node* previous) const 302 Node* LiveNodeListBase::itemBefore(const Node* previous) const
303 { 303 {
304 Node* current; 304 Node* current;
305 if (LIKELY(!!previous)) // Without this LIKELY, length() and item() can be 1 0% slower. 305 if (LIKELY(!!previous)) // Without this LIKELY, length() and item() can be 1 0% slower.
306 current = previousNode(rootNode(), *previous, shouldOnlyIncludeDirectChi ldren()); 306 current = previousNode(rootNode(), *previous, shouldOnlyIncludeDirectChi ldren());
307 else 307 else
308 current = lastNode(rootNode(), shouldOnlyIncludeDirectChildren()); 308 current = lastNode(rootNode(), shouldOnlyIncludeDirectChildren());
309 309
310 if (type() == ChildNodeListType) 310 if (type() == ChildNodeListType)
311 return current; 311 return current;
312 return iterateForPreviousNode(current); 312 return iterateForPreviousNode(current);
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
349 Node* next = &currentNode; 349 Node* next = &currentNode;
350 while ((next = next->nextSibling())) { 350 while ((next = next->nextSibling())) {
351 if (++currentOffset == offset) 351 if (++currentOffset == offset)
352 return next; 352 return next;
353 } 353 }
354 return 0; 354 return 0;
355 } 355 }
356 356
357 // FIXME: This should be in LiveNodeList.cpp but it needs to stay here until fir stMatchingElement() 357 // FIXME: This should be in LiveNodeList.cpp but it needs to stay here until fir stMatchingElement()
358 // and others are moved to a separate header. 358 // and others are moved to a separate header.
359 inline Node* LiveNodeList::traverseToFirstElement(const ContainerNode& root) con st 359 Node* LiveNodeList::traverseToFirstElement(const ContainerNode& root) const
360 { 360 {
361 ASSERT(isLiveNodeListType(type())); 361 ASSERT(isLiveNodeListType(type()));
362 switch (type()) { 362 switch (type()) {
363 case ChildNodeListType: 363 case ChildNodeListType:
364 return root.firstChild(); 364 return root.firstChild();
365 case HTMLTagNodeListType: 365 case HTMLTagNodeListType:
366 return firstMatchingElement(static_cast<const HTMLTagNodeList&>(*this), root); 366 return firstMatchingElement(static_cast<const HTMLTagNodeList&>(*this), root);
367 case ClassNodeListType: 367 case ClassNodeListType:
368 return firstMatchingElement(static_cast<const ClassNodeList&>(*this), ro ot); 368 return firstMatchingElement(static_cast<const ClassNodeList&>(*this), ro ot);
369 default: 369 default:
370 return firstMatchingElement(static_cast<const LiveNodeList&>(*this), roo t); 370 return firstMatchingElement(static_cast<const LiveNodeList&>(*this), roo t);
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, const ContainerNode& root) const 376 Node* LiveNodeList::traverseForwardToOffset(unsigned offset, Node& currentNode, unsigned& currentOffset, const 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( currentNode), currentOffset, root); 386 return traverseMatchingElementsForwardToOffset(*this, offset, toElement( currentNode), currentOffset, root);
387 } 387 }
388 } 388 }
389 389
390 bool ALWAYS_INLINE LiveNodeListBase::isLastItemCloserThanLastOrCachedItem(unsign ed offset) const
391 {
392 ASSERT(isLengthCacheValid());
393 unsigned distanceFromLastItem = cachedLength() - offset;
394 if (!cachedItem())
395 return distanceFromLastItem < offset;
396
397 return cachedItemOffset() < offset && distanceFromLastItem < offset - cached ItemOffset();
398 }
399
400 bool ALWAYS_INLINE LiveNodeListBase::isFirstItemCloserThanCachedItem(unsigned of fset) const
401 {
402 if (cachedItemOffset() < offset)
403 return false;
404
405 unsigned distanceFromCachedItem = cachedItemOffset() - offset;
406 return offset < distanceFromCachedItem;
407 }
408
409 unsigned LiveNodeListBase::length() const
410 {
411 if (isLengthCacheValid())
412 return cachedLength();
413
414 item(UINT_MAX);
415 ASSERT(isLengthCacheValid());
416
417 return cachedLength();
418 }
419
420 // FIXME: It is silly that these functions are in HTMLCollection.cpp.
421 Node* LiveNodeListBase::item(unsigned offset) const
422 {
423 if (cachedItem() && cachedItemOffset() == offset)
424 return cachedItem();
425
426 if (isLengthCacheValid() && cachedLength() <= offset)
427 return 0;
428
429 ContainerNode& root = rootNode();
430 if (isLengthCacheValid() && !overridesItemAfter() && isLastItemCloserThanLas tOrCachedItem(offset)) {
431 Node* lastItem = itemBefore(0);
432 ASSERT(lastItem);
433 setItemCache(lastItem, cachedLength() - 1);
434 } else if (!cachedItem() || isFirstItemCloserThanCachedItem(offset) || (over ridesItemAfter() && offset < cachedItemOffset())) {
435 Node* firstItem;
436 if (isLiveNodeListType(type()))
437 firstItem = static_cast<const LiveNodeList*>(this)->traverseToFirstE lement(root);
438 else
439 firstItem = static_cast<const HTMLCollection*>(this)->traverseToFirs tElement(root);
440
441 if (!firstItem) {
442 setLengthCache(0);
443 return 0;
444 }
445 setItemCache(firstItem, 0);
446 ASSERT(!cachedItemOffset());
447 }
448
449 if (cachedItemOffset() == offset)
450 return cachedItem();
451
452 return itemBeforeOrAfterCachedItem(offset, root);
453 }
454
455 inline Node* LiveNodeListBase::itemBeforeOrAfterCachedItem(unsigned offset, cons t ContainerNode& root) const
456 {
457 unsigned currentOffset = cachedItemOffset();
458 Node* currentItem = cachedItem();
459 ASSERT(currentItem);
460 ASSERT(currentOffset != offset);
461
462 if (offset < cachedItemOffset()) {
463 ASSERT(!overridesItemAfter());
464 while ((currentItem = itemBefore(currentItem))) {
465 ASSERT(currentOffset);
466 currentOffset--;
467 if (currentOffset == offset) {
468 setItemCache(currentItem, currentOffset);
469 return currentItem;
470 }
471 }
472 ASSERT_NOT_REACHED();
473 return 0;
474 }
475
476 if (isLiveNodeListType(type()))
477 currentItem = static_cast<const LiveNodeList*>(this)->traverseForwardToO ffset(offset, *currentItem, currentOffset, root);
478 else
479 currentItem = static_cast<const HTMLCollection*>(this)->traverseForwardT oOffset(offset, toElement(*currentItem), currentOffset, root);
480
481 if (!currentItem) {
482 // Did not find the item. On plus side, we now know the length.
483 setLengthCache(currentOffset + 1);
484 return 0;
485 }
486 setItemCache(currentItem, currentOffset);
487 return currentItem;
488 }
489
490 Element* HTMLCollection::virtualItemAfter(Element*) const 390 Element* HTMLCollection::virtualItemAfter(Element*) const
491 { 391 {
492 ASSERT_NOT_REACHED(); 392 ASSERT_NOT_REACHED();
493 return 0; 393 return 0;
494 } 394 }
495 395
496 static inline bool nameShouldBeVisibleInDocumentAll(const HTMLElement& element) 396 static inline bool nameShouldBeVisibleInDocumentAll(const HTMLElement& element)
497 { 397 {
498 // The document.all collection returns only certain types of elements by nam e, 398 // The document.all collection returns only certain types of elements by nam e,
499 // although it returns any type of element by id. 399 // although it returns any type of element by id.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
531 431
532 inline Element* nextMatchingChildElement(const HTMLCollection& nodeList, Element & current, const ContainerNode& root) 432 inline Element* nextMatchingChildElement(const HTMLCollection& nodeList, Element & current, const ContainerNode& root)
533 { 433 {
534 Element* next = &current; 434 Element* next = &current;
535 do { 435 do {
536 next = ElementTraversal::nextSkippingChildren(*next, &root); 436 next = ElementTraversal::nextSkippingChildren(*next, &root);
537 } while (next && !isMatchingElement(nodeList, *next)); 437 } while (next && !isMatchingElement(nodeList, *next));
538 return next; 438 return next;
539 } 439 }
540 440
541 inline Element* HTMLCollection::traverseToFirstElement(const ContainerNode& root ) const 441 Element* HTMLCollection::traverseToFirstElement(const ContainerNode& root) const
542 { 442 {
543 if (overridesItemAfter()) 443 if (overridesItemAfter())
544 return virtualItemAfter(0); 444 return virtualItemAfter(0);
545 if (shouldOnlyIncludeDirectChildren()) 445 if (shouldOnlyIncludeDirectChildren())
546 return firstMatchingChildElement(*this, root); 446 return firstMatchingChildElement(*this, root);
547 return firstMatchingElement(*this, root); 447 return firstMatchingElement(*this, root);
548 } 448 }
549 449
550 inline Element* HTMLCollection::traverseNextElement(Element& previous, const Con tainerNode& root) const 450 inline Element* HTMLCollection::traverseNextElement(Element& previous, const Con tainerNode& root) const
551 { 451 {
552 if (overridesItemAfter()) 452 if (overridesItemAfter())
553 return virtualItemAfter(&previous); 453 return virtualItemAfter(&previous);
554 if (shouldOnlyIncludeDirectChildren()) 454 if (shouldOnlyIncludeDirectChildren())
555 return nextMatchingChildElement(*this, previous, root); 455 return nextMatchingChildElement(*this, previous, root);
556 return nextMatchingElement(*this, previous, root); 456 return nextMatchingElement(*this, previous, root);
557 } 457 }
558 458
559 inline Element* HTMLCollection::traverseForwardToOffset(unsigned offset, Element & currentElement, unsigned& currentOffset, const ContainerNode& root) const 459 Element* HTMLCollection::traverseForwardToOffset(unsigned offset, Node& currentE lement, unsigned& currentOffset, const ContainerNode& root) const
560 { 460 {
561 ASSERT(currentOffset < offset); 461 ASSERT(currentOffset < offset);
562 if (overridesItemAfter()) { 462 if (overridesItemAfter()) {
563 Element* next = &currentElement; 463 Element* next = &toElement(currentElement);
564 while ((next = virtualItemAfter(next))) { 464 while ((next = virtualItemAfter(next))) {
565 if (++currentOffset == offset) 465 if (++currentOffset == offset)
566 return next; 466 return next;
567 } 467 }
568 return 0; 468 return 0;
569 } 469 }
570 if (shouldOnlyIncludeDirectChildren()) { 470 if (shouldOnlyIncludeDirectChildren()) {
571 Element* next = &currentElement; 471 Element* next = &toElement(currentElement);
572 while ((next = nextMatchingChildElement(*this, *next, root))) { 472 while ((next = nextMatchingChildElement(*this, *next, root))) {
573 if (++currentOffset == offset) 473 if (++currentOffset == offset)
574 return next; 474 return next;
575 } 475 }
576 return 0; 476 return 0;
577 } 477 }
578 return traverseMatchingElementsForwardToOffset(*this, offset, currentElement , currentOffset, root); 478 return traverseMatchingElementsForwardToOffset(*this, offset, toElement(curr entElement), currentOffset, root);
579 } 479 }
580 480
581 Element* HTMLCollection::namedItem(const AtomicString& name) const 481 Element* HTMLCollection::namedItem(const AtomicString& name) const
582 { 482 {
583 // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/namedit em.asp 483 // http://msdn.microsoft.com/workshop/author/dhtml/reference/methods/namedit em.asp
584 // This method first searches for an object with a matching id 484 // This method first searches for an object with a matching id
585 // attribute. If a match is not found, the method then searches for an 485 // attribute. If a match is not found, the method then searches for an
586 // object with a matching name attribute, but only on those elements 486 // object with a matching name attribute, but only on those elements
587 // that are allowed a name attribute. 487 // that are allowed a name attribute.
588 488
589 ContainerNode& root = rootNode(); 489 ContainerNode& root = rootNode();
590 unsigned i = 0; 490 unsigned i = 0;
591 for (Element* element = traverseToFirstElement(root); element; element = tra verseNextElement(*element, root)) { 491 for (Element* element = traverseToFirstElement(root); element; element = tra verseNextElement(*element, root)) {
592 if (checkForNameMatch(*element, /* checkName */ false, name)) { 492 if (checkForNameMatch(*element, /* checkName */ false, name)) {
593 setItemCache(element, i); 493 m_collectionIndexCache.setCachedNode(element, i);
594 return element; 494 return element;
595 } 495 }
596 i++; 496 i++;
597 } 497 }
598 498
599 i = 0; 499 i = 0;
600 for (Element* element = traverseToFirstElement(root); element; element = tra verseNextElement(*element, root)) { 500 for (Element* element = traverseToFirstElement(root); element; element = tra verseNextElement(*element, root)) {
601 if (checkForNameMatch(*element, /* checkName */ true, name)) { 501 if (checkForNameMatch(*element, /* checkName */ true, name)) {
602 setItemCache(element, i); 502 m_collectionIndexCache.setCachedNode(element, i);
603 return element; 503 return element;
604 } 504 }
605 i++; 505 i++;
606 } 506 }
607 507
608 return 0; 508 return 0;
609 } 509 }
610 510
611 void HTMLCollection::updateNameCache() const 511 void HTMLCollection::updateNameCache() const
612 { 512 {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
648 548
649 void HTMLCollection::append(NodeCacheMap& map, const AtomicString& key, Element* element) 549 void HTMLCollection::append(NodeCacheMap& map, const AtomicString& key, Element* element)
650 { 550 {
651 OwnPtr<Vector<Element*> >& vector = map.add(key.impl(), nullptr).iterator->v alue; 551 OwnPtr<Vector<Element*> >& vector = map.add(key.impl(), nullptr).iterator->v alue;
652 if (!vector) 552 if (!vector)
653 vector = adoptPtr(new Vector<Element*>); 553 vector = adoptPtr(new Vector<Element*>);
654 vector->append(element); 554 vector->append(element);
655 } 555 }
656 556
657 } // namespace WebCore 557 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/core/html/HTMLCollection.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698