| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/history/top_sites.h" | 5 #include "chrome/browser/history/top_sites.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <set> | 8 #include <set> |
| 9 | 9 |
| 10 #include "app/l10n_util.h" | 10 #include "app/l10n_util.h" |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 #include "gfx/codec/jpeg_codec.h" | 32 #include "gfx/codec/jpeg_codec.h" |
| 33 #include "grit/chromium_strings.h" | 33 #include "grit/chromium_strings.h" |
| 34 #include "grit/generated_resources.h" | 34 #include "grit/generated_resources.h" |
| 35 #include "grit/locale_settings.h" | 35 #include "grit/locale_settings.h" |
| 36 #include "third_party/skia/include/core/SkBitmap.h" | 36 #include "third_party/skia/include/core/SkBitmap.h" |
| 37 | 37 |
| 38 namespace history { | 38 namespace history { |
| 39 | 39 |
| 40 // How many top sites to store in the cache. | 40 // How many top sites to store in the cache. |
| 41 static const size_t kTopSitesNumber = 20; | 41 static const size_t kTopSitesNumber = 20; |
| 42 |
| 43 // Max number of temporary images we'll cache. See comment above |
| 44 // temp_images_ for details. |
| 45 static const size_t kMaxTempTopImages = 8; |
| 46 |
| 42 static const size_t kTopSitesShown = 8; | 47 static const size_t kTopSitesShown = 8; |
| 43 static const int kDaysOfHistory = 90; | 48 static const int kDaysOfHistory = 90; |
| 44 // Time from startup to first HistoryService query. | 49 // Time from startup to first HistoryService query. |
| 45 static const int64 kUpdateIntervalSecs = 15; | 50 static const int64 kUpdateIntervalSecs = 15; |
| 46 // Intervals between requests to HistoryService. | 51 // Intervals between requests to HistoryService. |
| 47 static const int64 kMinUpdateIntervalMinutes = 1; | 52 static const int64 kMinUpdateIntervalMinutes = 1; |
| 48 static const int64 kMaxUpdateIntervalMinutes = 60; | 53 static const int64 kMaxUpdateIntervalMinutes = 60; |
| 49 | 54 |
| 50 // IDs of the sites we force into top sites. | 55 // IDs of the sites we force into top sites. |
| 51 static const int kPrepopulatePageIDs[] = | 56 static const int kPrepopulatePageIDs[] = |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 193 } | 198 } |
| 194 | 199 |
| 195 if (!HistoryService::CanAddURL(url)) | 200 if (!HistoryService::CanAddURL(url)) |
| 196 return false; // It's not a real webpage. | 201 return false; // It's not a real webpage. |
| 197 | 202 |
| 198 scoped_refptr<RefCountedBytes> thumbnail_data; | 203 scoped_refptr<RefCountedBytes> thumbnail_data; |
| 199 if (!EncodeBitmap(thumbnail, &thumbnail_data)) | 204 if (!EncodeBitmap(thumbnail, &thumbnail_data)) |
| 200 return false; | 205 return false; |
| 201 | 206 |
| 202 if (add_temp_thumbnail) { | 207 if (add_temp_thumbnail) { |
| 208 // Always remove the existing entry and then add it back. That way if we end |
| 209 // up with too many temp thumbnails we'll prune the oldest first. |
| 210 RemoveTemporaryThumbnailByURL(url); |
| 203 AddTemporaryThumbnail(url, thumbnail_data, score); | 211 AddTemporaryThumbnail(url, thumbnail_data, score); |
| 204 return true; | 212 return true; |
| 205 } | 213 } |
| 206 | 214 |
| 207 return SetPageThumbnailEncoded(url, thumbnail_data, score); | 215 return SetPageThumbnailEncoded(url, thumbnail_data, score); |
| 208 } | 216 } |
| 209 | 217 |
| 210 void TopSites::GetMostVisitedURLs(CancelableRequestConsumer* consumer, | 218 void TopSites::GetMostVisitedURLs(CancelableRequestConsumer* consumer, |
| 211 GetTopSitesCallback* callback) { | 219 GetTopSitesCallback* callback) { |
| 212 // WARNING: this may be invoked on any thread. | 220 // WARNING: this may be invoked on any thread. |
| (...skipping 267 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 480 index, | 488 index, |
| 481 *(cache_->GetImage(most_visited.url))); | 489 *(cache_->GetImage(most_visited.url))); |
| 482 return true; | 490 return true; |
| 483 } | 491 } |
| 484 | 492 |
| 485 // static | 493 // static |
| 486 bool TopSites::EncodeBitmap(const SkBitmap& bitmap, | 494 bool TopSites::EncodeBitmap(const SkBitmap& bitmap, |
| 487 scoped_refptr<RefCountedBytes>* bytes) { | 495 scoped_refptr<RefCountedBytes>* bytes) { |
| 488 *bytes = new RefCountedBytes(); | 496 *bytes = new RefCountedBytes(); |
| 489 SkAutoLockPixels bitmap_lock(bitmap); | 497 SkAutoLockPixels bitmap_lock(bitmap); |
| 490 return gfx::JPEGCodec::Encode( | 498 std::vector<unsigned char> data; |
| 491 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)), | 499 if (!gfx::JPEGCodec::Encode( |
| 492 gfx::JPEGCodec::FORMAT_BGRA, bitmap.width(), | 500 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)), |
| 493 bitmap.height(), | 501 gfx::JPEGCodec::FORMAT_BGRA, bitmap.width(), |
| 494 static_cast<int>(bitmap.rowBytes()), 90, | 502 bitmap.height(), |
| 495 &((*bytes)->data)); | 503 static_cast<int>(bitmap.rowBytes()), 90, |
| 504 &data)) { |
| 505 return false; |
| 506 } |
| 507 // As we're going to cache this data, make sure the vector is only as big as |
| 508 // it needs to be. |
| 509 (*bytes)->data = data; |
| 510 return true; |
| 511 } |
| 512 |
| 513 void TopSites::RemoveTemporaryThumbnailByURL(const GURL& url) { |
| 514 for (TempImages::iterator i = temp_images_.begin(); i != temp_images_.end(); |
| 515 ++i) { |
| 516 if (i->first == url) { |
| 517 temp_images_.erase(i); |
| 518 return; |
| 519 } |
| 520 } |
| 496 } | 521 } |
| 497 | 522 |
| 498 void TopSites::AddTemporaryThumbnail(const GURL& url, | 523 void TopSites::AddTemporaryThumbnail(const GURL& url, |
| 499 const RefCountedBytes* thumbnail, | 524 const RefCountedBytes* thumbnail, |
| 500 const ThumbnailScore& score) { | 525 const ThumbnailScore& score) { |
| 501 Images& img = temp_thumbnails_map_[url]; | 526 if (temp_images_.size() == kMaxTempTopImages) |
| 502 img.thumbnail = const_cast<RefCountedBytes*>(thumbnail); | 527 temp_images_.erase(temp_images_.begin()); |
| 503 img.thumbnail_score = score; | 528 |
| 529 TempImage image; |
| 530 image.first = url; |
| 531 image.second.thumbnail = const_cast<RefCountedBytes*>(thumbnail); |
| 532 image.second.thumbnail_score = score; |
| 533 temp_images_.push_back(image); |
| 504 } | 534 } |
| 505 | 535 |
| 506 void TopSites::StartQueryForMostVisited() { | 536 void TopSites::StartQueryForMostVisited() { |
| 507 if (!profile_) | 537 if (!profile_) |
| 508 return; | 538 return; |
| 509 | 539 |
| 510 HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); | 540 HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); |
| 511 // |hs| may be null during unit tests. | 541 // |hs| may be null during unit tests. |
| 512 if (hs) { | 542 if (hs) { |
| 513 hs->QueryMostVisitedURLs( | 543 hs->QueryMostVisitedURLs( |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 696 } | 726 } |
| 697 StartQueryForMostVisited(); | 727 StartQueryForMostVisited(); |
| 698 } else if (type == NotificationType::NAV_ENTRY_COMMITTED) { | 728 } else if (type == NotificationType::NAV_ENTRY_COMMITTED) { |
| 699 if (cache_->top_sites().size() < kTopSitesNumber) { | 729 if (cache_->top_sites().size() < kTopSitesNumber) { |
| 700 NavigationController::LoadCommittedDetails* load_details = | 730 NavigationController::LoadCommittedDetails* load_details = |
| 701 Details<NavigationController::LoadCommittedDetails>(details).ptr(); | 731 Details<NavigationController::LoadCommittedDetails>(details).ptr(); |
| 702 if (!load_details) | 732 if (!load_details) |
| 703 return; | 733 return; |
| 704 const GURL& url = load_details->entry->url(); | 734 const GURL& url = load_details->entry->url(); |
| 705 if (!cache_->IsKnownURL(url) && HistoryService::CanAddURL(url)) { | 735 if (!cache_->IsKnownURL(url) && HistoryService::CanAddURL(url)) { |
| 706 // Ideally we would just invoke StartQueryForMostVisited, but at the | 736 // To avoid slamming history we throttle requests when the url updates. |
| 707 // time this is invoked history hasn't been updated, which means if we | 737 // To do otherwise negatively impacts perf tests. |
| 708 // invoked StartQueryForMostVisited now we could get stale data. | 738 RestartQueryForTopSitesTimer(GetUpdateDelay()); |
| 709 RestartQueryForTopSitesTimer(base::TimeDelta::FromMilliseconds(1)); | |
| 710 } | 739 } |
| 711 } | 740 } |
| 712 } | 741 } |
| 713 } | 742 } |
| 714 | 743 |
| 715 void TopSites::SetTopSites(const MostVisitedURLList& new_top_sites) { | 744 void TopSites::SetTopSites(const MostVisitedURLList& new_top_sites) { |
| 716 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 745 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 717 | 746 |
| 718 MostVisitedURLList top_sites(new_top_sites); | 747 MostVisitedURLList top_sites(new_top_sites); |
| 719 AddPrepopulatedPages(&top_sites); | 748 AddPrepopulatedPages(&top_sites); |
| 720 | 749 |
| 721 TopSitesDelta delta; | 750 TopSitesDelta delta; |
| 722 DiffMostVisited(cache_->top_sites(), top_sites, &delta); | 751 DiffMostVisited(cache_->top_sites(), top_sites, &delta); |
| 723 if (!delta.deleted.empty() || !delta.added.empty() || !delta.moved.empty()) | 752 if (!delta.deleted.empty() || !delta.added.empty() || !delta.moved.empty()) |
| 724 backend_->UpdateTopSites(delta); | 753 backend_->UpdateTopSites(delta); |
| 725 | 754 |
| 726 last_num_urls_changed_ = delta.added.size() + delta.moved.size(); | 755 last_num_urls_changed_ = delta.added.size() + delta.moved.size(); |
| 727 | 756 |
| 728 // We always do the following steps (setting top sites in cache, and resetting | 757 // We always do the following steps (setting top sites in cache, and resetting |
| 729 // thread safe cache ...) as this method is invoked during startup at which | 758 // thread safe cache ...) as this method is invoked during startup at which |
| 730 // point the caches haven't been updated yet. | 759 // point the caches haven't been updated yet. |
| 731 cache_->SetTopSites(top_sites); | 760 cache_->SetTopSites(top_sites); |
| 732 | 761 |
| 733 // See if we have any tmp thumbnails for the new sites. | 762 // See if we have any tmp thumbnails for the new sites. |
| 734 if (!temp_thumbnails_map_.empty()) { | 763 if (!temp_images_.empty()) { |
| 735 for (size_t i = 0; i < top_sites.size(); ++i) { | 764 for (size_t i = 0; i < top_sites.size(); ++i) { |
| 736 const MostVisitedURL& mv = top_sites[i]; | 765 const MostVisitedURL& mv = top_sites[i]; |
| 737 GURL canonical_url = cache_->GetCanonicalURL(mv.url); | 766 GURL canonical_url = cache_->GetCanonicalURL(mv.url); |
| 738 for (std::map<GURL, Images>::iterator it = temp_thumbnails_map_.begin(); | 767 // At the time we get the thumbnail redirects aren't known, so we have to |
| 739 it != temp_thumbnails_map_.end(); ++it) { | 768 // iterate through all the images. |
| 740 // Must map all temp URLs to canonical ones. | 769 for (TempImages::iterator it = temp_images_.begin(); |
| 741 // temp_thumbnails_map_ contains non-canonical URLs, because | 770 it != temp_images_.end(); ++it) { |
| 742 // when we add a temp thumbnail, redirect chain is not known. | |
| 743 // This is slow, but temp_thumbnails_map_ should have very few URLs. | |
| 744 if (canonical_url == cache_->GetCanonicalURL(it->first)) { | 771 if (canonical_url == cache_->GetCanonicalURL(it->first)) { |
| 745 SetPageThumbnailEncoded(mv.url, | 772 SetPageThumbnailEncoded(mv.url, |
| 746 it->second.thumbnail, | 773 it->second.thumbnail, |
| 747 it->second.thumbnail_score); | 774 it->second.thumbnail_score); |
| 748 temp_thumbnails_map_.erase(it); | 775 temp_images_.erase(it); |
| 749 break; | 776 break; |
| 750 } | 777 } |
| 751 } | 778 } |
| 752 } | 779 } |
| 753 } | 780 } |
| 754 | 781 |
| 755 if (top_sites.size() >= kTopSitesNumber) | 782 if (top_sites.size() >= kTopSitesNumber) |
| 756 temp_thumbnails_map_.clear(); | 783 temp_images_.clear(); |
| 757 | 784 |
| 758 ResetThreadSafeCache(); | 785 ResetThreadSafeCache(); |
| 759 ResetThreadSafeImageCache(); | 786 ResetThreadSafeImageCache(); |
| 760 | 787 |
| 761 // Restart the timer that queries history for top sites. This is done to | 788 // Restart the timer that queries history for top sites. This is done to |
| 762 // ensure we stay in sync with history. | 789 // ensure we stay in sync with history. |
| 763 RestartQueryForTopSitesTimer(GetUpdateDelay()); | 790 RestartQueryForTopSitesTimer(GetUpdateDelay()); |
| 764 } | 791 } |
| 765 | 792 |
| 766 int TopSites::num_results_to_request_from_history() const { | 793 int TopSites::num_results_to_request_from_history() const { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 803 thread_safe_cache_->SetTopSites(cached); | 830 thread_safe_cache_->SetTopSites(cached); |
| 804 } | 831 } |
| 805 | 832 |
| 806 void TopSites::ResetThreadSafeImageCache() { | 833 void TopSites::ResetThreadSafeImageCache() { |
| 807 AutoLock lock(lock_); | 834 AutoLock lock(lock_); |
| 808 thread_safe_cache_->SetThumbnails(cache_->images()); | 835 thread_safe_cache_->SetThumbnails(cache_->images()); |
| 809 thread_safe_cache_->RemoveUnreferencedThumbnails(); | 836 thread_safe_cache_->RemoveUnreferencedThumbnails(); |
| 810 } | 837 } |
| 811 | 838 |
| 812 void TopSites::RestartQueryForTopSitesTimer(base::TimeDelta delta) { | 839 void TopSites::RestartQueryForTopSitesTimer(base::TimeDelta delta) { |
| 840 if (timer_.IsRunning() && ((timer_start_time_ + timer_.GetCurrentDelay()) < |
| 841 (base::TimeTicks::Now() + delta))) { |
| 842 return; |
| 843 } |
| 844 |
| 845 timer_start_time_ = base::TimeTicks::Now(); |
| 813 timer_.Stop(); | 846 timer_.Stop(); |
| 814 timer_.Start(delta, this, &TopSites::StartQueryForMostVisited); | 847 timer_.Start(delta, this, &TopSites::StartQueryForMostVisited); |
| 815 } | 848 } |
| 816 | 849 |
| 817 void TopSites::OnHistoryMigrationWrittenToDisk(TopSitesBackend::Handle handle) { | 850 void TopSites::OnHistoryMigrationWrittenToDisk(TopSitesBackend::Handle handle) { |
| 818 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 851 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 819 | 852 |
| 820 if (!profile_) | 853 if (!profile_) |
| 821 return; | 854 return; |
| 822 | 855 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 851 base::TimeDelta::FromSeconds(kUpdateIntervalSecs)); | 884 base::TimeDelta::FromSeconds(kUpdateIntervalSecs)); |
| 852 } else { | 885 } else { |
| 853 // The top sites file didn't exist or is the wrong version. We need to wait | 886 // The top sites file didn't exist or is the wrong version. We need to wait |
| 854 // for history to finish loading to know if we really needed to migrate. | 887 // for history to finish loading to know if we really needed to migrate. |
| 855 if (history_state_ == HISTORY_LOADED) { | 888 if (history_state_ == HISTORY_LOADED) { |
| 856 top_sites_state_ = TOP_SITES_LOADED; | 889 top_sites_state_ = TOP_SITES_LOADED; |
| 857 SetTopSites(MostVisitedURLList()); | 890 SetTopSites(MostVisitedURLList()); |
| 858 MoveStateToLoaded(); | 891 MoveStateToLoaded(); |
| 859 } else { | 892 } else { |
| 860 top_sites_state_ = TOP_SITES_LOADED_WAITING_FOR_HISTORY; | 893 top_sites_state_ = TOP_SITES_LOADED_WAITING_FOR_HISTORY; |
| 861 // Ask for history just in case it hasn't been load yet. When history | 894 // Ask for history just in case it hasn't been loaded yet. When history |
| 862 // finishes loading we'll do migration and/or move to loaded. | 895 // finishes loading we'll do migration and/or move to loaded. |
| 863 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); | 896 profile_->GetHistoryService(Profile::EXPLICIT_ACCESS); |
| 864 } | 897 } |
| 865 } | 898 } |
| 866 } | 899 } |
| 867 | 900 |
| 868 void TopSites::OnTopSitesAvailableFromHistory( | 901 void TopSites::OnTopSitesAvailableFromHistory( |
| 869 CancelableRequestProvider::Handle handle, | 902 CancelableRequestProvider::Handle handle, |
| 870 MostVisitedURLList pages) { | 903 MostVisitedURLList pages) { |
| 871 SetTopSites(pages); | 904 SetTopSites(pages); |
| 872 } | 905 } |
| 873 | 906 |
| 874 } // namespace history | 907 } // namespace history |
| OLD | NEW |