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

Side by Side 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, 7 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 #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.
5
6 #include "base/logging.h"
7 #include "base/memory/ref_counted_memory.h"
8 #include "sql/statement.h"
9 #include "sql/transaction.h"
10
11 #if defined(OS_IOS)
12 #import "chrome/browser/bookmarks/enhanced/image_store_ios.h"
13 #endif // defined(OS_IOS)
14
15 namespace {
16 // The two methods below archive and unarchive an image to and from a bag of
17 // bytes. There is no API on gfx::Image capable of doing it while preserving the
18 // scale of the image. On iOS instead of the 1x representation (that may lose
19 // resolution) the archive contains a iOS specific archive of the UIImage
20 // representation.
21 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.
22 #if defined(OS_IOS)
23 // Forces the image to have a UIImage representation.
24 image.ToUIImage();
25 return image_store_ios::bytesForImage(image);
26 #else
27 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.
28 #endif // defined(OS_IOS)
29 } // namespace
30
31 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.
32 #if defined(OS_IOS)
33 return image_store_ios::imageForBytes(bytes);
34 #else
35 return gfx::Image::CreateFrom1xPNGBytes(bytes->front(), bytes->size());
36 #endif // defined(OS_IOS)
37 }
38 } // namespace
39
40 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.
41 if (!HasKey(from))
42 return;
43 GURL image_url;
44 gfx::Image image(Get(from, image_url));
45
46 Erase(from);
47 Insert(to, image_url, image);
48 }
49
50 // Removes all images.
51 void ImageStore::ClearAll() {
52 std::vector<GURL> all_keys = AllKeys();
53 for (std::vector<GURL>::const_iterator it = all_keys.begin();
54 it != all_keys.end();
55 ++it) {
56 Erase(*it);
57 }
58 }
59
60 MemoryImageStore::MemoryImageStore() : ImageStore() {}
61 MemoryImageStore::~MemoryImageStore() {}
62
63 bool MemoryImageStore::HasKey(const GURL& page_url) {
64 return store_.find(page_url) != store_.end();
65 }
66
67 void MemoryImageStore::Insert(const GURL& page_url,
68 const GURL& image_url,
69 const gfx::Image& image) {
70 Erase(page_url);
71 store_.insert(std::make_pair(
72 page_url,
73 std::make_pair(image,
74 image_url)));
75 }
76
77 void MemoryImageStore::Erase(const GURL& page_url) {
78 store_.erase(page_url);
79 }
80
81 gfx::Image MemoryImageStore::Get(const GURL& page_url, GURL& image_url) {
82 ImageMap::const_iterator pair_enumerator = store_.find(page_url);
83 if (pair_enumerator == store_.end())
84 return gfx::Image();
85
86 image_url = store_[page_url].second;
87 return store_[page_url].first;
88 }
89
90 gfx::Size MemoryImageStore::GetSize(const GURL& page_url) {
91 ImageMap::const_iterator pair_enumerator = store_.find(page_url);
92 if (pair_enumerator == store_.end())
93 return gfx::Size();
94
95 return store_[page_url].first.Size();
96 }
97
98 std::vector<GURL> MemoryImageStore::AllKeys() {
99 std::vector<GURL> result;
100
101 for (ImageMap::const_iterator it = store_.begin(); it != store_.end(); ++it) {
102 result.push_back(it->first);
103 }
104 return result;
105 }
106
107 namespace {
108 bool InitTables(sql::Connection& db) {
109 const char kTableSql[] =
110 "CREATE TABLE IF NOT EXISTS images_by_url ("
111 " page_url LONGVARCHAR NOT NULL,"
112 " image_url LONGVARCHAR NOT NULL,"
113 " image_data BLOB,"
114 " width INTEGER,"
115 " height INTEGER"
116 ")";
117 if (!db.Execute(kTableSql))
118 return false;
119 return true;
120 }
121
122 bool InitIndices(sql::Connection& db) {
123 const char kIndexSql[] =
124 "CREATE INDEX IF NOT EXISTS images_by_url_idx ON images_by_url(page_url)";
125 if (!db.Execute(kIndexSql))
126 return false;
127 return true;
128 }
129
130 sql::InitStatus OpenDatabaseImpl(sql::Connection& db,
131 const base::FilePath& db_path) {
132 DCHECK(!db.is_open());
133
134 db.set_histogram_tag("BookmarkImages");
135 // TODO(noyau): Set page and cache sizes?
136 // TODO(noyau): Set error callback?
137
138 // Run the database in exclusive mode. Nobody else should be accessing the
139 // database while we're running, and this will give somewhat improved perf.
140 db.set_exclusive_locking();
141
142 if (!db.Open(db_path))
143 return sql::INIT_FAILURE;
144
145 // Scope initialization in a transaction so we can't be partially initialized.
146 sql::Transaction transaction(&db);
147 if (!transaction.Begin())
148 return sql::INIT_FAILURE;
149
150 // Create the tables.
151 if (!InitTables(db) ||
152 !InitIndices(db)) {
153 return sql::INIT_FAILURE;
154 }
155
156 // Initialization is complete.
157 if (!transaction.Commit())
158 return sql::INIT_FAILURE;
159
160 return sql::INIT_OK;
161 }
162
163 } // namespace
164
165 PersistentImageStore::PersistentImageStore(const base::FilePath& path)
166 : ImageStore(), path_(path.Append("BookmarkImageAndUrlStore.db")) {}
167
168 PersistentImageStore::~PersistentImageStore() {}
169
170 bool PersistentImageStore::HasKey(const GURL& page_url) {
171 OpenDatabase();
172 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
173 "SELECT COUNT(*) FROM images_by_url WHERE page_url = ?"));
174 statement.BindString(0, page_url.possibly_invalid_spec());
175
176 int count = statement.Step() ? statement.ColumnInt(0) : 0;
177
178 return !!count;
179 }
180
181 void PersistentImageStore::Insert(const GURL& page_url,
182 const GURL& image_url,
183 const gfx::Image& image) {
184 Erase(page_url); // Remove previous image for this url, if any.
185 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
186 "INSERT INTO images_by_url "
187 " (page_url, image_url, image_data, width, height)"
188 " VALUES (?, ?, ?, ?, ?)"));
189
190 statement.BindString(0, page_url.possibly_invalid_spec());
191 statement.BindString(1, image_url.possibly_invalid_spec());
192
193 scoped_refptr<base::RefCountedMemory> data = bytesForImage(image);
194 statement.BindBlob(2, data->front(), data->size());
195
196 statement.BindInt64(3, image.Size().width());
197 statement.BindInt64(4, image.Size().height());
198 statement.Run();
199 }
200
201 void PersistentImageStore::Erase(const GURL& page_url) {
202 OpenDatabase();
203 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
204 "DELETE FROM images_by_url WHERE page_url = ?"));
205 statement.BindString(0, page_url.possibly_invalid_spec());
206 statement.Run();
207 }
208
209 gfx::Image PersistentImageStore::Get(const GURL& page_url, GURL& image_url) {
210 OpenDatabase();
211 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
212 "SELECT image_data, image_url FROM images_by_url WHERE page_url = ?"));
213
214 statement.BindString(0, page_url.possibly_invalid_spec());
215
216 while (statement.Step()) {
217 if (statement.ColumnByteLength(0) > 0) {
218 scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes());
219 statement.ColumnBlobAsVector(0, &data->data());
220 image_url = GURL(statement.ColumnString(1));
221 return imageForBytes(data);
222 }
223 }
224 return gfx::Image();
225 }
226
227 gfx::Size PersistentImageStore::GetSize(const GURL& page_url) {
228 OpenDatabase();
229 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
230 "SELECT width, height FROM images_by_url WHERE page_url = ?"));
231
232 statement.BindString(0, page_url.possibly_invalid_spec());
233
234 while (statement.Step()) {
235 if (statement.ColumnByteLength(0) > 0) {
236 int64 width = statement.ColumnInt64(0);
237 int64 height = statement.ColumnInt64(1);
238 return gfx::Size(width, height);
239 }
240 }
241 return gfx::Size();
242 }
243
244 std::vector<GURL> PersistentImageStore::AllKeys() {
245 OpenDatabase();
246 std::vector<GURL> result;
247 sql::Statement statement(db_.GetCachedStatement(SQL_FROM_HERE,
248 "SELECT page_url FROM images_by_url"));
249 while (statement.Step())
250 result.push_back(GURL(statement.ColumnString(0)));
251
252 return result;
253 }
254
255 sql::InitStatus PersistentImageStore::OpenDatabase() {
256 if (db_.is_open())
257 return sql::INIT_OK;
258
259 const size_t kAttempts = 2;
260
261 sql::InitStatus status = sql::INIT_FAILURE;
262 for (size_t i = 0; i < kAttempts; ++i) {
263 status = OpenDatabaseImpl(db_, path_);
264 if (status == sql::INIT_OK)
265 return status;
266
267 // Can't open, raze().
268 if (db_.is_open())
269 db_.Raze();
270 db_.Close();
271 }
272 CHECK(false) << "Can't open image DB";
273 return sql::INIT_FAILURE;
274 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698