diff options
author | nshkrob@chromium.org <nshkrob@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-24 23:24:17 +0000 |
---|---|---|
committer | nshkrob@chromium.org <nshkrob@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-05-24 23:24:17 +0000 |
commit | 5601f989e08815929e184d04fb720956d07e76cd (patch) | |
tree | be05175a4791fe7be4297487c1f4a5f6180f27e9 /chrome/browser/history | |
parent | eacf8143f91d374403508bb95fea1a0761dc9027 (diff) | |
download | chromium_src-5601f989e08815929e184d04fb720956d07e76cd.zip chromium_src-5601f989e08815929e184d04fb720956d07e76cd.tar.gz chromium_src-5601f989e08815929e184d04fb720956d07e76cd.tar.bz2 |
Adding a mock database layer.
Testing support of storage in TopSites.
BUG=None
TEST=TopSitesTest
Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=48061
Review URL: http://codereview.chromium.org/2133011
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@48099 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/history')
-rw-r--r-- | chrome/browser/history/history_types.h | 4 | ||||
-rw-r--r-- | chrome/browser/history/top_sites.cc | 85 | ||||
-rw-r--r-- | chrome/browser/history/top_sites.h | 31 | ||||
-rw-r--r-- | chrome/browser/history/top_sites_database.h | 55 | ||||
-rw-r--r-- | chrome/browser/history/top_sites_unittest.cc | 123 |
5 files changed, 270 insertions, 28 deletions
diff --git a/chrome/browser/history/history_types.h b/chrome/browser/history/history_types.h index c3fb5c6..9161ba1 100644 --- a/chrome/browser/history/history_types.h +++ b/chrome/browser/history/history_types.h @@ -518,6 +518,10 @@ struct MostVisitedURL { string16 title; RedirectList redirects; + + bool operator==(const MostVisitedURL& other) { + return url == other.url; + } }; typedef std::vector<MostVisitedURL> MostVisitedURLList; diff --git a/chrome/browser/history/top_sites.cc b/chrome/browser/history/top_sites.cc index fd23865..5bfc4c3 100644 --- a/chrome/browser/history/top_sites.cc +++ b/chrome/browser/history/top_sites.cc @@ -6,6 +6,7 @@ #include "base/logging.h" #include "chrome/browser/profile.h" +#include "chrome/browser/history/top_sites_database.h" #include "chrome/browser/history/page_usage_data.h" #include "gfx/codec/jpeg_codec.h" #include "third_party/skia/include/core/SkBitmap.h" @@ -26,16 +27,52 @@ TopSites::~TopSites() { } void TopSites::Init() { - // TODO(brettw) read the database here. + if (db_.get()) + ReadDatabase(); // Start the one-shot timer. timer_.Start(base::TimeDelta::FromSeconds(kUpdateIntervalSecs), this, &TopSites::StartQueryForMostVisited); } +void TopSites::ReadDatabase() { + DCHECK(db_.get()); + { + AutoLock lock(lock_); + MostVisitedURLList top_urls = db_->GetTopURLs(); + StoreMostVisited(&top_urls); + } // Lock is released here. + + for (size_t i = 0; i < top_sites_.size(); i++) { + MostVisitedURL url = top_sites_[i]; + Images thumbnail; + if (db_->GetPageThumbnail(url, &thumbnail)) { + SetPageThumbnail(url.url, thumbnail.thumbnail, thumbnail.thumbnail_score); + } + } +} + +// Public wrapper that encodes the bitmap into RefCountedBytes. bool TopSites::SetPageThumbnail(const GURL& url, const SkBitmap& thumbnail, const ThumbnailScore& score) { + RefCountedBytes* thumbnail_data = new RefCountedBytes; + SkAutoLockPixels thumbnail_lock(thumbnail); + bool encoded = gfx::JPEGCodec::Encode( + reinterpret_cast<unsigned char*>(thumbnail.getAddr32(0, 0)), + gfx::JPEGCodec::FORMAT_BGRA, thumbnail.width(), + thumbnail.height(), + static_cast<int>(thumbnail.rowBytes()), 90, + &thumbnail_data->data); + if (!encoded) + return false; + return SetPageThumbnail(url, thumbnail_data, score); +} + +// private +bool TopSites::SetPageThumbnail(const GURL& url, + const RefCountedBytes* thumbnail_data, + const ThumbnailScore& score) { AutoLock lock(lock_); std::map<GURL, size_t>::iterator found = canonical_urls_.find(url); @@ -55,16 +92,8 @@ bool TopSites::SetPageThumbnail(const GURL& url, new_score_with_redirects)) return false; // The one we already have is better. - image.thumbnail = new RefCountedBytes; - SkAutoLockPixels thumbnail_lock(thumbnail); - bool encoded = gfx::JPEGCodec::Encode( - reinterpret_cast<unsigned char*>(thumbnail.getAddr32(0, 0)), - gfx::JPEGCodec::FORMAT_BGRA, thumbnail.width(), - thumbnail.height(), - static_cast<int>(thumbnail.rowBytes()), 90, - &image.thumbnail->data); - if (!encoded) - return false; + // Take ownership of the thumbnail data. + image.thumbnail = const_cast<RefCountedBytes*>(thumbnail_data); image.thumbnail_score = new_score_with_redirects; return true; @@ -85,27 +114,47 @@ bool TopSites::GetPageThumbnail(const GURL& url, RefCountedBytes** data) const { return true; } -void TopSites::StoreMostVisited(MostVisitedURLList* most_visited) { +void TopSites::UpdateMostVisited(MostVisitedURLList* most_visited) { lock_.AssertAcquired(); // TODO(brettw) filter for blacklist! if (!top_sites_.empty()) { - std::vector<size_t> added; - std::vector<size_t> deleted; - std::vector<size_t> moved; + std::vector<size_t> added; // Indices into most_visited. + std::vector<size_t> deleted; // Indices into top_sites_. + std::vector<size_t> moved; // Indices into most_visited. DiffMostVisited(top_sites_, *most_visited, &added, &deleted, &moved); + // Process the diff: delete from images and disk, add to disk. // Delete all the thumbnails associated with URLs that were deleted. for (size_t i = 0; i < deleted.size(); i++) { + MostVisitedURL deleted_url = top_sites_[deleted[i]]; std::map<GURL, Images>::iterator found = - top_images_.find(top_sites_[deleted[i]].url); + top_images_.find(deleted_url.url); if (found != top_images_.end()) top_images_.erase(found); + + // Delete from disk. + if (db_.get()) + db_->RemoveURL(deleted_url); } - // TODO(brettw) write the new data to disk. + if (db_.get()) { + // Write both added and moved urls. + for (size_t i = 0; i < added.size(); i++) { + MostVisitedURL added_url = (*most_visited)[added[i]]; + db_->SetPageThumbnail(added_url, added[i], Images()); + } + for (size_t i = 0; i < moved.size(); i++) { + MostVisitedURL moved_url = (*most_visited)[moved[i]]; + db_->SetPageThumbnail(moved_url, moved[i], Images()); + } + } } + StoreMostVisited(most_visited); +} +void TopSites::StoreMostVisited(MostVisitedURLList* most_visited) { + lock_.AssertAcquired(); // Take ownership of the most visited data. top_sites_.clear(); top_sites_.swap(*most_visited); @@ -222,7 +271,7 @@ void TopSites::OnTopSitesAvailable( CancelableRequestProvider::Handle handle, MostVisitedURLList pages) { AutoLock lock(lock_); - StoreMostVisited(&pages); + UpdateMostVisited(&pages); } void TopSites::SetMockHistoryService(MockHistoryService* mhs) { diff --git a/chrome/browser/history/top_sites.h b/chrome/browser/history/top_sites.h index ff98b7a..0b9b1e4 100644 --- a/chrome/browser/history/top_sites.h +++ b/chrome/browser/history/top_sites.h @@ -28,6 +28,7 @@ class Profile; namespace history { class TopSitesBackend; +class TopSitesDatabase; class TopSitesTest; typedef std::vector<MostVisitedURL> MostVisitedURLList; @@ -56,6 +57,14 @@ class TopSites : public base::RefCountedThreadSafe<TopSites> { virtual ~MockHistoryService() {} }; + struct Images { + scoped_refptr<RefCountedBytes> thumbnail; + ThumbnailScore thumbnail_score; + + // TODO(brettw): this will eventually store the favicon. + // scoped_refptr<RefCountedBytes> favicon; + }; + // Initializes TopSites. void Init(); @@ -77,16 +86,15 @@ class TopSites : public base::RefCountedThreadSafe<TopSites> { friend class base::RefCountedThreadSafe<TopSites>; friend class TopSitesTest; friend class TopSitesTest_GetMostVisited_Test; + friend class TopSitesTest_ReadDatabase_Test; ~TopSites(); - struct Images { - scoped_refptr<RefCountedBytes> thumbnail; - ThumbnailScore thumbnail_score; - - // TODO(brettw): this will eventually store the favicon. - // scoped_refptr<RefCountedBytes> favicon; - }; + // Called by the public SetPageThumbnail. Takes RefCountedBytes + // rather than a SkBitmap. + bool SetPageThumbnail(const GURL& url, + const RefCountedBytes* thumbnail_data, + const ThumbnailScore& score); void StartQueryForMostVisited(); @@ -94,9 +102,10 @@ class TopSites : public base::RefCountedThreadSafe<TopSites> { void OnTopSitesAvailable(CancelableRequestProvider::Handle handle, MostVisitedURLList data); + // Updates the top sites list and writes the difference to disk. + void UpdateMostVisited(MostVisitedURLList* most_visited); // Saves the set of the top URLs visited by this user. The 0th item is the // most popular. - // // DANGER! This will clear all data from the input argument. void StoreMostVisited(MostVisitedURLList* most_visited); @@ -132,6 +141,10 @@ class TopSites : public base::RefCountedThreadSafe<TopSites> { std::vector<size_t>* deleted_urls, std::vector<size_t>* moved_urls); + // Reads the database from disk. Called on startup to get the last + // known top sites. + void ReadDatabase(); + // For testing with a HistoryService mock. void SetMockHistoryService(MockHistoryService* mhs); @@ -158,6 +171,8 @@ class TopSites : public base::RefCountedThreadSafe<TopSites> { // Timer for updating TopSites data. base::OneShotTimer<TopSites> timer_; + scoped_ptr<TopSitesDatabase> db_; + // TODO(brettw): use the blacklist. // std::set<GURL> blacklist_; diff --git a/chrome/browser/history/top_sites_database.h b/chrome/browser/history/top_sites_database.h new file mode 100644 index 0000000..50da75d --- /dev/null +++ b/chrome/browser/history/top_sites_database.h @@ -0,0 +1,55 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_HISTORY_TOP_SITES_DATABASE_H_ +#define CHROME_BROWSER_HISTORY_TOP_SITES_DATABASE_H_ + +#include <vector> + +#include "app/sql/connection.h" +#include "app/sql/init_status.h" +#include "app/sql/meta_table.h" +#include "base/ref_counted.h" +#include "chrome/browser/history/history_types.h" +#include "chrome/browser/history/url_database.h" // For DBCloseScoper. + +class FilePath; +class RefCountedMemory; +class SkBitmap; + +namespace base { +class Time; +} + +namespace history { + +// Interface to be implemented by the real storage layer as well as +// the mockup database for testing. +class TopSitesDatabase { + public: + virtual ~TopSitesDatabase() {} + + // Returns a list of all URLs currently in the table. + virtual MostVisitedURLList GetTopURLs() = 0; + + // Set a thumbnail for a URL. |url_rank| is the position of the URL + // in the list of TopURLs, zero-based. + // If the URL is not in the table, add it. If it is, replace its + // thumbnail. + virtual void SetPageThumbnail(const MostVisitedURL& url, + int url_rank, + const TopSites::Images thumbnail) = 0; + + // Get a thumbnail for a given page. Returns true iff we have the thumbnail. + virtual bool GetPageThumbnail(const MostVisitedURL& url, + TopSites::Images* thumbnail) const = 0; + + // Remove the record for this URL. Returns true iff removed successfully. + virtual bool RemoveURL(const MostVisitedURL& url) = 0; +}; + +} // namespace history + +#endif // CHROME_BROWSER_HISTORY_TOP_SITES_DATABASE_H_ + diff --git a/chrome/browser/history/top_sites_unittest.cc b/chrome/browser/history/top_sites_unittest.cc index 1886e25..bd912b3 100644 --- a/chrome/browser/history/top_sites_unittest.cc +++ b/chrome/browser/history/top_sites_unittest.cc @@ -4,6 +4,7 @@ #include "base/string_util.h" #include "chrome/browser/history/top_sites.h" +#include "chrome/browser/history/top_sites_database.h" #include "chrome/test/testing_profile.h" #include "googleurl/src/gurl.h" #include "testing/gtest/include/gtest/gtest.h" @@ -59,8 +60,8 @@ class TopSitesTest : public testing::Test { DISALLOW_COPY_AND_ASSIGN(TopSitesTest); }; -class MockHistoryServiceImpl: public TopSites::MockHistoryService { - // A mockup of a HistoryService used for testing TopSites. +// A mockup of a HistoryService used for testing TopSites. +class MockHistoryServiceImpl : public TopSites::MockHistoryService { public: // Calls the callback directly with the results. HistoryService::Handle QueryMostVisitedURLs( @@ -88,6 +89,67 @@ class MockHistoryServiceImpl: public TopSites::MockHistoryService { }; +// A mockup of a TopSitesDatabase used for testing TopSites. +class MockTopSitesDatabaseImpl : public TopSitesDatabase { + public: + virtual MostVisitedURLList GetTopURLs() { + // Return a copy of the vector. + return top_sites_list_; + } + + virtual void SetPageThumbnail(const MostVisitedURL& url, int url_rank, + const TopSites::Images thumbnail) { + // Update the list of URLs + // Check if this url is in the list, and at which position. + MostVisitedURLList::iterator pos = std::find(top_sites_list_.begin(), + top_sites_list_.end(), + url); + if (pos == top_sites_list_.end()) { + // Add it to the list. + top_sites_list_.insert(top_sites_list_.begin() + url_rank, url); + } else { + // Is it in the right position? + int rank = pos - top_sites_list_.begin(); + if (rank != url_rank) { + // Move the URL to a new position. + top_sites_list_.erase(pos); + top_sites_list_.insert(top_sites_list_.begin() + url_rank, url); + } + } + // Update thubmnail + thumbnails_map_[url.url] = thumbnail; + } + + // Get a thumbnail for a given page. Returns true iff we have the thumbnail. + virtual bool GetPageThumbnail(const MostVisitedURL& url, + TopSites::Images* thumbnail) const { + std::map<GURL, TopSites::Images>::const_iterator found = + thumbnails_map_.find(url.url); + if (found == thumbnails_map_.end()) + return false; // No thumbnail for this URL. + TopSites::Images* result = new TopSites::Images(found->second); + thumbnail = result; + return true; + } + + virtual bool RemoveURL(const MostVisitedURL& url) { + // Comparison by url. + MostVisitedURLList::iterator pos = std::find(top_sites_list_.begin(), + top_sites_list_.end(), + url); + if (pos == top_sites_list_.end()) { + return false; + } + top_sites_list_.erase(pos); + thumbnails_map_.erase(url.url); + return true; + } + + private: + MostVisitedURLList top_sites_list_; // Keeps the URLs sorted by score (rank). + std::map<GURL, TopSites::Images> thumbnails_map_; +}; + // Helper function for appending a URL to a vector of "most visited" URLs, // using the default values for everything but the URL. @@ -241,4 +303,61 @@ TEST_F(TopSitesTest, GetMostVisited) { EXPECT_EQ(google, results[1].url); } +TEST_F(TopSitesTest, ReadDatabase) { + MockTopSitesDatabaseImpl* db = new MockTopSitesDatabaseImpl; + // |db| is destroyed when the top_sites is destroyed in TearDown. + top_sites().db_.reset(db); + MostVisitedURL url; + GURL asdf_url("http://asdf.com"); + string16 asdf_title(ASCIIToUTF16("ASDF")); + GURL google_url("http://google.com"); + string16 google_title(ASCIIToUTF16("Google")); + GURL news_url("http://news.google.com"); + string16 news_title(ASCIIToUTF16("Google News")); + + url.url = asdf_url; + url.title = asdf_title; + url.redirects.push_back(url.url); + TopSites::Images thumbnail; + db->SetPageThumbnail(url, 0, thumbnail); + + top_sites().ReadDatabase(); + + MostVisitedURLList result = top_sites().GetMostVisitedURLs(); + EXPECT_EQ(1u, result.size()); + EXPECT_EQ(asdf_url, result[0].url); + EXPECT_EQ(asdf_title, result[0].title); + + MostVisitedURL url2; + url2.url = google_url; + url2.title = google_title; + url2.redirects.push_back(url2.url); + + // Add new thumbnail at rank 0 and shift the other result to 1. + db->SetPageThumbnail(url2, 0, thumbnail); + + top_sites().ReadDatabase(); + + result = top_sites().GetMostVisitedURLs(); + EXPECT_EQ(2u, result.size()); + EXPECT_EQ(google_url, result[0].url); + EXPECT_EQ(google_title, result[0].title); + EXPECT_EQ(asdf_url, result[1].url); + EXPECT_EQ(asdf_title, result[1].title); + + MockHistoryServiceImpl hs; + // Add one old, one new URL to the history. + hs.AppendMockPage(google_url, google_title); + hs.AppendMockPage(news_url, news_title); + top_sites().SetMockHistoryService(&hs); + + // This writes the new data to the DB. + top_sites().StartQueryForMostVisited(); + + result = db->GetTopURLs(); + EXPECT_EQ(2u, result.size()); + EXPECT_EQ(google_title, result[0].title); + EXPECT_EQ(news_title, result[1].title); +} + } // namespace history |