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" |
11 #include "base/file_util.h" | 12 #include "base/file_util.h" |
12 #include "base/gfx/jpeg_codec.h" | 13 #include "base/gfx/jpeg_codec.h" |
13 #include "base/md5.h" | 14 #include "base/md5.h" |
14 #include "base/string_util.h" | 15 #include "base/string_util.h" |
15 #include "base/thread.h" | 16 #include "base/thread.h" |
16 #include "base/values.h" | 17 #include "base/values.h" |
17 #include "chrome/browser/browser_process.h" | 18 #include "chrome/browser/browser_process.h" |
18 #include "chrome/browser/profile.h" | 19 #include "chrome/browser/profile.h" |
19 #include "chrome/common/pref_service.h" | 20 #include "chrome/common/pref_service.h" |
20 #include "chrome/common/sqlite_utils.h" | 21 #include "chrome/common/thumbnail_score.h" |
21 #include "googleurl/src/gurl.h" | 22 #include "googleurl/src/gurl.h" |
22 #include "third_party/skia/include/core/SkBitmap.h" | 23 #include "third_party/skia/include/core/SkBitmap.h" |
23 | 24 |
24 | 25 |
25 ThumbnailStore::ThumbnailStore() | 26 ThumbnailStore::ThumbnailStore() |
26 : cache_(NULL), | 27 : cache_(NULL), |
27 db_(NULL), | 28 cache_initialized_(false), |
28 hs_(NULL), | 29 hs_(NULL), |
29 url_blacklist_(NULL) { | 30 url_blacklist_(NULL) { |
30 } | 31 } |
31 | 32 |
32 ThumbnailStore::~ThumbnailStore() { | 33 ThumbnailStore::~ThumbnailStore() { |
33 CommitCacheToDB(NULL); | |
34 } | 34 } |
35 | 35 |
36 void ThumbnailStore::Init(const FilePath& db_name, | 36 void ThumbnailStore::Init(const FilePath& file_path, Profile* profile) { |
37 Profile* profile) { | 37 file_path_ = file_path; |
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. | |
44 hs_ = profile->GetHistoryService(Profile::EXPLICIT_ACCESS); | 38 hs_ = profile->GetHistoryService(Profile::EXPLICIT_ACCESS); |
45 | |
46 // Store a pointer to a persistent table of blacklisted URLs. | |
47 url_blacklist_ = profile->GetPrefs()-> | 39 url_blacklist_ = profile->GetPrefs()-> |
48 GetMutableDictionary(prefs::kNTPMostVisitedURLsBlacklist); | 40 GetMutableDictionary(prefs::kNTPMostVisitedURLsBlacklist); |
49 | 41 |
50 // Get the list of most visited URLs and redirect information from the | 42 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, |
51 // HistoryService. | 43 NewRunnableMethod(this, &ThumbnailStore::GetAllThumbnailsFromDisk, |
| 44 file_path_, MessageLoop::current())); |
| 45 |
52 timer_.Start(base::TimeDelta::FromMinutes(30), this, | 46 timer_.Start(base::TimeDelta::FromMinutes(30), this, |
53 &ThumbnailStore::UpdateURLData); | 47 &ThumbnailStore::UpdateURLData); |
54 UpdateURLData(); | 48 UpdateURLData(); |
55 } | 49 } |
56 | 50 |
57 bool ThumbnailStore::SetPageThumbnail(const GURL& url, | 51 bool ThumbnailStore::SetPageThumbnail(const GURL& url, |
58 const SkBitmap& thumbnail, | 52 const SkBitmap& thumbnail, |
59 const ThumbnailScore& score) { | 53 const ThumbnailScore& score, |
60 if (!cache_.get()) | 54 bool write_to_disk) { |
| 55 if (!cache_initialized_) |
61 return false; | 56 return false; |
62 | 57 |
63 if (!ShouldStoreThumbnailForURL(url) || | 58 if (!ShouldStoreThumbnailForURL(url) || |
64 (cache_->find(url) != cache_->end() && | 59 (cache_->find(url) != cache_->end() && |
65 !ShouldReplaceThumbnailWith((*cache_)[url].score_, score))) | 60 !ShouldReplaceThumbnailWith((*cache_)[url].second, score))) |
66 return true; | 61 return true; |
67 | 62 |
68 base::TimeTicks encode_start = base::TimeTicks::Now(); | 63 base::TimeTicks encode_start = base::TimeTicks::Now(); |
69 | 64 |
70 // Encode the SkBitmap to jpeg. | 65 // Encode the SkBitmap to jpeg and add to cache. |
71 scoped_refptr<RefCountedBytes> jpeg_data = new RefCountedBytes; | 66 scoped_refptr<RefCountedBytes> jpeg_data = new RefCountedBytes; |
72 SkAutoLockPixels thumbnail_lock(thumbnail); | 67 SkAutoLockPixels thumbnail_lock(thumbnail); |
73 bool encoded = JPEGCodec::Encode( | 68 bool encoded = JPEGCodec::Encode( |
74 reinterpret_cast<unsigned char*>(thumbnail.getAddr32(0, 0)), | 69 reinterpret_cast<unsigned char*>(thumbnail.getAddr32(0, 0)), |
75 JPEGCodec::FORMAT_BGRA, thumbnail.width(), | 70 JPEGCodec::FORMAT_BGRA, thumbnail.width(), |
76 thumbnail.height(), | 71 thumbnail.height(), |
77 static_cast<int>(thumbnail.rowBytes()), 90, | 72 static_cast<int>(thumbnail.rowBytes()), 90, |
78 &jpeg_data->data); | 73 &jpeg_data->data); |
79 | 74 |
80 base::TimeDelta delta = base::TimeTicks::Now() - encode_start; | 75 base::TimeDelta delta = base::TimeTicks::Now() - encode_start; |
81 HISTOGRAM_TIMES("Thumbnail.Encode", delta); | 76 HISTOGRAM_TIMES("Thumbnail.Encode", delta); |
82 | 77 |
83 if (!encoded) | 78 if (!encoded) |
84 return false; | 79 return false; |
85 | 80 |
86 // Update the cache_ with the new thumbnail. | 81 // Update the cache_ with the new thumbnail. |
87 (*cache_)[url] = CacheEntry(jpeg_data, score, true); | 82 (*cache_)[url] = std::make_pair(jpeg_data, score); |
88 | 83 |
| 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 } |
89 return true; | 90 return true; |
90 } | 91 } |
91 | 92 |
92 bool ThumbnailStore::GetPageThumbnail( | 93 bool ThumbnailStore::GetPageThumbnail( |
93 const GURL& url, | 94 const GURL& url, |
94 RefCountedBytes** data) { | 95 RefCountedBytes** data) { |
95 if (!cache_.get() || IsURLBlacklisted(url)) | 96 if (!cache_initialized_ || IsURLBlacklisted(url)) |
96 return false; | 97 return false; |
97 | 98 |
98 // Look up the |url| in the redirect list to find the final destination | 99 // Look up the |url| in the redirect list to find the final destination |
99 // which is the key into the |cache_|. | 100 // which is the key into the |cache_|. |
100 history::RedirectMap::iterator it = redirect_urls_->find(url); | 101 history::RedirectMap::iterator it = redirect_urls_->find(url); |
101 if (it != redirect_urls_->end()) { | 102 if (it == redirect_urls_->end()) |
102 // Return the first available thumbnail starting at the end of the | 103 return false; |
103 // redirect list. | 104 |
104 history::RedirectList::reverse_iterator rit; | 105 // Return the first available thumbnail starting at the end of the |
105 for (rit = it->second->data.rbegin(); | 106 // redirect list. |
106 rit != it->second->data.rend(); ++rit) { | 107 history::RedirectList::reverse_iterator rit; |
107 if (cache_->find(*rit) != cache_->end()) { | 108 for (rit = it->second->data.rbegin(); |
108 *data = (*cache_)[*rit].data_.get(); | 109 rit != it->second->data.rend(); ++rit) { |
109 (*data)->AddRef(); | 110 if (cache_->find(*rit) != cache_->end()) { |
110 return true; | 111 *data = (*cache_)[*rit].first; |
111 } | 112 (*data)->AddRef(); |
| 113 return true; |
112 } | 114 } |
113 } | 115 } |
114 | 116 |
115 // TODO(meelapshah) bug 14643: check past redirect lists | 117 // TODO(meelapshah) bug 14643: check past redirect lists |
116 | 118 |
117 if (cache_->find(url) == cache_->end()) | 119 if (cache_->find(url) == cache_->end()) |
118 return false; | 120 return false; |
119 | 121 |
120 *data = (*cache_)[url].data_.get(); | 122 *data = (*cache_)[url].first; |
121 (*data)->AddRef(); | 123 (*data)->AddRef(); |
122 return true; | 124 return true; |
123 } | 125 } |
124 | 126 |
125 void ThumbnailStore::UpdateURLData() { | 127 void ThumbnailStore::UpdateURLData() { |
126 int result_count = ThumbnailStore::kMaxCacheSize + url_blacklist_->GetSize(); | 128 int result_count = ThumbnailStore::kMaxCacheSize + url_blacklist_->GetSize(); |
127 hs_->QueryTopURLsAndRedirects(result_count, &consumer_, | 129 hs_->QueryTopURLsAndRedirects(result_count, &consumer_, |
128 NewCallback(this, &ThumbnailStore::OnURLDataAvailable)); | 130 NewCallback(this, &ThumbnailStore::OnURLDataAvailable)); |
129 } | 131 } |
130 | 132 |
131 void ThumbnailStore::OnURLDataAvailable(std::vector<GURL>* urls, | 133 void ThumbnailStore::OnURLDataAvailable(std::vector<GURL>* urls, |
132 history::RedirectMap* redirects) { | 134 history::RedirectMap* redirects) { |
133 DCHECK(urls); | 135 DCHECK(urls); |
134 DCHECK(redirects); | 136 DCHECK(redirects); |
135 | 137 |
136 most_visited_urls_.reset(new std::vector<GURL>(*urls)); | 138 most_visited_urls_.reset(new std::vector<GURL>(*urls)); |
137 redirect_urls_.reset(new history::RedirectMap(*redirects)); | 139 redirect_urls_.reset(new history::RedirectMap(*redirects)); |
138 CleanCacheData(); | 140 CleanCacheData(); |
139 } | 141 } |
140 | 142 |
141 void ThumbnailStore::CleanCacheData() { | 143 void ThumbnailStore::CleanCacheData() { |
142 if (!cache_.get()) | 144 if (!cache_initialized_) |
143 return; | 145 return; |
144 | 146 |
145 // For each URL in the cache, search the RedirectMap for the originating URL. | 147 // For each URL in the cache, search the RedirectMap for the originating URL. |
146 // If this URL is blacklisted or not in the most visited list, delete the | 148 // If this URL is blacklisted or not in the most visited list, delete the |
147 // thumbnail data for it from the cache and from disk in the background. | 149 // thumbnail data for it from the cache and from disk in the background. |
148 scoped_refptr<RefCountedVector<GURL> > old_urls = new RefCountedVector<GURL>; | 150 scoped_refptr<RefCountedVector<GURL> > old_urls = new RefCountedVector<GURL>; |
149 for (Cache::iterator cache_it = cache_->begin(); | 151 for (ThumbnailStore::Cache::iterator cache_it = cache_->begin(); |
150 cache_it != cache_->end();) { | 152 cache_it != cache_->end();) { |
151 const GURL* url = NULL; | 153 const GURL* url = NULL; |
152 for (history::RedirectMap::iterator it = redirect_urls_->begin(); | 154 for (history::RedirectMap::iterator it = redirect_urls_->begin(); |
153 it != redirect_urls_->end(); ++it) { | 155 it != redirect_urls_->end(); ++it) { |
154 if (cache_it->first == it->first || | 156 if (cache_it->first == it->first || |
155 (it->second->data.size() && | 157 (it->second->data.size() && |
156 cache_it->first == it->second->data.back())) { | 158 cache_it->first == it->second->data.back())) { |
157 url = &it->first; | 159 url = &it->first; |
158 break; | 160 break; |
159 } | 161 } |
160 } | 162 } |
161 | 163 |
162 if (url == NULL || IsURLBlacklisted(*url) || !IsPopular(*url)) { | 164 if (url == NULL || IsURLBlacklisted(*url) || !IsPopular(*url)) { |
163 old_urls->data.push_back(cache_it->first); | 165 old_urls->data.push_back(cache_it->first); |
164 cache_->erase(cache_it++); | 166 cache_->erase(cache_it++); |
165 } else { | 167 } else { |
166 cache_it++; | 168 cache_it++; |
167 } | 169 } |
168 } | 170 } |
169 | 171 |
170 if (old_urls->data.size()) { | 172 if (old_urls->data.size()) { |
171 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, | 173 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, |
172 NewRunnableMethod(this, &ThumbnailStore::CommitCacheToDB, old_urls)); | 174 NewRunnableMethod(this, &ThumbnailStore::DeleteThumbnails, old_urls)); |
173 } | 175 } |
174 } | 176 } |
175 | 177 |
176 void ThumbnailStore::CommitCacheToDB( | 178 void ThumbnailStore::DeleteThumbnails( |
177 scoped_refptr<RefCountedVector<GURL> > stale_urls) const { | 179 scoped_refptr<RefCountedVector<GURL> > thumbnail_urls) const { |
178 if (!db_) | 180 for (std::vector<GURL>::iterator it = thumbnail_urls->data.begin(); |
179 return; | 181 it != thumbnail_urls->data.end(); ++it) |
| 182 file_util::Delete(file_path_.AppendASCII(MD5String(it->spec())), false); |
| 183 } |
180 | 184 |
181 // Delete old thumbnails. | 185 void ThumbnailStore::GetAllThumbnailsFromDisk(FilePath filepath, |
182 if (stale_urls.get()) { | 186 MessageLoop* cb_loop) { |
183 for (std::vector<GURL>::iterator it = stale_urls->data.begin(); | 187 ThumbnailStore::Cache* cache = new ThumbnailStore::Cache; |
184 it != stale_urls->data.end(); ++it) { | 188 |
185 SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, | 189 // Create the specified directory if it does not exist. |
186 "DELETE FROM thumbnails WHERE url=?"); | 190 if (!file_util::DirectoryExists(filepath)) { |
187 statement->bind_string(0, it->spec()); | 191 file_util::CreateDirectory(filepath); |
188 if (statement->step() != SQLITE_DONE) | 192 } else { |
189 NOTREACHED(); | 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 |
| 201 while (!(path = fenum.Next()).empty()) { |
| 202 data = new RefCountedBytes; |
| 203 if (GetPageThumbnailFromDisk(path, &url, data, &score)) |
| 204 (*cache)[url] = std::make_pair(data, score); |
| 205 else |
| 206 delete data; |
190 } | 207 } |
191 } | 208 } |
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 } | |
215 } | |
216 | |
217 void ThumbnailStore::InitializeFromDB(const FilePath& db_name, | |
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) { | |
257 ThumbnailStore::Cache* cache = new ThumbnailStore::Cache; | |
258 | |
259 SQLITE_UNIQUE_STATEMENT(statement, *statement_cache_, | |
260 "SELECT * FROM thumbnails"); | |
261 | |
262 while (statement->step() == SQLITE_ROW) { | |
263 GURL url(statement->column_string(0)); | |
264 ThumbnailScore score(statement->column_double(1), // Boring score | |
265 statement->column_bool(2), // Good clipping | |
266 statement->column_bool(3), // At top | |
267 base::Time::FromInternalValue( | |
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); | |
272 } | |
273 | |
274 cb_loop->PostTask(FROM_HERE, | 209 cb_loop->PostTask(FROM_HERE, |
275 NewRunnableMethod(this, &ThumbnailStore::OnDiskDataAvailable, cache)); | 210 NewRunnableMethod(this, &ThumbnailStore::OnDiskDataAvailable, cache)); |
276 } | 211 } |
277 | 212 |
| 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 |
278 void ThumbnailStore::OnDiskDataAvailable(ThumbnailStore::Cache* cache) { | 258 void ThumbnailStore::OnDiskDataAvailable(ThumbnailStore::Cache* cache) { |
279 if (cache) | 259 if (cache) { |
280 cache_.reset(cache); | 260 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; |
281 } | 313 } |
282 | 314 |
283 bool ThumbnailStore::ShouldStoreThumbnailForURL(const GURL& url) const { | 315 bool ThumbnailStore::ShouldStoreThumbnailForURL(const GURL& url) const { |
284 if (IsURLBlacklisted(url) || cache_->size() >= ThumbnailStore::kMaxCacheSize) | 316 if (IsURLBlacklisted(url) || cache_->size() >= ThumbnailStore::kMaxCacheSize) |
285 return false; | 317 return false; |
286 | 318 |
287 return most_visited_urls_->size() < ThumbnailStore::kMaxCacheSize || | 319 return most_visited_urls_->size() < ThumbnailStore::kMaxCacheSize || |
288 IsPopular(url); | 320 IsPopular(url); |
289 } | 321 } |
290 | 322 |
291 bool ThumbnailStore::IsURLBlacklisted(const GURL& url) const { | 323 bool ThumbnailStore::IsURLBlacklisted(const GURL& url) const { |
292 if (url_blacklist_) | 324 if (url_blacklist_) |
293 return url_blacklist_->HasKey(GetDictionaryKeyForURL(url.spec())); | 325 return url_blacklist_->HasKey(GetDictionaryKeyForURL(url.spec())); |
294 return false; | 326 return false; |
295 } | 327 } |
296 | 328 |
297 std::wstring ThumbnailStore::GetDictionaryKeyForURL( | 329 std::wstring ThumbnailStore::GetDictionaryKeyForURL( |
298 const std::string& url) const { | 330 const std::string& url) const { |
299 return ASCIIToWide(MD5String(url)); | 331 return ASCIIToWide(MD5String(url)); |
300 } | 332 } |
301 | 333 |
302 bool ThumbnailStore::IsPopular(const GURL& url) const { | 334 bool ThumbnailStore::IsPopular(const GURL& url) const { |
303 return most_visited_urls_->end() != find(most_visited_urls_->begin(), | 335 return most_visited_urls_->end() != find(most_visited_urls_->begin(), |
304 most_visited_urls_->end(), | 336 most_visited_urls_->end(), |
305 url); | 337 url); |
306 } | 338 } |
OLD | NEW |