1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/history/top_sites_cache.h"
6
7 #include "base/logging.h"
8 #include "base/memory/ref_counted_memory.h"
9
10 namespace history {
11
CanonicalURLQuery(const GURL & url)12 TopSitesCache::CanonicalURLQuery::CanonicalURLQuery(const GURL& url) {
13 most_visited_url_.redirects.push_back(url);
14 entry_.first = &most_visited_url_;
15 entry_.second = 0u;
16 }
17
~CanonicalURLQuery()18 TopSitesCache::CanonicalURLQuery::~CanonicalURLQuery() {
19 }
20
TopSitesCache()21 TopSitesCache::TopSitesCache() {
22 clear_query_ref_.ClearQuery();
23 clear_query_ref_.ClearRef();
24 clear_path_query_ref_.ClearQuery();
25 clear_path_query_ref_.ClearRef();
26 clear_path_query_ref_.ClearPath();
27 }
28
~TopSitesCache()29 TopSitesCache::~TopSitesCache() {
30 }
31
SetTopSites(const MostVisitedURLList & top_sites)32 void TopSitesCache::SetTopSites(const MostVisitedURLList& top_sites) {
33 top_sites_ = top_sites;
34 CountForcedURLs();
35 GenerateCanonicalURLs();
36 }
37
SetThumbnails(const URLToImagesMap & images)38 void TopSitesCache::SetThumbnails(const URLToImagesMap& images) {
39 images_ = images;
40 }
41
GetImage(const GURL & url)42 Images* TopSitesCache::GetImage(const GURL& url) {
43 return &images_[GetCanonicalURL(url)];
44 }
45
GetPageThumbnail(const GURL & url,scoped_refptr<base::RefCountedMemory> * bytes) const46 bool TopSitesCache::GetPageThumbnail(
47 const GURL& url,
48 scoped_refptr<base::RefCountedMemory>* bytes) const {
49 std::map<GURL, Images>::const_iterator found =
50 images_.find(GetCanonicalURL(url));
51 if (found != images_.end()) {
52 base::RefCountedMemory* data = found->second.thumbnail.get();
53 if (data) {
54 *bytes = data;
55 return true;
56 }
57 }
58 return false;
59 }
60
GetPageThumbnailScore(const GURL & url,ThumbnailScore * score) const61 bool TopSitesCache::GetPageThumbnailScore(const GURL& url,
62 ThumbnailScore* score) const {
63 std::map<GURL, Images>::const_iterator found =
64 images_.find(GetCanonicalURL(url));
65 if (found != images_.end()) {
66 *score = found->second.thumbnail_score;
67 return true;
68 }
69 return false;
70 }
71
GetCanonicalURL(const GURL & url) const72 const GURL& TopSitesCache::GetCanonicalURL(const GURL& url) const {
73 CanonicalURLs::const_iterator it = GetCanonicalURLsIterator(url);
74 return it == canonical_urls_.end() ? url : it->first.first->url;
75 }
76
GetGeneralizedCanonicalURL(const GURL & url) const77 GURL TopSitesCache::GetGeneralizedCanonicalURL(const GURL& url) const {
78 CanonicalURLs::const_iterator it_hi =
79 canonical_urls_.lower_bound(CanonicalURLQuery(url).entry());
80 if (it_hi != canonical_urls_.end()) {
81 // Test match ignoring "?query#ref". This also handles exact match.
82 if (url.ReplaceComponents(clear_query_ref_) ==
83 GetURLFromIterator(it_hi).ReplaceComponents(clear_query_ref_)) {
84 return it_hi->first.first->url;
85 }
86 }
87 // Everything on or after |it_hi| is irrelevant.
88
89 GURL base_url(url.ReplaceComponents(clear_path_query_ref_));
90 CanonicalURLs::const_iterator it_lo =
91 canonical_urls_.lower_bound(CanonicalURLQuery(base_url).entry());
92 if (it_lo == canonical_urls_.end())
93 return GURL::EmptyGURL();
94 GURL compare_url_lo(GetURLFromIterator(it_lo));
95 if (!HaveSameSchemeHostAndPort(base_url, compare_url_lo) ||
96 !IsPathPrefix(base_url.path(), compare_url_lo.path())) {
97 return GURL::EmptyGURL();
98 }
99 // Everything before |it_lo| is irrelevant.
100
101 // Search in [|it_lo|, |it_hi|) in reversed order. The first URL found that's
102 // a prefix of |url| (ignoring "?query#ref") would be returned.
103 for (CanonicalURLs::const_iterator it = it_hi; it != it_lo;) {
104 --it;
105 GURL compare_url(GetURLFromIterator(it));
106 DCHECK(HaveSameSchemeHostAndPort(compare_url, url));
107 if (IsPathPrefix(compare_url.path(), url.path()))
108 return it->first.first->url;
109 }
110
111 return GURL::EmptyGURL();
112 }
113
IsKnownURL(const GURL & url) const114 bool TopSitesCache::IsKnownURL(const GURL& url) const {
115 return GetCanonicalURLsIterator(url) != canonical_urls_.end();
116 }
117
GetURLIndex(const GURL & url) const118 size_t TopSitesCache::GetURLIndex(const GURL& url) const {
119 DCHECK(IsKnownURL(url));
120 return GetCanonicalURLsIterator(url)->second;
121 }
122
GetNumNonForcedURLs() const123 size_t TopSitesCache::GetNumNonForcedURLs() const {
124 return top_sites_.size() - num_forced_urls_;
125 }
126
GetNumForcedURLs() const127 size_t TopSitesCache::GetNumForcedURLs() const {
128 return num_forced_urls_;
129 }
130
CountForcedURLs()131 void TopSitesCache::CountForcedURLs() {
132 num_forced_urls_ = 0;
133 while (num_forced_urls_ < top_sites_.size()) {
134 // Forced sites are all at the beginning.
135 if (top_sites_[num_forced_urls_].last_forced_time.is_null())
136 break;
137 num_forced_urls_++;
138 }
139 #if DCHECK_IS_ON
140 // In debug, ensure the cache user has no forced URLs pass that point.
141 for (size_t i = num_forced_urls_; i < top_sites_.size(); ++i) {
142 DCHECK(top_sites_[i].last_forced_time.is_null())
143 << "All the forced URLs must appear before non-forced URLs.";
144 }
145 #endif
146 }
147
GenerateCanonicalURLs()148 void TopSitesCache::GenerateCanonicalURLs() {
149 canonical_urls_.clear();
150 for (size_t i = 0; i < top_sites_.size(); i++)
151 StoreRedirectChain(top_sites_[i].redirects, i);
152 }
153
StoreRedirectChain(const RedirectList & redirects,size_t destination)154 void TopSitesCache::StoreRedirectChain(const RedirectList& redirects,
155 size_t destination) {
156 // |redirects| is empty if the user pinned a site and there are not enough top
157 // sites before the pinned site.
158
159 // Map all the redirected URLs to the destination.
160 for (size_t i = 0; i < redirects.size(); i++) {
161 // If this redirect is already known, don't replace it with a new one.
162 if (!IsKnownURL(redirects[i])) {
163 CanonicalURLEntry entry;
164 entry.first = &(top_sites_[destination]);
165 entry.second = i;
166 canonical_urls_[entry] = destination;
167 }
168 }
169 }
170
171 TopSitesCache::CanonicalURLs::const_iterator
GetCanonicalURLsIterator(const GURL & url) const172 TopSitesCache::GetCanonicalURLsIterator(const GURL& url) const {
173 return canonical_urls_.find(CanonicalURLQuery(url).entry());
174 }
175
GetURLFromIterator(CanonicalURLs::const_iterator it) const176 const GURL& TopSitesCache::GetURLFromIterator(
177 CanonicalURLs::const_iterator it) const {
178 DCHECK(it != canonical_urls_.end());
179 return it->first.first->redirects[it->first.second];
180 }
181
182 } // namespace history
183