Commit 174a621f authored by kkimlabs@chromium.org's avatar kkimlabs@chromium.org

Local salient image storage for enhanced bookmark experiment.

BUG=368034

Review URL: https://codereview.chromium.org/259863007

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@269703 0039d316-1c4b-4281-b951-d872f2087c98
parent 41a7fd69
......@@ -20,6 +20,7 @@
'data_reduction_proxy.gypi',
'dom_distiller.gypi',
'domain_reliability.gypi',
'enhanced_bookmarks.gypi',
'favicon.gypi',
'favicon_base.gypi',
'feedback.gypi', # crbug.com/368738
......
......@@ -92,6 +92,7 @@
'domain_reliability/test_util.h',
'domain_reliability/uploader_unittest.cc',
'domain_reliability/util_unittest.cc',
'enhanced_bookmarks/image_store_unittest.cc',
'feedback/feedback_uploader_unittest.cc',
'invalidation/invalidation_logger_unittest.cc',
'json_schema/json_schema_validator_unittest.cc',
......@@ -206,7 +207,7 @@
# Dependencies of bookmarks
'components.gyp:bookmarks_core_browser',
'components.gyp:bookmarks_core_test_support',
# Dependencies of captive_portal
'components.gyp:captive_portal_test_support',
'../net/net.gyp:net_test_support',
......@@ -227,6 +228,10 @@
# Dependencies of domain_reliability
'components.gyp:domain_reliability',
# Dependencies of enhanced_bookmarks
'components.gyp:enhanced_bookmarks',
'components.gyp:enhanced_bookmarks_test_support',
# Dependencies of feedback
'components.gyp:feedback_component',
......
# Copyright 2014 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.
{
'targets': [
{
'target_name': 'enhanced_bookmarks',
'type': 'static_library',
'include_dirs': [
'..',
],
'dependencies': [
'../base/base.gyp:base',
'../sql/sql.gyp:sql',
'../ui/gfx/gfx.gyp:gfx',
'../url/url.gyp:url_lib',
],
'sources': [
'enhanced_bookmarks/image_store.cc',
'enhanced_bookmarks/image_store.h',
'enhanced_bookmarks/image_store_util.cc',
'enhanced_bookmarks/image_store_util.h',
'enhanced_bookmarks/persistent_image_store.cc',
'enhanced_bookmarks/persistent_image_store.h',
],
'conditions': [
['OS=="ios"', {
'sources!': [
'enhanced_bookmarks/image_store_util.cc',
],
}],
],
},
{
'target_name': 'enhanced_bookmarks_test_support',
'type': 'static_library',
'include_dirs': [
'..',
],
'dependencies': [
'../testing/gtest.gyp:gtest',
'enhanced_bookmarks',
],
'sources': [
'enhanced_bookmarks/test_image_store.cc',
'enhanced_bookmarks/test_image_store.h',
],
},
],
}
include_rules = [
"+components/bookmarks/core",
"+sql",
"+ui",
]
specific_include_rules = {
"image_store_unittest\.cc": [
"+third_party/skia"
],
}
noyau@chromium.org
sky@chromium.org
// Copyright 2014 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.
#include "components/enhanced_bookmarks/image_store.h"
#include "url/gurl.h"
ImageStore::ImageStore() {
}
void ImageStore::ChangeImageURL(const GURL& from, const GURL& to) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!HasKey(from))
return;
std::pair<gfx::Image, GURL> image_info = Get(from);
Erase(from);
Insert(to, image_info.second, image_info.first);
}
ImageStore::~ImageStore() {
}
// Copyright 2014 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 COMPONENTS_ENHANCED_BOOKMARKS_IMAGE_STORE_H_
#define COMPONENTS_ENHANCED_BOOKMARKS_IMAGE_STORE_H_
#include <map>
#include <set>
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/threading/thread_checker.h"
#include "ui/gfx/image/image.h"
class GURL;
// The ImageStore keeps an image for each URL. This class is not thread safe,
// and will check the thread using base::ThreadChecker, except the constructor.
class ImageStore : public base::RefCounted<ImageStore> {
public:
ImageStore();
// Returns true if there is an image for this url.
virtual bool HasKey(const GURL& page_url) = 0;
// Inserts an image and its url in the store for the the given page url. The
// image can be null indicating that the download of the image at this URL or
// encoding for insertion failed previously. On non-ios platforms, |image|
// must have exactly one representation with a scale factor of 1.
virtual void Insert(const GURL& page_url,
const GURL& image_url,
const gfx::Image& image) = 0;
// Removes an image from the store.
virtual void Erase(const GURL& page_url) = 0;
// Returns the image associated with this url. Returns empty image and url if
// there are no image for this url. It also returns the image_url where the
// image was downloaded from or failed to be downloaded from.
virtual std::pair<gfx::Image, GURL> Get(const GURL& page_url) = 0;
// Returns the size of the image stored for this URL or empty size if no
// images are present.
virtual gfx::Size GetSize(const GURL& page_url) = 0;
// Populates |urls| with all the urls that have an image in the store.
virtual void GetAllPageUrls(std::set<GURL>* urls) = 0;
// Removes all images.
virtual void ClearAll() = 0;
// Moves an image from one url to another.
void ChangeImageURL(const GURL& from, const GURL& to);
protected:
virtual ~ImageStore();
base::ThreadChecker thread_checker_;
private:
friend class base::RefCounted<ImageStore>;
DISALLOW_COPY_AND_ASSIGN(ImageStore);
};
#endif // COMPONENTS_ENHANCED_BOOKMARKS_IMAGE_STORE_H_
// Copyright 2014 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.
#include "components/enhanced_bookmarks/image_store.h"
#include "base/files/scoped_temp_dir.h"
#include "components/enhanced_bookmarks/image_store_util.h"
#include "components/enhanced_bookmarks/persistent_image_store.h"
#include "components/enhanced_bookmarks/test_image_store.h"
#include "testing/platform_test.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "url/gurl.h"
namespace {
const SkBitmap CreateBitmap(int width, int height, int a, int r, int g, int b) {
SkBitmap bitmap;
bitmap.allocN32Pixels(width, height);
bitmap.eraseARGB(a, r, g, b);
return bitmap;
}
gfx::Image GenerateWhiteImage() {
return gfx::Image::CreateFrom1xBitmap(
CreateBitmap(42, 24, 255, 255, 255, 255));
}
gfx::Image GenerateBlackImage(int width, int height) {
return gfx::Image::CreateFrom1xBitmap(
CreateBitmap(width, height, 255, 0, 0, 0));
}
gfx::Image GenerateBlackImage() {
return GenerateBlackImage(42, 24);
}
// Returns true if the two images are identical.
bool CompareImages(const gfx::Image& image_1, const gfx::Image& image_2) {
if (image_1.IsEmpty() && image_2.IsEmpty())
return true;
if (image_1.IsEmpty() || image_2.IsEmpty())
return false;
scoped_refptr<base::RefCountedMemory> image_1_png =
enhanced_bookmarks::BytesForImage(image_1);
scoped_refptr<base::RefCountedMemory> image_2_png =
enhanced_bookmarks::BytesForImage(image_2);
if (image_1_png->size() != image_2_png->size())
return false;
return !memcmp(image_1_png->front(),
image_2_png->front(),
image_1_png->size());
}
// Factory functions for creating instances of the implementations.
template <class T>
scoped_refptr<ImageStore> CreateStore(base::ScopedTempDir& folder);
template <>
scoped_refptr<ImageStore> CreateStore<TestImageStore>(
base::ScopedTempDir& folder) {
return scoped_refptr<ImageStore>(new TestImageStore());
}
template <>
scoped_refptr<ImageStore> CreateStore<PersistentImageStore>(
base::ScopedTempDir& folder) {
return scoped_refptr<ImageStore>(new PersistentImageStore(folder.path()));
}
// Methods to check if persistence is on or not.
template <class T> bool ShouldPersist();
template <> bool ShouldPersist<TestImageStore>() { return false; }
template <> bool ShouldPersist<PersistentImageStore>() { return true; }
// Test fixture class template for the abstract API.
template <class T>
class ImageStoreUnitTest : public PlatformTest {
protected:
ImageStoreUnitTest() {}
virtual ~ImageStoreUnitTest() {}
virtual void SetUp() OVERRIDE {
bool success = tempDir_.CreateUniqueTempDir();
ASSERT_TRUE(success);
store_ = CreateStore<T>(tempDir_);
}
virtual void TearDown() OVERRIDE {
if (store_ && use_persistent_store())
store_->ClearAll();
}
bool use_persistent_store() const { return ShouldPersist<T>(); }
void ResetStore() { store_ = CreateStore<T>(tempDir_); }
// The directory the database is saved into.
base::ScopedTempDir tempDir_;
// The object the fixture is testing, via its base interface.
scoped_refptr<ImageStore> store_;
private:
DISALLOW_COPY_AND_ASSIGN(ImageStoreUnitTest);
};
// The list of implementations of the abstract API that are going to be tested.
typedef testing::Types<TestImageStore,
PersistentImageStore> Implementations;
TYPED_TEST_CASE(ImageStoreUnitTest, Implementations);
// All those tests are run on all the implementations.
TYPED_TEST(ImageStoreUnitTest, StartsEmpty) {
std::set<GURL> all_urls;
this->store_->GetAllPageUrls(&all_urls);
EXPECT_EQ(0u, all_urls.size());
}
TYPED_TEST(ImageStoreUnitTest, StoreOne) {
this->store_->Insert(GURL("foo://bar"), GURL("a.jpg"), GenerateBlackImage());
std::set<GURL> all_urls;
this->store_->GetAllPageUrls(&all_urls);
EXPECT_EQ(1u, all_urls.size());
EXPECT_EQ(GURL("foo://bar"), *all_urls.begin());
EXPECT_TRUE(this->store_->HasKey(GURL("foo://bar")));
}
TYPED_TEST(ImageStoreUnitTest, Retrieve) {
gfx::Image src_image = GenerateBlackImage(42, 24);
const GURL url("foo://bar");
const GURL image_url("a.jpg");
this->store_->Insert(url, image_url, src_image);
std::pair<gfx::Image, GURL> image_info = this->store_->Get(url);
gfx::Size size = this->store_->GetSize(url);
EXPECT_EQ(size.width(), 42);
EXPECT_EQ(size.height(), 24);
EXPECT_EQ(image_url, image_info.second);
EXPECT_TRUE(CompareImages(src_image, image_info.first));
}
TYPED_TEST(ImageStoreUnitTest, Erase) {
gfx::Image src_image = GenerateBlackImage();
const GURL url("foo://bar");
const GURL image_url("a.jpg");
this->store_->Insert(url, image_url, src_image);
this->store_->Erase(url);
EXPECT_FALSE(this->store_->HasKey(url));
std::set<GURL> all_urls;
this->store_->GetAllPageUrls(&all_urls);
EXPECT_EQ(0u, all_urls.size());
}
TYPED_TEST(ImageStoreUnitTest, ClearAll) {
const GURL url_foo("http://foo");
this->store_->Insert(url_foo, GURL("foo.jpg"), GenerateBlackImage());
const GURL url_bar("http://bar");
this->store_->Insert(url_foo, GURL("bar.jpg"), GenerateWhiteImage());
this->store_->ClearAll();
EXPECT_FALSE(this->store_->HasKey(url_foo));
EXPECT_FALSE(this->store_->HasKey(url_bar));
std::set<GURL> all_urls;
this->store_->GetAllPageUrls(&all_urls);
EXPECT_EQ(0u, all_urls.size());
}
TYPED_TEST(ImageStoreUnitTest, Update) {
gfx::Image src_image1 = GenerateWhiteImage();
gfx::Image src_image2 = GenerateBlackImage();
const GURL url("foo://bar");
const GURL image_url1("1.jpg");
this->store_->Insert(url, image_url1, src_image1);
const GURL image_url2("2.jpg");
this->store_->Insert(url, image_url2, src_image2);
std::pair<gfx::Image, GURL> image_info = this->store_->Get(url);
EXPECT_TRUE(this->store_->HasKey(url));
std::set<GURL> all_urls;
this->store_->GetAllPageUrls(&all_urls);
EXPECT_EQ(1u, all_urls.size());
EXPECT_EQ(image_url2, image_info.second);
EXPECT_TRUE(CompareImages(src_image2, image_info.first));
}
TYPED_TEST(ImageStoreUnitTest, Persistence) {
gfx::Image src_image = GenerateBlackImage();
const GURL url("foo://bar");
const GURL image_url("a.jpg");
this->store_->Insert(url, image_url, src_image);
this->ResetStore();
if (this->use_persistent_store()) {
std::set<GURL> all_urls;
this->store_->GetAllPageUrls(&all_urls);
EXPECT_EQ(1u, all_urls.size());
EXPECT_EQ(GURL("foo://bar"), *all_urls.begin());
EXPECT_TRUE(this->store_->HasKey(GURL("foo://bar")));
std::pair<gfx::Image, GURL> image_info = this->store_->Get(url);
EXPECT_EQ(image_url, image_info.second);
EXPECT_TRUE(CompareImages(src_image, image_info.first));
} else {
std::set<GURL> all_urls;
this->store_->GetAllPageUrls(&all_urls);
EXPECT_EQ(0u, all_urls.size());
EXPECT_FALSE(this->store_->HasKey(GURL("foo://bar")));
}
}
} // namespace
// Copyright 2014 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.
#include "components/enhanced_bookmarks/image_store_util.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_util.h"
namespace {
const int kJpegEncodingQuality = 70;
} // namespace
namespace enhanced_bookmarks {
scoped_refptr<base::RefCountedMemory> BytesForImage(const gfx::Image& image) {
DCHECK(image.AsImageSkia().image_reps().size() == 1);
DCHECK(image.AsImageSkia().image_reps().begin()->scale() == 1.0f);
std::vector<unsigned char> data;
bool succeeded =
gfx::JPEG1xEncodedDataFromImage(image, kJpegEncodingQuality, &data);
if (!succeeded)
return scoped_refptr<base::RefCountedMemory>();
return scoped_refptr<base::RefCountedMemory>(new base::RefCountedBytes(data));
}
gfx::Image ImageForBytes(const scoped_refptr<base::RefCountedMemory>& bytes) {
return gfx::ImageFrom1xJPEGEncodedData(bytes->front(), bytes->size());
}
}
// Copyright 2014 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 COMPONENTS_ENHANCED_BOOKMARKS_IMAGE_STORE_UTIL_H_
#define COMPONENTS_ENHANCED_BOOKMARKS_IMAGE_STORE_UTIL_H_
#include "base/memory/ref_counted_memory.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image.h"
namespace enhanced_bookmarks {
// The two methods below archive and unarchive an image to and from a bag of
// bytes. There is no API on gfx::Image capable of doing it while preserving the
// scale of the image.
// Encode |image| to bytes, that can be decoded using the below |ImageForBytes|
// function. If encoding fails, then returned scoped_refptr has NULL.
scoped_refptr<base::RefCountedMemory> BytesForImage(const gfx::Image& image);
// Decode the image bytes encoded by the above |BytesForImage| function and
// returns a gfx::Image. If decoding fails, returns an empty image.
gfx::Image ImageForBytes(const scoped_refptr<base::RefCountedMemory>& data);
}
#endif // COMPONENTS_ENHANCED_BOOKMARKS_IMAGE_STORE_UTIL_H_
// Copyright 2014 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.
#include "components/enhanced_bookmarks/persistent_image_store.h"
#include "components/enhanced_bookmarks/image_store_util.h"
#include "sql/statement.h"
#include "sql/transaction.h"
#include "ui/gfx/geometry/size.h"
#include "url/gurl.h"
namespace {
bool InitTables(sql::Connection& db) {
const char kTableSql[] =
"CREATE TABLE IF NOT EXISTS images_by_url ("
"page_url LONGVARCHAR NOT NULL,"
"image_url LONGVARCHAR NOT NULL,"
"image_data BLOB,"
"width INTEGER,"
"height INTEGER"
")";
if (!db.Execute(kTableSql))
return false;
return true;
}
bool InitIndices(sql::Connection& db) {
const char kIndexSql[] =
"CREATE INDEX IF NOT EXISTS images_by_url_idx ON images_by_url(page_url)";
if (!db.Execute(kIndexSql))
return false;
return true;
}
sql::InitStatus OpenDatabaseImpl(sql::Connection& db,
const base::FilePath& db_path) {
DCHECK(!db.is_open());
db.set_histogram_tag("BookmarkImages");
// TODO(noyau): Set page and cache sizes?
// TODO(noyau): Set error callback?
// Run the database in exclusive mode. Nobody else should be accessing the
// database while we're running, and this will give somewhat improved perf.
db.set_exclusive_locking();
if (!db.Open(db_path))
return sql::INIT_FAILURE;
// Scope initialization in a transaction so we can't be partially initialized.
sql::Transaction transaction(&db);
if (!transaction.Begin())
return sql::INIT_FAILURE;
// Create the tables.
if (!InitTables(db) ||
!InitIndices(db)) {
return sql::INIT_FAILURE;
}
// Initialization is complete.
if (!transaction.Commit())
return sql::INIT_FAILURE;
return sql::INIT_OK;
}
} // namespace
PersistentImageStore::PersistentImageStore(const base::FilePath& path)
: ImageStore(),
path_(path.Append(
base::FilePath::FromUTF8Unsafe("BookmarkImageAndUrlStore.db"))) {
}
bool PersistentImageStore::HasKey(const GURL& page_url) {
DCHECK(thread_checker_.CalledOnValidThread());
if (OpenDatabase() != sql::INIT_OK)
return false;
sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
"SELECT COUNT(*) FROM images_by_url WHERE page_url = ?"));
statement.BindString(0, page_url.possibly_invalid_spec());
int count = statement.Step() ? statement.ColumnInt(0) : 0;
return !!count;
}
void PersistentImageStore::Insert(const GURL& page_url,
const GURL& image_url,
const gfx::Image& image) {
DCHECK(thread_checker_.CalledOnValidThread());
if (OpenDatabase() != sql::INIT_OK)
return;
Erase(page_url); // Remove previous image for this url, if any.
sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
"INSERT INTO images_by_url "
"(page_url, image_url, image_data, width, height)"
"VALUES (?, ?, ?, ?, ?)"));
statement.BindString(0, page_url.possibly_invalid_spec());
statement.BindString(1, image_url.possibly_invalid_spec());
scoped_refptr<base::RefCountedMemory> image_bytes =
enhanced_bookmarks::BytesForImage(image);
// Insert an empty image in case encoding fails.
if (!image_bytes.get())
image_bytes = enhanced_bookmarks::BytesForImage(gfx::Image());
CHECK(image_bytes.get());
statement.BindBlob(2, image_bytes->front(), (int)image_bytes->size());
statement.BindInt(3, image.Size().width());
statement.BindInt(4, image.Size().height());
statement.Run();
}
void PersistentImageStore::Erase(const GURL& page_url) {
DCHECK(thread_checker_.CalledOnValidThread());
if (OpenDatabase() != sql::INIT_OK)
return;
sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
"DELETE FROM images_by_url WHERE page_url = ?"));
statement.BindString(0, page_url.possibly_invalid_spec());
statement.Run();
}
std::pair<gfx::Image, GURL> PersistentImageStore::Get(const GURL& page_url) {
DCHECK(thread_checker_.CalledOnValidThread());
if (OpenDatabase() != sql::INIT_OK)
return std::make_pair(gfx::Image(), GURL());
sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
"SELECT image_data, image_url FROM images_by_url WHERE page_url = ?"));
statement.BindString(0, page_url.possibly_invalid_spec());
while (statement.Step()) {
if (statement.ColumnByteLength(0) > 0) {
scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes());
statement.ColumnBlobAsVector(0, &data->data());
return std::make_pair(enhanced_bookmarks::ImageForBytes(data),
GURL(statement.ColumnString(1)));
}
}
return std::make_pair(gfx::Image(), GURL());
}
gfx::Size PersistentImageStore::GetSize(const GURL& page_url) {
DCHECK(thread_checker_.CalledOnValidThread());
if (OpenDatabase() != sql::INIT_OK)
return gfx::Size();
sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
"SELECT width, height FROM images_by_url WHERE page_url = ?"));
statement.BindString(0, page_url.possibly_invalid_spec());
while (statement.Step()) {
if (statement.ColumnByteLength(0) > 0) {
int width = statement.ColumnInt(0);
int height = statement.ColumnInt(1);
return gfx::Size(width, height);
}
}
return gfx::Size();
}
void PersistentImageStore::GetAllPageUrls(std::set<GURL>* urls) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(urls->empty());
if (OpenDatabase() != sql::INIT_OK)
return;
sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
"SELECT page_url FROM images_by_url"));
while (statement.Step())
urls->insert(GURL(statement.ColumnString(0)));
}
void PersistentImageStore::ClearAll() {
DCHECK(thread_checker_.CalledOnValidThread());
if (OpenDatabase() != sql::INIT_OK)
return;
sql::Statement statement(db_.GetCachedStatement(
SQL_FROM_HERE, "DELETE FROM images_by_url"));
statement.Run();
}
PersistentImageStore::~PersistentImageStore() {
DCHECK(thread_checker_.CalledOnValidThread());
}
sql::InitStatus PersistentImageStore::OpenDatabase() {
DCHECK(thread_checker_.CalledOnValidThread());
if (db_.is_open())
return sql::INIT_OK;
const size_t kAttempts = 2;
sql::InitStatus status = sql::INIT_FAILURE;
for (size_t i = 0; i < kAttempts; ++i) {
status = OpenDatabaseImpl(db_, path_);
if (status == sql::INIT_OK)
return status;
// Can't open, raze().
if (db_.is_open())
db_.Raze();
db_.Close();
}
DCHECK(false) << "Can't open image DB";
return sql::INIT_FAILURE;
}
// Copyright 2014 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 COMPONENTS_ENHANCED_BOOKMARKS_PERSISTENT_IMAGE_STORE_H_
#define COMPONENTS_ENHANCED_BOOKMARKS_PERSISTENT_IMAGE_STORE_H_
#include "components/enhanced_bookmarks/image_store.h"
#include "base/files/file_path.h"
#include "sql/connection.h"
#include "sql/init_status.h"
// The PersistentImageStore is an implementation of ImageStore that persists its
// data on disk.
class PersistentImageStore : public ImageStore {
public:
// Creates a PersistentImageStore in the directory at the given path.
explicit PersistentImageStore(const base::FilePath& path);
virtual bool HasKey(const GURL& page_url) OVERRIDE;
virtual void Insert(const GURL& page_url,
const GURL& image_url,
const gfx::Image& image) OVERRIDE;
virtual void Erase(const GURL& page_url) OVERRIDE;
virtual std::pair<gfx::Image, GURL> Get(const GURL& page_url) OVERRIDE;
virtual gfx::Size GetSize(const GURL& page_url) OVERRIDE;
virtual void GetAllPageUrls(std::set<GURL>* urls) OVERRIDE;
virtual void ClearAll() OVERRIDE;
protected:
virtual ~PersistentImageStore();
private:
sql::InitStatus OpenDatabase();
const base::FilePath path_;
sql::Connection db_;
DISALLOW_COPY_AND_ASSIGN(PersistentImageStore);
};
#endif // COMPONENTS_ENHANCED_BOOKMARKS_PERSISTENT_IMAGE_STORE_H_
// Copyright 2014 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.
#include "components/enhanced_bookmarks/test_image_store.h"
#include "ui/gfx/geometry/size.h"
#include "url/gurl.h"
TestImageStore::TestImageStore() {
}
bool TestImageStore::HasKey(const GURL& page_url) {
DCHECK(thread_checker_.CalledOnValidThread());
return store_.find(page_url) != store_.end();
}
void TestImageStore::Insert(const GURL& page_url,
const GURL& image_url,
const gfx::Image& image) {
DCHECK(thread_checker_.CalledOnValidThread());
Erase(page_url);
store_.insert(std::make_pair(
page_url,
std::make_pair(image,
image_url)));
}
void TestImageStore::Erase(const GURL& page_url) {
DCHECK(thread_checker_.CalledOnValidThread());
store_.erase(page_url);
}
std::pair<gfx::Image, GURL> TestImageStore::Get(const GURL& page_url) {
DCHECK(thread_checker_.CalledOnValidThread());
ImageMap::const_iterator pair_enumerator = store_.find(page_url);
if (pair_enumerator == store_.end())
return std::make_pair(gfx::Image(), GURL());
return std::make_pair(store_[page_url].first, store_[page_url].second);
}
gfx::Size TestImageStore::GetSize(const GURL& page_url) {
DCHECK(thread_checker_.CalledOnValidThread());
ImageMap::const_iterator pair_enumerator = store_.find(page_url);
if (pair_enumerator == store_.end())
return gfx::Size();
return store_[page_url].first.Size();
}
void TestImageStore::GetAllPageUrls(std::set<GURL>* urls) {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(urls->empty());
for (ImageMap::const_iterator it = store_.begin(); it != store_.end(); ++it)
urls->insert(it->first);
}
void TestImageStore::ClearAll() {
DCHECK(thread_checker_.CalledOnValidThread());
store_.clear();
}
TestImageStore::~TestImageStore() {
DCHECK(thread_checker_.CalledOnValidThread());
}
// Copyright 2014 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 COMPONENTS_ENHANCED_BOOKMARKS_TEST_IMAGE_STORE_H_
#define COMPONENTS_ENHANCED_BOOKMARKS_TEST_IMAGE_STORE_H_
#include "components/enhanced_bookmarks/image_store.h"
// The TestImageStore is an implementation of ImageStore that keeps all its
// data in memory. When deallocated all the associations are lost.
// Used in tests.
class TestImageStore : public ImageStore {
public:
TestImageStore();
virtual bool HasKey(const GURL& page_url) OVERRIDE;
virtual void Insert(const GURL& page_url,
const GURL& image_url,
const gfx::Image& image) OVERRIDE;
virtual void Erase(const GURL& page_url) OVERRIDE;
virtual std::pair<gfx::Image, GURL> Get(const GURL& page_url) OVERRIDE;
virtual gfx::Size GetSize(const GURL& page_url) OVERRIDE;
virtual void GetAllPageUrls(std::set<GURL>* urls) OVERRIDE;
virtual void ClearAll() OVERRIDE;
protected:
virtual ~TestImageStore();
private:
typedef std::map<const GURL, std::pair<gfx::Image, const GURL> > ImageMap;
ImageMap store_;
DISALLOW_COPY_AND_ASSIGN(TestImageStore);
};
#endif // COMPONENTS_ENHANCED_BOOKMARKS_TEST_IMAGE_STORE_H_
......@@ -45825,6 +45825,7 @@ Therefore, the affected-histogram name has to have at least one dot in it.
<histogram_suffixes name="SqliteDatabases" separator=".">
<suffix name="Activity" label="Activity"/>
<suffix name="AppCache" label="AppCache"/>
<suffix name="BookmarkImages" label="BookmarkImages"/>
<suffix name="Cookie" label="Cookie"/>
<suffix name="DatabaseTracker" label="DatabaseTracker"/>
<suffix name="DomainBoundCerts" label="DomainBoundCerts"/>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment