summaryrefslogtreecommitdiffstats
path: root/chrome/browser/history
diff options
context:
space:
mode:
authornshkrob@chromium.org <nshkrob@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-24 23:24:17 +0000
committernshkrob@chromium.org <nshkrob@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-24 23:24:17 +0000
commit5601f989e08815929e184d04fb720956d07e76cd (patch)
treebe05175a4791fe7be4297487c1f4a5f6180f27e9 /chrome/browser/history
parenteacf8143f91d374403508bb95fea1a0761dc9027 (diff)
downloadchromium_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.h4
-rw-r--r--chrome/browser/history/top_sites.cc85
-rw-r--r--chrome/browser/history/top_sites.h31
-rw-r--r--chrome/browser/history/top_sites_database.h55
-rw-r--r--chrome/browser/history/top_sites_unittest.cc123
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