| Index: chrome/browser/history/top_sites_cache.cc
|
| diff --git a/chrome/browser/history/top_sites_cache.cc b/chrome/browser/history/top_sites_cache.cc
|
| index f94013f0773be2ee3408d859a9fa827ff60cff89..bc31260a3ab4d4acf7a8620a224730fa1d7280d8 100644
|
| --- a/chrome/browser/history/top_sites_cache.cc
|
| +++ b/chrome/browser/history/top_sites_cache.cc
|
| @@ -4,11 +4,43 @@
|
|
|
| #include "chrome/browser/history/top_sites_cache.h"
|
|
|
| +#include <algorithm>
|
| +
|
| #include "base/logging.h"
|
| #include "base/memory/ref_counted_memory.h"
|
|
|
| namespace history {
|
|
|
| +bool CanonicalURLComparator::operator()(const CanonicalURLEntry& e1,
|
| + const CanonicalURLEntry& e2) const {
|
| + return CanonicalURLComparator::CompareString(
|
| + e1.first->redirects[e1.second].spec(),
|
| + e2.first->redirects[e2.second].spec());
|
| +}
|
| +
|
| +// static
|
| +bool CanonicalURLComparator::CompareString(const std::string& s1,
|
| + const std::string& s2) {
|
| + const std::string::value_type* ch1 = s1.c_str();
|
| + const std::string::value_type* ch2 = s2.c_str();
|
| + // Find first difference.
|
| + while (*ch1 && *ch2 && *ch1 == *ch2) {
|
| + ++ch1;
|
| + ++ch2;
|
| + }
|
| + if (!*ch1 || !*ch2) // Identical strings, or one is strict prefix of other.
|
| + return *ch2 != '\0'; // true iff |e1| is strict prefix of |e2|.
|
| +
|
| + // Now |*ch1| != |*ch2|. Compare using order '?' < '/' < other.
|
| + // Table : |*ch2| = '?' : |*ch2| = "/" : |*ch2| = other
|
| + // |*ch1| = '?' : (excluded) : true : true
|
| + // |*ch1| = '/' : false : (excluded) : true
|
| + // |*ch1| = 'other' : false : false : |*ch1| < |*ch2|
|
| + return (*ch1 == '?') || (*ch1 == '/' && *ch2 != '?') ||
|
| + (*ch2 != '?' && *ch2 != '/' && *ch1 < *ch2);
|
| +}
|
| +
|
| +
|
| TopSitesCache::TopSitesCache() {
|
| }
|
|
|
| @@ -43,6 +75,21 @@ bool TopSitesCache::GetPageThumbnail(
|
| return false;
|
| }
|
|
|
| +bool TopSitesCache::GetPageThumbnailForPrefix(
|
| + const GURL& prefix_url,
|
| + scoped_refptr<base::RefCountedMemory>* bytes) {
|
| + std::map<GURL, Images>::const_iterator found =
|
| + images_.find(GetCanonicalURLForPrefix(prefix_url));
|
| + if (found != images_.end()) {
|
| + base::RefCountedMemory* data = found->second.thumbnail.get();
|
| + if (data) {
|
| + *bytes = data;
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| bool TopSitesCache::GetPageThumbnailScore(const GURL& url,
|
| ThumbnailScore* score) {
|
| std::map<GURL, Images>::const_iterator found =
|
| @@ -55,17 +102,51 @@ bool TopSitesCache::GetPageThumbnailScore(const GURL& url,
|
| }
|
|
|
| const GURL& TopSitesCache::GetCanonicalURL(const GURL& url) {
|
| - CanonicalURLs::iterator i = TopSitesCache::GetCanonicalURLsIterator(url);
|
| + CanonicalURLs::iterator i = GetCanonicalURLsIterator(url, false);
|
| + return i == canonical_urls_.end() ? url : i->first.first->url;
|
| +}
|
| +
|
| +const GURL& TopSitesCache::GetCanonicalURLForPrefix(const GURL& url) {
|
| + CanonicalURLs::iterator i = GetCanonicalURLsIterator(url, true);
|
| return i == canonical_urls_.end() ? url : i->first.first->url;
|
| }
|
|
|
| bool TopSitesCache::IsKnownURL(const GURL& url) {
|
| - return GetCanonicalURLsIterator(url) != canonical_urls_.end();
|
| + return GetCanonicalURLsIterator(url, false) != canonical_urls_.end();
|
| }
|
|
|
| size_t TopSitesCache::GetURLIndex(const GURL& url) {
|
| DCHECK(IsKnownURL(url));
|
| - return GetCanonicalURLsIterator(url)->second;
|
| + return GetCanonicalURLsIterator(url, false)->second;
|
| +}
|
| +
|
| +// static
|
| +bool TopSitesCache::UrlIsPrefix(const GURL& url1, const GURL& url2) {
|
| + if (url1.scheme() != url2.scheme() || url1.host() != url2.host() ||
|
| + url1.port() != url2.port()) {
|
| + return false;
|
| + }
|
| + // Only need to compare path now. Note that queries are ignored.
|
| + std::string p1(url1.path());
|
| + std::string p2(url2.path());
|
| + if (p1.length() > p2.length())
|
| + return false;
|
| + std::pair<std::string::iterator, std::string::iterator> first_diff =
|
| + std::mismatch(p1.begin(), p1.end(), p2.begin());
|
| + // Necessary condition: |p1| is a string prefix of |p2|.
|
| + if (first_diff.first != p1.end())
|
| + return false; // E.g.: (|p1| = "/test", |p2| = "/exam") => false.
|
| +
|
| + // |p1| is string prefix.
|
| + if (first_diff.second == p2.end()) // Is exact match?
|
| + return true; // E.g.: ("/test", "/test") => true.
|
| + // |p1| is strict string prefix, check full match of last path component.
|
| + if (!p1.empty() && *p1.rbegin() == '/') // Ends in '/'?
|
| + return true; // E.g.: ("/test/", "/test/stuff") => true.
|
| +
|
| + // Finally, |p1| does not end in "/": check first extra character in |p2|.
|
| + // E.g.: ("/test", "/test/stuff") => true; ("/test", "/testing") => false.
|
| + return *(first_diff.second) == '/';
|
| }
|
|
|
| void TopSitesCache::GenerateCanonicalURLs() {
|
| @@ -76,7 +157,7 @@ void TopSitesCache::GenerateCanonicalURLs() {
|
|
|
| void TopSitesCache::StoreRedirectChain(const RedirectList& redirects,
|
| size_t destination) {
|
| - // redirects is empty if the user pinned a site and there are not enough top
|
| + // |redirects| is empty if the user pinned a site and there are not enough top
|
| // sites before the pinned site.
|
|
|
| // Map all the redirected URLs to the destination.
|
| @@ -92,13 +173,22 @@ void TopSitesCache::StoreRedirectChain(const RedirectList& redirects,
|
| }
|
|
|
| TopSitesCache::CanonicalURLs::iterator TopSitesCache::GetCanonicalURLsIterator(
|
| - const GURL& url) {
|
| + const GURL& url, bool match_prefix) {
|
| MostVisitedURL most_visited_url;
|
| most_visited_url.redirects.push_back(url);
|
| CanonicalURLEntry entry;
|
| entry.first = &most_visited_url;
|
| entry.second = 0u;
|
| - return canonical_urls_.find(entry);
|
| + if (!match_prefix)
|
| + return canonical_urls_.find(entry);
|
| +
|
| + TopSitesCache::CanonicalURLs::iterator best_it =
|
| + canonical_urls_.lower_bound(entry);
|
| + if (best_it == canonical_urls_.end())
|
| + return best_it;
|
| +
|
| + const GURL& comp_url = best_it->first.first->redirects[best_it->first.second];
|
| + return UrlIsPrefix(url, comp_url) ? best_it : canonical_urls_.end();
|
| }
|
|
|
| } // namespace history
|
|
|