• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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