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/pickle.h" |
12 #include "base/file_util.h" | 12 #include "base/file_util.h" |
13 #include "base/gfx/jpeg_codec.h" | 13 #include "base/gfx/jpeg_codec.h" |
14 #include "base/md5.h" | 14 #include "base/md5.h" |
15 #include "base/string_util.h" | 15 #include "base/string_util.h" |
16 #include "base/thread.h" | 16 #include "base/thread.h" |
17 #include "base/values.h" | 17 #include "base/values.h" |
18 #include "chrome/browser/browser_process.h" | 18 #include "chrome/browser/browser_process.h" |
19 #include "chrome/browser/history/page_usage_data.h" | |
20 #include "chrome/browser/profile.h" | 19 #include "chrome/browser/profile.h" |
21 #include "chrome/common/pref_service.h" | 20 #include "chrome/common/pref_service.h" |
22 #include "chrome/common/thumbnail_score.h" | 21 #include "chrome/common/thumbnail_score.h" |
23 #include "googleurl/src/gurl.h" | 22 #include "googleurl/src/gurl.h" |
24 #include "third_party/skia/include/core/SkBitmap.h" | 23 #include "third_party/skia/include/core/SkBitmap.h" |
25 | 24 |
26 | 25 |
27 ThumbnailStore::ThumbnailStore() | 26 ThumbnailStore::ThumbnailStore() |
28 : cache_(NULL), | 27 : cache_(NULL), |
29 cache_initialized_(false), | 28 cache_initialized_(false), |
30 hs_(NULL), | 29 hs_(NULL), |
31 url_blacklist_(NULL) { | 30 url_blacklist_(NULL) { |
32 } | 31 } |
33 | 32 |
34 ThumbnailStore::~ThumbnailStore() { | 33 ThumbnailStore::~ThumbnailStore() { |
35 } | 34 } |
36 | 35 |
37 void ThumbnailStore::Init(const FilePath& file_path, Profile* profile) { | 36 void ThumbnailStore::Init(const FilePath& file_path, Profile* profile) { |
38 file_path_ = file_path; | 37 file_path_ = file_path; |
39 hs_ = profile->GetHistoryService(Profile::EXPLICIT_ACCESS); | 38 hs_ = profile->GetHistoryService(Profile::EXPLICIT_ACCESS); |
40 url_blacklist_ = profile->GetPrefs()-> | 39 url_blacklist_ = profile->GetPrefs()-> |
41 GetMutableDictionary(prefs::kNTPMostVisitedURLsBlacklist); | 40 GetMutableDictionary(prefs::kNTPMostVisitedURLsBlacklist); |
42 | 41 |
43 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, | 42 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, |
44 NewRunnableMethod(this, &ThumbnailStore::GetAllThumbnailsFromDisk, | 43 NewRunnableMethod(this, &ThumbnailStore::GetAllThumbnailsFromDisk, |
45 file_path_, MessageLoop::current())); | 44 file_path_, MessageLoop::current())); |
46 | 45 |
47 timer_.Start(base::TimeDelta::FromMinutes(30), this, | 46 timer_.Start(base::TimeDelta::FromMinutes(30), this, |
48 &ThumbnailStore::UpdateMostVisited); | 47 &ThumbnailStore::UpdateURLData); |
49 UpdateMostVisited(); | 48 UpdateURLData(); |
50 } | |
51 | |
52 void ThumbnailStore::GetAllThumbnailsFromDisk(FilePath filepath, | |
53 MessageLoop* cb_loop) { | |
54 ThumbnailStore::Cache* cache = new ThumbnailStore::Cache; | |
55 | |
56 // Create the specified directory if it does not exist. | |
57 if (!file_util::DirectoryExists(filepath)) { | |
58 file_util::CreateDirectory(filepath); | |
59 } else { | |
60 // Walk the directory and read the thumbnail data from disk. | |
61 FilePath path; | |
62 GURL url; | |
63 RefCountedBytes* data; | |
64 ThumbnailScore score; | |
65 file_util::FileEnumerator fenum(filepath, false, | |
66 file_util::FileEnumerator::FILES); | |
67 | |
68 while (!(path = fenum.Next()).empty()) { | |
69 data = new RefCountedBytes; | |
70 if (GetPageThumbnailFromDisk(path, &url, data, &score)) | |
71 (*cache)[url] = std::make_pair(data, score); | |
72 else | |
73 delete data; | |
74 } | |
75 } | |
76 cb_loop->PostTask(FROM_HERE, | |
77 NewRunnableMethod(this, &ThumbnailStore::OnDiskDataAvailable, cache)); | |
78 } | |
79 | |
80 bool ThumbnailStore::GetPageThumbnailFromDisk(const FilePath& file, | |
81 GURL* url, | |
82 RefCountedBytes* data, | |
83 ThumbnailScore* score) const { | |
84 int64 file_size; | |
85 if (!file_util::GetFileSize(file, &file_size)) | |
86 return false; | |
87 | |
88 // Read the file into a buffer. | |
89 std::vector<char> file_data; | |
90 file_data.resize(static_cast<unsigned int>(file_size)); | |
91 if (file_util::ReadFile(file, &file_data[0], | |
92 static_cast<int>(file_size)) == -1) | |
93 return false; | |
94 | |
95 // Unpack the url, ThumbnailScore and JPEG size from the buffer. | |
96 std::string url_string; | |
97 unsigned int jpeg_len; | |
98 void* iter = NULL; | |
99 Pickle packed(&file_data[0], static_cast<int>(file_size)); | |
100 | |
101 if (!packed.ReadString(&iter, &url_string) || | |
102 !UnpackScore(score, packed, iter) || | |
103 !packed.ReadUInt32(&iter, &jpeg_len)) | |
104 return false; | |
105 | |
106 // Store the url to the out parameter. | |
107 GURL temp_url(url_string); | |
108 url->Swap(&temp_url); | |
109 | |
110 // Unpack the JPEG data from the buffer. | |
111 const char* jpeg_data = NULL; | |
112 int out_len; | |
113 | |
114 if (!packed.ReadData(&iter, &jpeg_data, &out_len) || | |
115 out_len != static_cast<int>(jpeg_len)) | |
116 return false; | |
117 | |
118 // Copy jpeg data to the out parameter. | |
119 data->data.resize(jpeg_len); | |
120 memcpy(&data->data[0], jpeg_data, jpeg_len); | |
121 | |
122 return true; | |
123 } | |
124 | |
125 void ThumbnailStore::OnDiskDataAvailable(ThumbnailStore::Cache* cache) { | |
126 if (cache) { | |
127 cache_.reset(cache); | |
128 cache_initialized_ = true; | |
129 } | |
130 } | 49 } |
131 | 50 |
132 bool ThumbnailStore::SetPageThumbnail(const GURL& url, | 51 bool ThumbnailStore::SetPageThumbnail(const GURL& url, |
133 const SkBitmap& thumbnail, | 52 const SkBitmap& thumbnail, |
134 const ThumbnailScore& score, | 53 const ThumbnailScore& score, |
135 bool write_to_disk) { | 54 bool write_to_disk) { |
136 if (!cache_initialized_) | 55 if (!cache_initialized_) |
137 return false; | 56 return false; |
138 | 57 |
139 if (!ShouldStoreThumbnailForURL(url) || | 58 if (!ShouldStoreThumbnailForURL(url) || |
(...skipping 24 matching lines...) Expand all Loading... |
164 | 83 |
165 // Write the new thumbnail data to disk in the background on file_thread. | 84 // Write the new thumbnail data to disk in the background on file_thread. |
166 if (write_to_disk) { | 85 if (write_to_disk) { |
167 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, | 86 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, |
168 NewRunnableMethod(this, &ThumbnailStore::WriteThumbnailToDisk, url, | 87 NewRunnableMethod(this, &ThumbnailStore::WriteThumbnailToDisk, url, |
169 jpeg_data, score)); | 88 jpeg_data, score)); |
170 } | 89 } |
171 return true; | 90 return true; |
172 } | 91 } |
173 | 92 |
174 bool ThumbnailStore::WriteThumbnailToDisk(const GURL& url, | 93 bool ThumbnailStore::GetPageThumbnail( |
175 scoped_refptr<RefCountedBytes> data, | |
176 const ThumbnailScore& score) const { | |
177 Pickle packed; | |
178 FilePath file = file_path_.AppendASCII(MD5String(url.spec())); | |
179 | |
180 // Pack the url, ThumbnailScore, and the JPEG data. | |
181 packed.WriteString(url.spec()); | |
182 PackScore(score, &packed); | |
183 packed.WriteUInt32(data->data.size()); | |
184 packed.WriteData(reinterpret_cast<char*>(&data->data[0]), data->data.size()); | |
185 | |
186 // Write the packed data to a file. | |
187 file_util::Delete(file, false); | |
188 return file_util::WriteFile(file, | |
189 reinterpret_cast<const char*>(packed.data()), | |
190 packed.size()) != -1; | |
191 } | |
192 | |
193 ThumbnailStore::GetStatus ThumbnailStore::GetPageThumbnail( | |
194 const GURL& url, | 94 const GURL& url, |
195 RefCountedBytes** data) { | 95 RefCountedBytes** data) { |
196 if (!cache_initialized_ || IsURLBlacklisted(url)) | 96 if (!cache_initialized_ || IsURLBlacklisted(url)) |
197 return ThumbnailStore::FAIL; | 97 return false; |
198 | 98 |
199 // We need to check if the URL was redirected so that we can return the | 99 // Look up the |url| in the redirect list to find the final destination |
200 // thumbnail for the final destination. Redirect information needs to be | 100 // which is the key into the |cache_|. |
201 // fetched asynchronously from the HistoryService and is stored in a map | 101 history::RedirectMap::iterator it = redirect_urls_->find(url); |
202 // of the form "url => {redirect1 -> redirect2 -> .... -> final url}". | 102 if (it == redirect_urls_->end()) |
203 // If the redirect info has not been cached, tell the caller to call | 103 return false; |
204 // GetPageThumbnailAsync instead which will wait for the redirect info | |
205 // and return the thumbnail data when it becomes available. | |
206 ThumbnailStore::RedirectMap::iterator it = redirect_urls_.find(url); | |
207 if (it == redirect_urls_.end()) | |
208 return ThumbnailStore::ASYNC; | |
209 | 104 |
210 // Return the first available thumbnail starting at the end of the | 105 // Return the first available thumbnail starting at the end of the |
211 // redirect list. | 106 // redirect list. |
212 history::RedirectList::reverse_iterator rit; | 107 history::RedirectList::reverse_iterator rit; |
213 for (rit = it->second->data.rbegin(); | 108 for (rit = it->second->data.rbegin(); |
214 rit != it->second->data.rend(); ++rit) { | 109 rit != it->second->data.rend(); ++rit) { |
215 if (cache_->find(*rit) != cache_->end()) { | 110 if (cache_->find(*rit) != cache_->end()) { |
216 *data = (*cache_)[*rit].first; | 111 *data = (*cache_)[*rit].first; |
217 (*data)->AddRef(); | 112 (*data)->AddRef(); |
218 return ThumbnailStore::SUCCESS; | 113 return true; |
219 } | 114 } |
220 } | 115 } |
221 | 116 |
222 // TODO(meelapshah) bug 14643: check past redirect lists | 117 // TODO(meelapshah) bug 14643: check past redirect lists |
223 | 118 |
224 if (cache_->find(url) == cache_->end()) | 119 if (cache_->find(url) == cache_->end()) |
225 return ThumbnailStore::FAIL; | 120 return false; |
226 | 121 |
227 *data = (*cache_)[url].first; | 122 *data = (*cache_)[url].first; |
228 (*data)->AddRef(); | 123 (*data)->AddRef(); |
229 return ThumbnailStore::SUCCESS; | 124 return true; |
230 } | 125 } |
231 | 126 |
232 void ThumbnailStore::GetPageThumbnailAsync(const GURL& url, | 127 void ThumbnailStore::UpdateURLData() { |
233 int request_id, | 128 int result_count = ThumbnailStore::kMaxCacheSize + url_blacklist_->GetSize(); |
234 ThumbnailStore::ThumbnailDataCallback* cb) { | 129 hs_->QueryTopURLsAndRedirects(result_count, &consumer_, |
235 DCHECK(redirect_requests_.find(request_id) == redirect_requests_.end()); | 130 NewCallback(this, &ThumbnailStore::OnURLDataAvailable)); |
236 | |
237 HistoryService::Handle handle = hs_->QueryRedirectsFrom( | |
238 url, &hs_consumer_, | |
239 NewCallback(this, &ThumbnailStore::OnRedirectQueryComplete)); | |
240 hs_consumer_.SetClientData(hs_, handle, request_id); | |
241 redirect_requests_[request_id] = std::make_pair(cb, handle); | |
242 } | 131 } |
243 | 132 |
244 void ThumbnailStore::OnRedirectQueryComplete( | 133 void ThumbnailStore::OnURLDataAvailable(std::vector<GURL>* urls, |
245 HistoryService::Handle request_handle, | 134 history::RedirectMap* redirects) { |
246 GURL url, | 135 DCHECK(urls); |
247 bool success, | 136 DCHECK(redirects); |
248 history::RedirectList* redirects) { | |
249 if (!success) | |
250 return; | |
251 | 137 |
252 // Copy the redirects list returned by the HistoryService into our cache. | 138 most_visited_urls_.reset(new std::vector<GURL>(*urls)); |
253 redirect_urls_[url] = new RefCountedVector<GURL>(*redirects); | 139 redirect_urls_.reset(new history::RedirectMap(*redirects)); |
254 | |
255 // Get the request_id associated with this request. | |
256 int request_id = hs_consumer_.GetClientData(hs_, request_handle); | |
257 | |
258 // Return if no callback was associated with this redirect query. | |
259 // (The request for redirect info was made from UpdateMostVisited().) | |
260 if (request_id == -1) | |
261 return; | |
262 | |
263 // Run the callback if a thumbnail was requested for the URL. | |
264 ThumbnailStore::RequestMap::iterator it = | |
265 redirect_requests_.find(request_id); | |
266 if (it != redirect_requests_.end()) { | |
267 ThumbnailStore::ThumbnailDataCallback* cb = it->second.first; | |
268 RefCountedBytes* data = NULL; | |
269 | |
270 redirect_requests_.erase(it); | |
271 GetPageThumbnail(url, &data); | |
272 cb->Run(request_id, data); | |
273 } | |
274 } | |
275 | |
276 void ThumbnailStore::CancelPendingRequests( | |
277 const std::set<int>& pending_requests) { | |
278 ThumbnailStore::RequestMap::iterator req_it; | |
279 for (std::set<int>::const_iterator it = pending_requests.begin(); | |
280 it != pending_requests.end(); ++it) { | |
281 req_it = redirect_requests_.find(*it); | |
282 | |
283 // Cancel the request and delete the callback. | |
284 DCHECK(req_it != redirect_requests_.end()); | |
285 hs_->CancelRequest(req_it->second.second); | |
286 delete req_it->second.first; | |
287 redirect_requests_.erase(req_it); | |
288 } | |
289 } | |
290 | |
291 void ThumbnailStore::UpdateMostVisited() { | |
292 int result_count = ThumbnailStore::kMaxCacheSize; | |
293 if (url_blacklist_) | |
294 result_count += url_blacklist_->GetSize(); | |
295 | |
296 hs_->QuerySegmentUsageSince( | |
297 &cancelable_consumer_, | |
298 base::Time::Now() - | |
299 base::TimeDelta::FromDays(ThumbnailStore::kMostVisitedScope), | |
300 result_count, | |
301 NewCallback(this, &ThumbnailStore::OnMostVisitedURLsAvailable)); | |
302 } | |
303 | |
304 void ThumbnailStore::OnMostVisitedURLsAvailable( | |
305 CancelableRequestProvider::Handle handle, | |
306 std::vector<PageUsageData*>* data) { | |
307 most_visited_urls_.clear(); | |
308 | |
309 // Extract the top kMaxCacheSize + |url_blacklist_| most visited URLs. | |
310 GURL url; | |
311 size_t data_index = 0; | |
312 size_t output_index = 0; | |
313 | |
314 while (output_index < ThumbnailStore::kMaxCacheSize && | |
315 data_index < data->size()) { | |
316 url = (*data)[data_index]->GetURL(); | |
317 ++data_index; | |
318 | |
319 if (!IsURLBlacklisted(url)) { | |
320 most_visited_urls_.push_back(url); | |
321 ++output_index; | |
322 } | |
323 | |
324 // Preemptively fetch the redirect lists for the current URL if we don't | |
325 // already have it cached. | |
326 if (redirect_urls_.find(url) == redirect_urls_.end()) { | |
327 hs_->QueryRedirectsFrom(url, &hs_consumer_, | |
328 NewCallback(this, &ThumbnailStore::OnRedirectQueryComplete)); | |
329 } | |
330 } | |
331 CleanCacheData(); | 140 CleanCacheData(); |
332 } | 141 } |
333 | 142 |
334 void ThumbnailStore::CleanCacheData() { | 143 void ThumbnailStore::CleanCacheData() { |
335 if (!cache_initialized_) | 144 if (!cache_initialized_) |
336 return; | 145 return; |
337 | 146 |
338 // 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. |
339 // 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 |
340 // 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. |
341 scoped_refptr<RefCountedVector<GURL> > delete_me = new RefCountedVector<GURL>; | 150 scoped_refptr<RefCountedVector<GURL> > old_urls = new RefCountedVector<GURL>; |
342 for (ThumbnailStore::Cache::iterator cache_it = cache_->begin(); | 151 for (ThumbnailStore::Cache::iterator cache_it = cache_->begin(); |
343 cache_it != cache_->end();) { | 152 cache_it != cache_->end();) { |
344 const GURL* url = NULL; | 153 const GURL* url = NULL; |
345 for (ThumbnailStore::RedirectMap::iterator it = redirect_urls_.begin(); | 154 for (history::RedirectMap::iterator it = redirect_urls_->begin(); |
346 it != redirect_urls_.end(); ++it) { | 155 it != redirect_urls_->end(); ++it) { |
347 if (cache_it->first == it->first || | 156 if (cache_it->first == it->first || |
348 (it->second->data.size() && | 157 (it->second->data.size() && |
349 cache_it->first == it->second->data.back())) { | 158 cache_it->first == it->second->data.back())) { |
350 url = &it->first; | 159 url = &it->first; |
351 break; | 160 break; |
352 } | 161 } |
353 } | 162 } |
354 | 163 |
355 // If there was no entry in the RedirectMap for the URL cache_it->first, | 164 if (url == NULL || IsURLBlacklisted(*url) || !IsPopular(*url)) { |
356 // that means SetPageThumbnail was called but GetPageThumbnail was not | 165 old_urls->data.push_back(cache_it->first); |
357 // called. Since we do not have a reverse redirect lookup (i.e. we have | |
358 // a final destination such as http://www.google.com/ but we cannot get | |
359 // what the user typed such as google.com from it), we cannot | |
360 // check if this cache entry is blacklisted or if it is popular. | |
361 // TODO(meelapshah) bug 14644: Fix this. | |
362 if (url == NULL) { | |
363 cache_it++; | |
364 continue; | |
365 } | |
366 | |
367 if (IsURLBlacklisted(*url) || !IsPopular(*url)) { | |
368 delete_me->data.push_back(cache_it->first); | |
369 cache_->erase(cache_it++); | 166 cache_->erase(cache_it++); |
370 } else { | 167 } else { |
371 cache_it++; | 168 cache_it++; |
372 } | 169 } |
373 } | 170 } |
374 | 171 |
375 if (delete_me->data.size()) { | 172 if (old_urls->data.size()) { |
376 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, | 173 g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE, |
377 NewRunnableMethod(this, &ThumbnailStore::DeleteThumbnails, delete_me)); | 174 NewRunnableMethod(this, &ThumbnailStore::DeleteThumbnails, old_urls)); |
378 } | 175 } |
379 } | 176 } |
380 | 177 |
381 bool ThumbnailStore::ShouldStoreThumbnailForURL(const GURL& url) const { | 178 void ThumbnailStore::DeleteThumbnails( |
382 if (IsURLBlacklisted(url) || cache_->size() >= ThumbnailStore::kMaxCacheSize) | 179 scoped_refptr<RefCountedVector<GURL> > thumbnail_urls) const { |
| 180 for (std::vector<GURL>::iterator it = thumbnail_urls->data.begin(); |
| 181 it != thumbnail_urls->data.end(); ++it) |
| 182 file_util::Delete(file_path_.AppendASCII(MD5String(it->spec())), false); |
| 183 } |
| 184 |
| 185 void ThumbnailStore::GetAllThumbnailsFromDisk(FilePath filepath, |
| 186 MessageLoop* cb_loop) { |
| 187 ThumbnailStore::Cache* cache = new ThumbnailStore::Cache; |
| 188 |
| 189 // Create the specified directory if it does not exist. |
| 190 if (!file_util::DirectoryExists(filepath)) { |
| 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 |
| 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; |
| 207 } |
| 208 } |
| 209 cb_loop->PostTask(FROM_HERE, |
| 210 NewRunnableMethod(this, &ThumbnailStore::OnDiskDataAvailable, cache)); |
| 211 } |
| 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)) |
383 return false; | 219 return false; |
384 | 220 |
385 return most_visited_urls_.size() < ThumbnailStore::kMaxCacheSize || | 221 // Read the file into a buffer. |
386 IsPopular(url); | 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) { |
| 259 if (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; |
387 } | 282 } |
388 | 283 |
389 void ThumbnailStore::PackScore(const ThumbnailScore& score, | 284 void ThumbnailStore::PackScore(const ThumbnailScore& score, |
390 Pickle* packed) const { | 285 Pickle* packed) const { |
391 // Pack the contents of the given ThumbnailScore into the given Pickle. | 286 // Pack the contents of the given ThumbnailScore into the given Pickle. |
392 packed->WriteData(reinterpret_cast<const char*>(&score.boring_score), | 287 packed->WriteData(reinterpret_cast<const char*>(&score.boring_score), |
393 sizeof(score.boring_score)); | 288 sizeof(score.boring_score)); |
394 packed->WriteBool(score.at_top); | 289 packed->WriteBool(score.at_top); |
395 packed->WriteBool(score.good_clipping); | 290 packed->WriteBool(score.good_clipping); |
396 packed->WriteInt64(score.time_at_snapshot.ToInternalValue()); | 291 packed->WriteInt64(score.time_at_snapshot.ToInternalValue()); |
(...skipping 13 matching lines...) Expand all Loading... |
410 return false; | 305 return false; |
411 | 306 |
412 if (out_len != sizeof(score->boring_score)) | 307 if (out_len != sizeof(score->boring_score)) |
413 return false; | 308 return false; |
414 | 309 |
415 memcpy(&score->boring_score, boring, sizeof(score->boring_score)); | 310 memcpy(&score->boring_score, boring, sizeof(score->boring_score)); |
416 score->time_at_snapshot = base::Time::FromInternalValue(us); | 311 score->time_at_snapshot = base::Time::FromInternalValue(us); |
417 return true; | 312 return true; |
418 } | 313 } |
419 | 314 |
420 void ThumbnailStore::DeleteThumbnails( | 315 bool ThumbnailStore::ShouldStoreThumbnailForURL(const GURL& url) const { |
421 scoped_refptr<RefCountedVector<GURL> > thumbnail_urls) const { | 316 if (IsURLBlacklisted(url) || cache_->size() >= ThumbnailStore::kMaxCacheSize) |
422 for (std::vector<GURL>::iterator it = thumbnail_urls->data.begin(); | 317 return false; |
423 it != thumbnail_urls->data.end(); ++it) | 318 |
424 file_util::Delete(file_path_.AppendASCII(MD5String(it->spec())), false); | 319 return most_visited_urls_->size() < ThumbnailStore::kMaxCacheSize || |
| 320 IsPopular(url); |
425 } | 321 } |
426 | 322 |
427 bool ThumbnailStore::IsURLBlacklisted(const GURL& url) const { | 323 bool ThumbnailStore::IsURLBlacklisted(const GURL& url) const { |
428 if (url_blacklist_) | 324 if (url_blacklist_) |
429 return url_blacklist_->HasKey(GetDictionaryKeyForURL(url.spec())); | 325 return url_blacklist_->HasKey(GetDictionaryKeyForURL(url.spec())); |
430 return false; | 326 return false; |
431 } | 327 } |
432 | 328 |
433 std::wstring ThumbnailStore::GetDictionaryKeyForURL( | 329 std::wstring ThumbnailStore::GetDictionaryKeyForURL( |
434 const std::string& url) const { | 330 const std::string& url) const { |
435 return ASCIIToWide(MD5String(url)); | 331 return ASCIIToWide(MD5String(url)); |
436 } | 332 } |
437 | 333 |
438 bool ThumbnailStore::IsPopular(const GURL& url) const { | 334 bool ThumbnailStore::IsPopular(const GURL& url) const { |
439 return most_visited_urls_.end() != find(most_visited_urls_.begin(), | 335 return most_visited_urls_->end() != find(most_visited_urls_->begin(), |
440 most_visited_urls_.end(), | 336 most_visited_urls_->end(), |
441 url); | 337 url); |
442 } | 338 } |
OLD | NEW |