OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/thumbnail_store.h" | 5 #include "chrome/browser/thumbnail_store.h" |
6 | 6 |
7 #include <string.h> | 7 #include <string.h> |
8 #include <algorithm> | 8 #include <algorithm> |
9 | 9 |
10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
11 #include "base/pickle.h" | |
12 #include "base/file_util.h" | 11 #include "base/file_util.h" |
13 #include "base/gfx/jpeg_codec.h" | 12 #include "base/gfx/jpeg_codec.h" |
14 #include "base/md5.h" | 13 #include "base/md5.h" |
15 #include "base/string_util.h" | 14 #include "base/string_util.h" |
16 #include "base/thread.h" | 15 #include "base/thread.h" |
17 #include "base/values.h" | 16 #include "base/values.h" |
18 #include "chrome/browser/browser_process.h" | 17 #include "chrome/browser/browser_process.h" |
19 #include "chrome/browser/profile.h" | 18 #include "chrome/browser/profile.h" |
20 #include "chrome/common/pref_service.h" | 19 #include "chrome/common/pref_service.h" |
21 #include "chrome/common/thumbnail_score.h" | 20 #include "chrome/common/sqlite_utils.h" |
22 #include "googleurl/src/gurl.h" | 21 #include "googleurl/src/gurl.h" |
23 #include "third_party/skia/include/core/SkBitmap.h" | 22 #include "third_party/skia/include/core/SkBitmap.h" |
24 | 23 |
25 | 24 |
26 ThumbnailStore::ThumbnailStore() | 25 ThumbnailStore::ThumbnailStore() |
27 : cache_(NULL), | 26 : cache_(NULL), |
28 cache_initialized_(false), | 27 db_(NULL), |
29 hs_(NULL), | 28 hs_(NULL), |
30 url_blacklist_(NULL) { | 29 url_blacklist_(NULL) { |
31 } | 30 } |
32 | 31 |
33 ThumbnailStore::~ThumbnailStore() { | 32 ThumbnailStore::~ThumbnailStore() { |
| 33 CommitCacheToDB(NULL); |
34 } | 34 } |
35 | 35 |
36 void ThumbnailStore::Init(const FilePath& file_path, Profile* profile) { | 36 void ThumbnailStore::Init(const FilePath& db_name, |
37 file_path_ = file_path; | 37 Profile* profile) { |
| 38 // Load thumbnails already in the database. |
| 39 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, |
| 40 NewRunnableMethod(this, &ThumbnailStore::InitializeFromDB, |
| 41 db_name, MessageLoop::current())); |
| 42 |
| 43 // Take ownership of a reference to the HistoryService. |
38 hs_ = profile->GetHistoryService(Profile::EXPLICIT_ACCESS); | 44 hs_ = profile->GetHistoryService(Profile::EXPLICIT_ACCESS); |
| 45 |
| 46 // Store a pointer to a persistent table of blacklisted URLs. |
39 url_blacklist_ = profile->GetPrefs()-> | 47 url_blacklist_ = profile->GetPrefs()-> |
40 GetMutableDictionary(prefs::kNTPMostVisitedURLsBlacklist); | 48 GetMutableDictionary(prefs::kNTPMostVisitedURLsBlacklist); |
41 | 49 |
42 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, | 50 // Get the list of most visited URLs and redirect information from the |
43 NewRunnableMethod(this, &ThumbnailStore::GetAllThumbnailsFromDisk, | 51 // HistoryService. |
44 file_path_, MessageLoop::current())); | |
45 | |
46 timer_.Start(base::TimeDelta::FromMinutes(30), this, | 52 timer_.Start(base::TimeDelta::FromMinutes(30), this, |
47 &ThumbnailStore::UpdateURLData); | 53 &ThumbnailStore::UpdateURLData); |
48 UpdateURLData(); | 54 UpdateURLData(); |
49 } | 55 } |
50 | 56 |
51 bool ThumbnailStore::SetPageThumbnail(const GURL& url, | 57 bool ThumbnailStore::SetPageThumbnail(const GURL& url, |
52 const SkBitmap& thumbnail, | 58 const SkBitmap& thumbnail, |
53 const ThumbnailScore& score, | 59 const ThumbnailScore& score) { |
54 bool write_to_disk) { | 60 if (!cache_.get()) |
55 if (!cache_initialized_) | |
56 return false; | 61 return false; |
57 | 62 |
58 if (!ShouldStoreThumbnailForURL(url) || | 63 if (!ShouldStoreThumbnailForURL(url) || |
59 (cache_->find(url) != cache_->end() && | 64 (cache_->find(url) != cache_->end() && |
60 !ShouldReplaceThumbnailWith((*cache_)[url].second, score))) | 65 !ShouldReplaceThumbnailWith((*cache_)[url].score_, score))) |
61 return true; | 66 return true; |
62 | 67 |
63 base::TimeTicks encode_start = base::TimeTicks::Now(); | 68 base::TimeTicks encode_start = base::TimeTicks::Now(); |
64 | 69 |
65 // Encode the SkBitmap to jpeg and add to cache. | 70 // Encode the SkBitmap to jpeg. |
66 scoped_refptr<RefCountedBytes> jpeg_data = new RefCountedBytes; | 71 scoped_refptr<RefCountedBytes> jpeg_data = new RefCountedBytes; |
67 SkAutoLockPixels thumbnail_lock(thumbnail); | 72 SkAutoLockPixels thumbnail_lock(thumbnail); |
68 bool encoded = JPEGCodec::Encode( | 73 bool encoded = JPEGCodec::Encode( |
69 reinterpret_cast<unsigned char*>(thumbnail.getAddr32(0, 0)), | 74 reinterpret_cast<unsigned char*>(thumbnail.getAddr32(0, 0)), |
70 JPEGCodec::FORMAT_BGRA, thumbnail.width(), | 75 JPEGCodec::FORMAT_BGRA, thumbnail.width(), |
71 thumbnail.height(), | 76 thumbnail.height(), |
72 static_cast<int>(thumbnail.rowBytes()), 90, | 77 static_cast<int>(thumbnail.rowBytes()), 90, |
73 &jpeg_data->data); | 78 &jpeg_data->data); |
74 | 79 |
75 base::TimeDelta delta = base::TimeTicks::Now() - encode_start; | 80 base::TimeDelta delta = base::TimeTicks::Now() - encode_start; |
76 HISTOGRAM_TIMES("Thumbnail.Encode", delta); | 81 HISTOGRAM_TIMES("Thumbnail.Encode", delta); |
77 | 82 |
78 if (!encoded) | 83 if (!encoded) |
79 return false; | 84 return false; |
80 | 85 |
81 // Update the cache_ with the new thumbnail. | 86 // Update the cache_ with the new thumbnail. |
82 (*cache_)[url] = std::make_pair(jpeg_data, score); | 87 (*cache_)[url] = CacheEntry(jpeg_data, score, true); |
83 | 88 |
84 // Write the new thumbnail data to disk in the background on file_thread. | |
85 if (write_to_disk) { | |
86 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, | |
87 NewRunnableMethod(this, &ThumbnailStore::WriteThumbnailToDisk, url, | |
88 jpeg_data, score)); | |
89 } | |
90 return true; | 89 return true; |
91 } | 90 } |
92 | 91 |
93 bool ThumbnailStore::GetPageThumbnail( | 92 bool ThumbnailStore::GetPageThumbnail( |
94 const GURL& url, | 93 const GURL& url, |
95 RefCountedBytes** data) { | 94 RefCountedBytes** data) { |
96 if (!cache_initialized_ || IsURLBlacklisted(url)) | 95 if (!cache_.get() || IsURLBlacklisted(url)) |
97 return false; | 96 return false; |
98 | 97 |
99 // Look up the |url| in the redirect list to find the final destination | 98 // Look up the |url| in the redirect list to find the final destination |
100 // which is the key into the |cache_|. | 99 // which is the key into the |cache_|. |
101 history::RedirectMap::iterator it = redirect_urls_->find(url); | 100 history::RedirectMap::iterator it = redirect_urls_->find(url); |
102 if (it == redirect_urls_->end()) | 101 if (it != redirect_urls_->end()) { |
103 return false; | 102 // Return the first available thumbnail starting at the end of the |
104 | 103 // redirect list. |
105 // Return the first available thumbnail starting at the end of the | 104 history::RedirectList::reverse_iterator rit; |
106 // redirect list. | 105 for (rit = it->second->data.rbegin(); |
107 history::RedirectList::reverse_iterator rit; | 106 rit != it->second->data.rend(); ++rit) { |
108 for (rit = it->second->data.rbegin(); | 107 if (cache_->find(*rit) != cache_->end()) { |
109 rit != it->second->data.rend(); ++rit) { | 108 *data = (*cache_)[*rit].data_.get(); |
110 if (cache_->find(*rit) != cache_->end()) { | 109 (*data)->AddRef(); |
111 *data = (*cache_)[*rit].first; | 110 return true; |
112 (*data)->AddRef(); | 111 } |
113 return true; | |
114 } | 112 } |
115 } | 113 } |
116 | 114 |
117 // TODO(meelapshah) bug 14643: check past redirect lists | 115 // TODO(meelapshah) bug 14643: check past redirect lists |
118 | 116 |
119 if (cache_->find(url) == cache_->end()) | 117 if (cache_->find(url) == cache_->end()) |
120 return false; | 118 return false; |
121 | 119 |
122 *data = (*cache_)[url].first; | 120 *data = (*cache_)[url].data_.get(); |
123 (*data)->AddRef(); | 121 (*data)->AddRef(); |
124 return true; | 122 return true; |
125 } | 123 } |
126 | 124 |
127 void ThumbnailStore::UpdateURLData() { | 125 void ThumbnailStore::UpdateURLData() { |
128 int result_count = ThumbnailStore::kMaxCacheSize + url_blacklist_->GetSize(); | 126 int result_count = ThumbnailStore::kMaxCacheSize + url_blacklist_->GetSize(); |
129 hs_->QueryTopURLsAndRedirects(result_count, &consumer_, | 127 hs_->QueryTopURLsAndRedirects(result_count, &consumer_, |
130 NewCallback(this, &ThumbnailStore::OnURLDataAvailable)); | 128 NewCallback(this, &ThumbnailStore::OnURLDataAvailable)); |
131 } | 129 } |
132 | 130 |
133 void ThumbnailStore::OnURLDataAvailable(std::vector<GURL>* urls, | 131 void ThumbnailStore::OnURLDataAvailable(std::vector<GURL>* urls, |
134 history::RedirectMap* redirects) { | 132 history::RedirectMap* redirects) { |
135 DCHECK(urls); | 133 DCHECK(urls); |
136 DCHECK(redirects); | 134 DCHECK(redirects); |
137 | 135 |
138 most_visited_urls_.reset(new std::vector<GURL>(*urls)); | 136 most_visited_urls_.reset(new std::vector<GURL>(*urls)); |
139 redirect_urls_.reset(new history::RedirectMap(*redirects)); | 137 redirect_urls_.reset(new history::RedirectMap(*redirects)); |
140 CleanCacheData(); | 138 CleanCacheData(); |
141 } | 139 } |
142 | 140 |
143 void ThumbnailStore::CleanCacheData() { | 141 void ThumbnailStore::CleanCacheData() { |
144 if (!cache_initialized_) | 142 if (!cache_.get()) |
145 return; | 143 return; |
146 | 144 |
147 // For each URL in the cache, search the RedirectMap for the originating URL. | 145 // For each URL in the cache, search the RedirectMap for the originating URL. |
148 // If this URL is blacklisted or not in the most visited list, delete the | 146 // If this URL is blacklisted or not in the most visited list, delete the |
149 // thumbnail data for it from the cache and from disk in the background. | 147 // thumbnail data for it from the cache and from disk in the background. |
150 scoped_refptr<RefCountedVector<GURL> > old_urls = new RefCountedVector<GURL>; | 148 scoped_refptr<RefCountedVector<GURL> > old_urls = new RefCountedVector<GURL>; |
151 for (ThumbnailStore::Cache::iterator cache_it = cache_->begin(); | 149 for (Cache::iterator cache_it = cache_->begin(); |
152 cache_it != cache_->end();) { | 150 cache_it != cache_->end();) { |
153 const GURL* url = NULL; | 151 const GURL* url = NULL; |
154 for (history::RedirectMap::iterator it = redirect_urls_->begin(); | 152 for (history::RedirectMap::iterator it = redirect_urls_->begin(); |
155 it != redirect_urls_->end(); ++it) { | 153 it != redirect_urls_->end(); ++it) { |
156 if (cache_it->first == it->first || | 154 if (cache_it->first == it->first || |
157 (it->second->data.size() && | 155 (it->second->data.size() && |
158 cache_it->first == it->second->data.back())) { | 156 cache_it->first == it->second->data.back())) { |
159 url = &it->first; | 157 url = &it->first; |
160 break; | 158 break; |
161 } | 159 } |
162 } | 160 } |
163 | 161 |
164 if (url == NULL || IsURLBlacklisted(*url) || !IsPopular(*url)) { | 162 if (url == NULL || IsURLBlacklisted(*url) || !IsPopular(*url)) { |
165 old_urls->data.push_back(cache_it->first); | 163 old_urls->data.push_back(cache_it->first); |
166 cache_->erase(cache_it++); | 164 cache_->erase(cache_it++); |
167 } else { | 165 } else { |
168 cache_it++; | 166 cache_it++; |
169 } | 167 } |
170 } | 168 } |
171 | 169 |
172 if (old_urls->data.size()) { | 170 if (old_urls->data.size()) { |
173 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, | 171 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, |
174 NewRunnableMethod(this, &ThumbnailStore::DeleteThumbnails, old_urls)); | 172 NewRunnableMethod(this, &ThumbnailStore::CommitCacheToDB, old_urls)); |
175 } | 173 } |
176 } | 174 } |
177 | 175 |
178 void ThumbnailStore::DeleteThumbnails( | 176 void ThumbnailStore::CommitCacheToDB( |
179 scoped_refptr<RefCountedVector<GURL> > thumbnail_urls) const { | 177 scoped_refptr<RefCountedVector<GURL> > stale_urls) const { |
180 for (std::vector<GURL>::iterator it = thumbnail_urls->data.begin(); | 178 if (!db_) |
181 it != thumbnail_urls->data.end(); ++it) | 179 return; |
182 file_util::Delete(file_path_.AppendASCII(MD5String(it->spec())), false); | 180 |
| 181 // Delete old thumbnails. |
| 182 if (stale_urls.get()) { |
| 183 for (std::vector<GURL>::iterator it = stale_urls->data.begin(); |
| 184 it != stale_urls->data.end(); ++it) { |
| 185 SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, |
| 186 "DELETE FROM thumbnails WHERE url=?"); |
| 187 statement->bind_string(0, it->spec()); |
| 188 if (statement->step() != SQLITE_DONE) |
| 189 NOTREACHED(); |
| 190 } |
| 191 } |
| 192 |
| 193 // Update cached thumbnails. |
| 194 for (Cache::iterator it = cache_->begin(); it != cache_->end(); ++it) { |
| 195 if (!it->second.dirty_) |
| 196 continue; |
| 197 |
| 198 SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, |
| 199 "INSERT OR REPLACE INTO thumbnails " |
| 200 "(url, boring_score, good_clipping, at_top, time_taken, data) " |
| 201 "VALUES (?,?,?,?,?,?)"); |
| 202 statement->bind_string(0, it->first.spec()); |
| 203 statement->bind_double(1, it->second.score_.boring_score); |
| 204 statement->bind_bool(2, it->second.score_.good_clipping); |
| 205 statement->bind_bool(3, it->second.score_.at_top); |
| 206 statement->bind_int64(4, it->second.score_.time_at_snapshot. |
| 207 ToInternalValue()); |
| 208 statement->bind_blob(5, &it->second.data_->data[0], |
| 209 static_cast<int>(it->second.data_->data.size())); |
| 210 if (statement->step() != SQLITE_DONE) |
| 211 DLOG(WARNING) << "Unable to insert thumbnail for URL"; |
| 212 else |
| 213 it->second.dirty_ = false; |
| 214 } |
183 } | 215 } |
184 | 216 |
185 void ThumbnailStore::GetAllThumbnailsFromDisk(FilePath filepath, | 217 void ThumbnailStore::InitializeFromDB(const FilePath& db_name, |
186 MessageLoop* cb_loop) { | 218 MessageLoop* cb_loop) { |
| 219 if (OpenSqliteDb(db_name, &db_) != SQLITE_OK) |
| 220 return; |
| 221 |
| 222 // Use a large page size since the thumbnails we are storing are typically |
| 223 // large, a small cache size since we cache in memory and don't go to disk |
| 224 // often, and take exclusive access since nobody else uses this db. |
| 225 sqlite3_exec(db_, "PRAGMA page_size=4096 " |
| 226 "PRAGMA cache_size=64 " |
| 227 "PRAGMA locking_mode=EXCLUSIVE", NULL, NULL, NULL); |
| 228 |
| 229 statement_cache_ = new SqliteStatementCache; |
| 230 |
| 231 // Use local DBCloseScoper so that if we cannot create the table and |
| 232 // need to return, the |db_| and |statement_cache_| are closed properly. |
| 233 history::DBCloseScoper scoper(&db_, &statement_cache_); |
| 234 |
| 235 if (!DoesSqliteTableExist(db_, "thumbnails")) { |
| 236 if (sqlite3_exec(db_, "CREATE TABLE thumbnails (" |
| 237 "url LONGVARCHAR PRIMARY KEY," |
| 238 "boring_score DOUBLE DEFAULT 1.0," |
| 239 "good_clipping INTEGER DEFAULT 0," |
| 240 "at_top INTEGER DEFAULT 0," |
| 241 "time_taken INTEGER DEFAULT 0," |
| 242 "data BLOB)", NULL, NULL, NULL) != SQLITE_OK) |
| 243 return; |
| 244 } |
| 245 |
| 246 statement_cache_->set_db(db_); |
| 247 |
| 248 // Now we can use a DBCloseScoper at the object scope. |
| 249 scoper.Detach(); |
| 250 close_scoper_.Attach(&db_, &statement_cache_); |
| 251 |
| 252 if (cb_loop) |
| 253 GetAllThumbnailsFromDisk(cb_loop); |
| 254 } |
| 255 |
| 256 void ThumbnailStore::GetAllThumbnailsFromDisk(MessageLoop* cb_loop) { |
187 ThumbnailStore::Cache* cache = new ThumbnailStore::Cache; | 257 ThumbnailStore::Cache* cache = new ThumbnailStore::Cache; |
188 | 258 |
189 // Create the specified directory if it does not exist. | 259 SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, |
190 if (!file_util::DirectoryExists(filepath)) { | 260 "SELECT * FROM thumbnails"); |
191 file_util::CreateDirectory(filepath); | |
192 } else { | |
193 // Walk the directory and read the thumbnail data from disk. | |
194 FilePath path; | |
195 GURL url; | |
196 RefCountedBytes* data; | |
197 ThumbnailScore score; | |
198 file_util::FileEnumerator fenum(filepath, false, | |
199 file_util::FileEnumerator::FILES); | |
200 | 261 |
201 while (!(path = fenum.Next()).empty()) { | 262 while (statement->step() == SQLITE_ROW) { |
202 data = new RefCountedBytes; | 263 GURL url(statement->column_string(0)); |
203 if (GetPageThumbnailFromDisk(path, &url, data, &score)) | 264 ThumbnailScore score(statement->column_double(1), // Boring score |
204 (*cache)[url] = std::make_pair(data, score); | 265 statement->column_bool(2), // Good clipping |
205 else | 266 statement->column_bool(3), // At top |
206 delete data; | 267 base::Time::FromInternalValue( |
207 } | 268 statement->column_int64(4))); // Time taken |
| 269 scoped_refptr<RefCountedBytes> data = new RefCountedBytes; |
| 270 if (statement->column_blob_as_vector(5, &data->data)) |
| 271 (*cache)[url] = CacheEntry(data, score, false); |
208 } | 272 } |
| 273 |
209 cb_loop->PostTask(FROM_HERE, | 274 cb_loop->PostTask(FROM_HERE, |
210 NewRunnableMethod(this, &ThumbnailStore::OnDiskDataAvailable, cache)); | 275 NewRunnableMethod(this, &ThumbnailStore::OnDiskDataAvailable, cache)); |
211 } | 276 } |
212 | 277 |
213 bool ThumbnailStore::GetPageThumbnailFromDisk(const FilePath& file, | |
214 GURL* url, | |
215 RefCountedBytes* data, | |
216 ThumbnailScore* score) const { | |
217 int64 file_size; | |
218 if (!file_util::GetFileSize(file, &file_size)) | |
219 return false; | |
220 | |
221 // Read the file into a buffer. | |
222 std::vector<char> file_data; | |
223 file_data.resize(static_cast<unsigned int>(file_size)); | |
224 if (file_util::ReadFile(file, &file_data[0], | |
225 static_cast<int>(file_size)) == -1) | |
226 return false; | |
227 | |
228 // Unpack the url, ThumbnailScore and JPEG size from the buffer. | |
229 std::string url_string; | |
230 unsigned int jpeg_len; | |
231 void* iter = NULL; | |
232 Pickle packed(&file_data[0], static_cast<int>(file_size)); | |
233 | |
234 if (!packed.ReadString(&iter, &url_string) || | |
235 !UnpackScore(score, packed, iter) || | |
236 !packed.ReadUInt32(&iter, &jpeg_len)) | |
237 return false; | |
238 | |
239 // Store the url to the out parameter. | |
240 GURL temp_url(url_string); | |
241 url->Swap(&temp_url); | |
242 | |
243 // Unpack the JPEG data from the buffer. | |
244 const char* jpeg_data = NULL; | |
245 int out_len; | |
246 | |
247 if (!packed.ReadData(&iter, &jpeg_data, &out_len) || | |
248 out_len != static_cast<int>(jpeg_len)) | |
249 return false; | |
250 | |
251 // Copy jpeg data to the out parameter. | |
252 data->data.resize(jpeg_len); | |
253 memcpy(&data->data[0], jpeg_data, jpeg_len); | |
254 | |
255 return true; | |
256 } | |
257 | |
258 void ThumbnailStore::OnDiskDataAvailable(ThumbnailStore::Cache* cache) { | 278 void ThumbnailStore::OnDiskDataAvailable(ThumbnailStore::Cache* cache) { |
259 if (cache) { | 279 if (cache) |
260 cache_.reset(cache); | 280 cache_.reset(cache); |
261 cache_initialized_ = true; | |
262 } | |
263 } | |
264 | |
265 bool ThumbnailStore::WriteThumbnailToDisk(const GURL& url, | |
266 scoped_refptr<RefCountedBytes> data, | |
267 const ThumbnailScore& score) const { | |
268 Pickle packed; | |
269 FilePath file = file_path_.AppendASCII(MD5String(url.spec())); | |
270 | |
271 // Pack the url, ThumbnailScore, and the JPEG data. | |
272 packed.WriteString(url.spec()); | |
273 PackScore(score, &packed); | |
274 packed.WriteUInt32(data->data.size()); | |
275 packed.WriteData(reinterpret_cast<char*>(&data->data[0]), data->data.size()); | |
276 | |
277 // Write the packed data to a file. | |
278 file_util::Delete(file, false); | |
279 return file_util::WriteFile(file, | |
280 reinterpret_cast<const char*>(packed.data()), | |
281 packed.size()) != -1; | |
282 } | |
283 | |
284 void ThumbnailStore::PackScore(const ThumbnailScore& score, | |
285 Pickle* packed) const { | |
286 // Pack the contents of the given ThumbnailScore into the given Pickle. | |
287 packed->WriteData(reinterpret_cast<const char*>(&score.boring_score), | |
288 sizeof(score.boring_score)); | |
289 packed->WriteBool(score.at_top); | |
290 packed->WriteBool(score.good_clipping); | |
291 packed->WriteInt64(score.time_at_snapshot.ToInternalValue()); | |
292 } | |
293 | |
294 bool ThumbnailStore::UnpackScore(ThumbnailScore* score, const Pickle& packed, | |
295 void*& iter) const { | |
296 // Unpack a ThumbnailScore from the given Pickle and iterator. | |
297 const char* boring = NULL; | |
298 int out_len; | |
299 int64 us; | |
300 | |
301 if (!packed.ReadData(&iter, &boring, &out_len) || | |
302 !packed.ReadBool(&iter, &score->at_top) || | |
303 !packed.ReadBool(&iter, &score->good_clipping) || | |
304 !packed.ReadInt64(&iter, &us)) | |
305 return false; | |
306 | |
307 if (out_len != sizeof(score->boring_score)) | |
308 return false; | |
309 | |
310 memcpy(&score->boring_score, boring, sizeof(score->boring_score)); | |
311 score->time_at_snapshot = base::Time::FromInternalValue(us); | |
312 return true; | |
313 } | 281 } |
314 | 282 |
315 bool ThumbnailStore::ShouldStoreThumbnailForURL(const GURL& url) const { | 283 bool ThumbnailStore::ShouldStoreThumbnailForURL(const GURL& url) const { |
316 if (IsURLBlacklisted(url) || cache_->size() >= ThumbnailStore::kMaxCacheSize) | 284 if (IsURLBlacklisted(url) || cache_->size() >= ThumbnailStore::kMaxCacheSize) |
317 return false; | 285 return false; |
318 | 286 |
319 return most_visited_urls_->size() < ThumbnailStore::kMaxCacheSize || | 287 return most_visited_urls_->size() < ThumbnailStore::kMaxCacheSize || |
320 IsPopular(url); | 288 IsPopular(url); |
321 } | 289 } |
322 | 290 |
323 bool ThumbnailStore::IsURLBlacklisted(const GURL& url) const { | 291 bool ThumbnailStore::IsURLBlacklisted(const GURL& url) const { |
324 if (url_blacklist_) | 292 if (url_blacklist_) |
325 return url_blacklist_->HasKey(GetDictionaryKeyForURL(url.spec())); | 293 return url_blacklist_->HasKey(GetDictionaryKeyForURL(url.spec())); |
326 return false; | 294 return false; |
327 } | 295 } |
328 | 296 |
329 std::wstring ThumbnailStore::GetDictionaryKeyForURL( | 297 std::wstring ThumbnailStore::GetDictionaryKeyForURL( |
330 const std::string& url) const { | 298 const std::string& url) const { |
331 return ASCIIToWide(MD5String(url)); | 299 return ASCIIToWide(MD5String(url)); |
332 } | 300 } |
333 | 301 |
334 bool ThumbnailStore::IsPopular(const GURL& url) const { | 302 bool ThumbnailStore::IsPopular(const GURL& url) const { |
335 return most_visited_urls_->end() != find(most_visited_urls_->begin(), | 303 return most_visited_urls_->end() != find(most_visited_urls_->begin(), |
336 most_visited_urls_->end(), | 304 most_visited_urls_->end(), |
337 url); | 305 url); |
338 } | 306 } |
OLD | NEW |