Home | History | Annotate | Download | only in history
      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 
     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 
     18 TopSitesCache::CanonicalURLQuery::~CanonicalURLQuery() {
     19 }
     20 
     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 
     29 TopSitesCache::~TopSitesCache() {
     30 }
     31 
     32 void TopSitesCache::SetTopSites(const MostVisitedURLList& top_sites) {
     33   top_sites_ = top_sites;
     34   CountForcedURLs();
     35   GenerateCanonicalURLs();
     36 }
     37 
     38 void TopSitesCache::SetThumbnails(const URLToImagesMap& images) {
     39   images_ = images;
     40 }
     41 
     42 Images* TopSitesCache::GetImage(const GURL& url) {
     43   return &images_[GetCanonicalURL(url)];
     44 }
     45 
     46 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 
     61 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 
     72 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 
     77 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 
    114 bool TopSitesCache::IsKnownURL(const GURL& url) const {
    115   return GetCanonicalURLsIterator(url) != canonical_urls_.end();
    116 }
    117 
    118 size_t TopSitesCache::GetURLIndex(const GURL& url) const {
    119   DCHECK(IsKnownURL(url));
    120   return GetCanonicalURLsIterator(url)->second;
    121 }
    122 
    123 size_t TopSitesCache::GetNumNonForcedURLs() const {
    124   return top_sites_.size() - num_forced_urls_;
    125 }
    126 
    127 size_t TopSitesCache::GetNumForcedURLs() const {
    128   return num_forced_urls_;
    129 }
    130 
    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 
    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 
    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
    172     TopSitesCache::GetCanonicalURLsIterator(const GURL& url) const {
    173   return canonical_urls_.find(CanonicalURLQuery(url).entry());
    174 }
    175 
    176 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