Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1396)

Unified Diff: chrome/browser/bookmarks/enhanced/image_store.cc

Issue 259863007: Local salient image storage for enhanced bookmark experiment. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: nits Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/bookmarks/enhanced/image_store.cc
diff --git a/chrome/browser/bookmarks/enhanced/image_store.cc b/chrome/browser/bookmarks/enhanced/image_store.cc
new file mode 100644
index 0000000000000000000000000000000000000000..53982a45b96bd4ed43f8463a6793c949e0b9beb2
--- /dev/null
+++ b/chrome/browser/bookmarks/enhanced/image_store.cc
@@ -0,0 +1,274 @@
+// Copyright 2013 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 "chrome/browser/bookmarks/enhanced/image_store.h"
sky 2014/04/30 18:09:13 nit: newline between 3/4.
Kibeom Kim (inactive) 2014/05/01 19:02:26 Done.
+
+#include "base/logging.h"
+#include "base/memory/ref_counted_memory.h"
+#include "sql/statement.h"
+#include "sql/transaction.h"
+
+#if defined(OS_IOS)
+#import "chrome/browser/bookmarks/enhanced/image_store_ios.h"
+#endif // defined(OS_IOS)
+
+namespace {
+// 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. On iOS instead of the 1x representation (that may lose
+// resolution) the archive contains a iOS specific archive of the UIImage
+// representation.
+scoped_refptr<base::RefCountedMemory> bytesForImage(gfx::Image image) {
sky 2014/04/30 18:09:13 BytesForImage
Kibeom Kim (inactive) 2014/05/01 19:02:26 Done.
+#if defined(OS_IOS)
+ // Forces the image to have a UIImage representation.
+ image.ToUIImage();
+ return image_store_ios::bytesForImage(image);
+#else
+ return image.As1xPNGBytes();
sky 2014/04/30 18:09:13 Why are you only 1x image?
Kibeom Kim (inactive) 2014/05/01 19:02:26 I think above comment #16-#20 explains this issue.
+#endif // defined(OS_IOS)
+} // namespace
+
+gfx::Image imageForBytes(scoped_refptr<base::RefCountedMemory> bytes) {
sky 2014/04/30 18:09:13 ImageForBytes
Kibeom Kim (inactive) 2014/05/01 19:02:26 Done.
+#if defined(OS_IOS)
+ return image_store_ios::imageForBytes(bytes);
+#else
+ return gfx::Image::CreateFrom1xPNGBytes(bytes->front(), bytes->size());
+#endif // defined(OS_IOS)
+}
+} // namespace
+
+void ImageStore::ChangeImageURL(const GURL& from, const GURL& to) {
sky 2014/04/30 18:09:13 Make order match header.
Kibeom Kim (inactive) 2014/05/01 19:02:26 Done.
+ if (!HasKey(from))
+ return;
+ GURL image_url;
+ gfx::Image image(Get(from, image_url));
+
+ Erase(from);
+ Insert(to, image_url, image);
+}
+
+// Removes all images.
+void ImageStore::ClearAll() {
+ std::vector<GURL> all_keys = AllKeys();
+ for (std::vector<GURL>::const_iterator it = all_keys.begin();
+ it != all_keys.end();
+ ++it) {
+ Erase(*it);
+ }
+}
+
+MemoryImageStore::MemoryImageStore() : ImageStore() {}
+MemoryImageStore::~MemoryImageStore() {}
+
+bool MemoryImageStore::HasKey(const GURL& page_url) {
+ return store_.find(page_url) != store_.end();
+}
+
+void MemoryImageStore::Insert(const GURL& page_url,
+ const GURL& image_url,
+ const gfx::Image& image) {
+ Erase(page_url);
+ store_.insert(std::make_pair(
+ page_url,
+ std::make_pair(image,
+ image_url)));
+}
+
+void MemoryImageStore::Erase(const GURL& page_url) {
+ store_.erase(page_url);
+}
+
+gfx::Image MemoryImageStore::Get(const GURL& page_url, GURL& image_url) {
+ ImageMap::const_iterator pair_enumerator = store_.find(page_url);
+ if (pair_enumerator == store_.end())
+ return gfx::Image();
+
+ image_url = store_[page_url].second;
+ return store_[page_url].first;
+}
+
+gfx::Size MemoryImageStore::GetSize(const GURL& page_url) {
+ ImageMap::const_iterator pair_enumerator = store_.find(page_url);
+ if (pair_enumerator == store_.end())
+ return gfx::Size();
+
+ return store_[page_url].first.Size();
+}
+
+std::vector<GURL> MemoryImageStore::AllKeys() {
+ std::vector<GURL> result;
+
+ for (ImageMap::const_iterator it = store_.begin(); it != store_.end(); ++it) {
+ result.push_back(it->first);
+ }
+ return result;
+}
+
+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("BookmarkImageAndUrlStore.db")) {}
+
+PersistentImageStore::~PersistentImageStore() {}
+
+bool PersistentImageStore::HasKey(const GURL& page_url) {
+ OpenDatabase();
+ 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) {
+ 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> data = bytesForImage(image);
+ statement.BindBlob(2, data->front(), data->size());
+
+ statement.BindInt64(3, image.Size().width());
+ statement.BindInt64(4, image.Size().height());
+ statement.Run();
+}
+
+void PersistentImageStore::Erase(const GURL& page_url) {
+ OpenDatabase();
+ 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();
+}
+
+gfx::Image PersistentImageStore::Get(const GURL& page_url, GURL& image_url) {
+ OpenDatabase();
+ 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());
+ image_url = GURL(statement.ColumnString(1));
+ return imageForBytes(data);
+ }
+ }
+ return gfx::Image();
+}
+
+gfx::Size PersistentImageStore::GetSize(const GURL& page_url) {
+ OpenDatabase();
+ 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) {
+ int64 width = statement.ColumnInt64(0);
+ int64 height = statement.ColumnInt64(1);
+ return gfx::Size(width, height);
+ }
+ }
+ return gfx::Size();
+}
+
+std::vector<GURL> PersistentImageStore::AllKeys() {
+ OpenDatabase();
+ std::vector<GURL> result;
+ sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
+ "SELECT page_url FROM images_by_url"));
+ while (statement.Step())
+ result.push_back(GURL(statement.ColumnString(0)));
+
+ return result;
+}
+
+sql::InitStatus PersistentImageStore::OpenDatabase() {
+ 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();
+ }
+ CHECK(false) << "Can't open image DB";
+ return sql::INIT_FAILURE;
+}

Powered by Google App Engine
This is Rietveld 408576698