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

Side by Side Diff: chrome/browser/android/thumbnail/thumbnail_store.cc

Issue 262543002: android: add ThumbnailCache (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@codec
Patch Set: added DEPS file Created 6 years, 5 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
« no previous file with comments | « chrome/browser/android/thumbnail/thumbnail_store.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 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
5 #include "chrome/browser/android/thumbnail/thumbnail_store.h"
6
7 #include <algorithm>
8 #include <cmath>
9
10 #include "base/file_util.h"
11 #include "base/files/file.h"
12 #include "base/files/file_enumerator.h"
13 #include "base/files/file_path.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/time/time.h"
16 #include "content/public/browser/android/ui_resource_provider.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "third_party/android_opengl/etc1/etc1.h"
19 #include "third_party/skia/include/core/SkBitmap.h"
20 #include "third_party/skia/include/core/SkCanvas.h"
21 #include "third_party/skia/include/core/SkData.h"
22 #include "third_party/skia/include/core/SkMallocPixelRef.h"
23 #include "third_party/skia/include/core/SkPixelRef.h"
24 #include "ui/gfx/geometry/size_conversions.h"
25
26 namespace {
27
28 const float kApproximationScaleFactor = 4.f;
29 const base::TimeDelta kCaptureMinRequestTimeMs(
30 base::TimeDelta::FromMilliseconds(1000));
31
32 const int kCompressedKey = 0xABABABAB;
33
34 // Indicates whether we prefer to have more free CPU memory over GPU memory.
35 const bool kPreferCPUMemory = true;
36
37 // ETC1 texture sizes are multiples of four.
38 size_t NextETC1Size(size_t s) {
39 return (s / 4 + (s % 4 ? 1 : 0)) * 4;
40 }
41
42 gfx::Size GetEncodedSize(const gfx::Size& bitmap_size) {
43 return gfx::Size(NextETC1Size(bitmap_size.width()),
44 NextETC1Size(bitmap_size.height()));
45 }
46
47 } // anonymous namespace
48
49 ThumbnailStore::ThumbnailStore(const std::string& disk_cache_path_str,
50 size_t default_cache_size,
51 size_t approximation_cache_size,
52 size_t compression_queue_max_size,
53 size_t write_queue_max_size,
54 bool use_approximation_thumbnail)
55 : disk_cache_path_(disk_cache_path_str),
56 compression_queue_max_size_(compression_queue_max_size),
57 write_queue_max_size_(write_queue_max_size),
58 use_approximation_thumbnail_(use_approximation_thumbnail),
59 compression_tasks_count_(0),
60 write_tasks_count_(0),
61 read_in_progress_(false),
62 cache_(default_cache_size),
63 approximation_cache_(approximation_cache_size),
64 ui_resource_provider_(NULL),
65 compression_thread_("thumbnail_compression"),
66 weak_factory_(this) {
67 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
68 compression_thread_.Start();
69 }
70
71 ThumbnailStore::~ThumbnailStore() {
72 compression_thread_.Stop();
73 SetUIResourceProvider(NULL);
74 }
75
76 void ThumbnailStore::SetUIResourceProvider(
77 content::UIResourceProvider* ui_resource_provider) {
78 if (ui_resource_provider_ == ui_resource_provider)
79 return;
80
81 approximation_cache_.Clear();
82 cache_.Clear();
83
84 ui_resource_provider_ = ui_resource_provider;
85 }
86
87 void ThumbnailStore::AddThumbnailStoreObserver(
88 ThumbnailStoreObserver* observer) {
89 if (!observers_.HasObserver(observer))
90 observers_.AddObserver(observer);
91 }
92
93 void ThumbnailStore::RemoveThumbnailStoreObserver(
94 ThumbnailStoreObserver* observer) {
95 if (observers_.HasObserver(observer))
96 observers_.RemoveObserver(observer);
97 }
98
99 void ThumbnailStore::Put(TabId tab_id,
100 const SkBitmap& bitmap,
101 float thumbnail_scale) {
102 if (!ui_resource_provider_ || bitmap.empty() || thumbnail_scale <= 0)
103 return;
104
105 DCHECK(thumbnail_meta_data_.find(tab_id) != thumbnail_meta_data_.end());
106
107 base::Time time_stamp = thumbnail_meta_data_[tab_id].capture_time();
108 scoped_ptr<Thumbnail> thumbnail = Thumbnail::Create(
109 tab_id, time_stamp, thumbnail_scale, ui_resource_provider_, this);
110 thumbnail->SetBitmap(bitmap);
111
112 RemoveFromReadQueue(tab_id);
113 MakeSpaceForNewItemIfNecessary(tab_id);
114 cache_.Put(tab_id, thumbnail.Pass());
115
116 if (use_approximation_thumbnail_) {
117 std::pair<SkBitmap, float> approximation =
118 CreateApproximation(bitmap, thumbnail_scale);
119 scoped_ptr<Thumbnail> approx_thumbnail = Thumbnail::Create(
120 tab_id, time_stamp, approximation.second, ui_resource_provider_, this);
121 approx_thumbnail->SetBitmap(approximation.first);
122 approximation_cache_.Put(tab_id, approx_thumbnail.Pass());
123 }
124 CompressThumbnailIfNecessary(tab_id, time_stamp, bitmap, thumbnail_scale);
125 }
126
127 void ThumbnailStore::Remove(TabId tab_id) {
128 cache_.Remove(tab_id);
129 approximation_cache_.Remove(tab_id);
130 thumbnail_meta_data_.erase(tab_id);
131 RemoveFromDisk(tab_id);
132 RemoveFromReadQueue(tab_id);
133 }
134
135 Thumbnail* ThumbnailStore::Get(TabId tab_id, bool force_disk_read) {
136 Thumbnail* thumbnail = cache_.Get(tab_id);
137 if (thumbnail) {
138 thumbnail->CreateUIResource();
139 return thumbnail;
140 }
141
142 if (force_disk_read &&
143 std::find(visible_ids_.begin(), visible_ids_.end(), tab_id) !=
144 visible_ids_.end() &&
145 std::find(read_queue_.begin(), read_queue_.end(), tab_id) ==
146 read_queue_.end()) {
147 read_queue_.push_back(tab_id);
148 ReadNextThumbnail();
149 }
150
151 thumbnail = approximation_cache_.Get(tab_id);
152 if (thumbnail) {
153 thumbnail->CreateUIResource();
154 return thumbnail;
155 }
156
157 return NULL;
158 }
159
160 void ThumbnailStore::RemoveFromDiskAtAndAboveId(TabId min_id) {
161 base::Closure remove_task =
162 base::Bind(&ThumbnailStore::RemoveFromDiskAtAndAboveIdTask,
163 disk_cache_path_,
164 min_id);
165 content::BrowserThread::PostTask(
166 content::BrowserThread::FILE, FROM_HERE, remove_task);
167 }
168
169 void ThumbnailStore::InvalidateThumbnailIfChanged(TabId tab_id,
170 const GURL& url) {
171 ThumbnailMetaDataMap::iterator meta_data_iter =
172 thumbnail_meta_data_.find(tab_id);
173 if (meta_data_iter == thumbnail_meta_data_.end()) {
174 thumbnail_meta_data_[tab_id] = ThumbnailMetaData(base::Time(), url);
175 } else if (meta_data_iter->second.url() != url) {
176 Remove(tab_id);
177 }
178 }
179
180 bool ThumbnailStore::CheckAndUpdateThumbnailMetaData(TabId tab_id,
181 const GURL& url) {
182 base::Time current_time = base::Time::Now();
183 ThumbnailMetaDataMap::iterator meta_data_iter =
184 thumbnail_meta_data_.find(tab_id);
185 if (meta_data_iter != thumbnail_meta_data_.end() &&
186 meta_data_iter->second.url() == url &&
187 (current_time - meta_data_iter->second.capture_time()) <
188 kCaptureMinRequestTimeMs) {
189 return false;
190 }
191
192 thumbnail_meta_data_[tab_id] = ThumbnailMetaData(current_time, url);
193 return true;
194 }
195
196 void ThumbnailStore::UpdateVisibleIds(const TabIdList& priority) {
197 if (priority.empty()) {
198 visible_ids_.clear();
199 return;
200 }
201
202 size_t ids_size = std::min(priority.size(), cache_.MaximumCacheSize());
203 if (visible_ids_.size() == ids_size) {
204 // Early out if called with the same input as last time (We only care
205 // about the first mCache.MaximumCacheSize() entries).
206 bool lists_differ = false;
207 TabIdList::const_iterator visible_iter = visible_ids_.begin();
208 TabIdList::const_iterator priority_iter = priority.begin();
209 while (visible_iter != visible_ids_.end() &&
210 priority_iter != priority.end()) {
211 if (*priority_iter != *visible_iter) {
212 lists_differ = true;
213 break;
214 }
215 visible_iter++;
216 priority_iter++;
217 }
218
219 if (!lists_differ)
220 return;
221 }
222
223 read_queue_.clear();
224 visible_ids_.clear();
225 size_t count = 0;
226 TabIdList::const_iterator iter = priority.begin();
227 while (iter != priority.end() && count < ids_size) {
228 TabId tab_id = *iter;
229 visible_ids_.push_back(tab_id);
230 if (!cache_.Get(tab_id) &&
231 std::find(read_queue_.begin(), read_queue_.end(), tab_id) ==
232 read_queue_.end()) {
233 read_queue_.push_back(tab_id);
234 }
235 iter++;
236 count++;
237 }
238
239 ReadNextThumbnail();
240 }
241
242 void ThumbnailStore::RemoveFromDisk(TabId tab_id) {
243 base::FilePath file_path = GetFilePath(tab_id);
244 base::Closure task =
245 base::Bind(&ThumbnailStore::RemoveFromDiskTask, file_path);
246 content::BrowserThread::PostTask(
247 content::BrowserThread::FILE, FROM_HERE, task);
248 }
249
250 void ThumbnailStore::RemoveFromDiskTask(const base::FilePath& file_path) {
251 if (base::PathExists(file_path))
252 base::DeleteFile(file_path, false);
253 }
254
255 void ThumbnailStore::RemoveFromDiskAtAndAboveIdTask(
256 const base::FilePath& dir_path,
257 TabId min_id) {
258 base::FileEnumerator enumerator(dir_path, false, base::FileEnumerator::FILES);
259 while (true) {
260 base::FilePath path = enumerator.Next();
261 if (path.empty())
262 break;
263 base::FileEnumerator::FileInfo info = enumerator.GetInfo();
264 TabId tab_id;
265 bool success = base::StringToInt(info.GetName().value(), &tab_id);
266 if (success && tab_id >= min_id)
267 base::DeleteFile(path, false);
268 }
269 }
270
271 void ThumbnailStore::WriteThumbnailIfNecessary(
272 TabId tab_id,
273 skia::RefPtr<SkPixelRef> compressed_data,
274 float scale,
275 const gfx::Size& content_size) {
276 if (write_tasks_count_ >= write_queue_max_size_)
277 return;
278
279 write_tasks_count_++;
280
281 base::Callback<void()> post_write_task =
282 base::Bind(&ThumbnailStore::PostWriteTask, weak_factory_.GetWeakPtr());
283 content::BrowserThread::PostTask(content::BrowserThread::FILE,
284 FROM_HERE,
285 base::Bind(&ThumbnailStore::WriteTask,
286 GetFilePath(tab_id),
287 compressed_data,
288 scale,
289 content_size,
290 post_write_task));
291 }
292
293 void ThumbnailStore::CompressThumbnailIfNecessary(
294 TabId tab_id,
295 const base::Time& time_stamp,
296 const SkBitmap& bitmap,
297 float scale) {
298 if (compression_tasks_count_ >= compression_queue_max_size_) {
299 RemoveOnMatchedTimeStamp(tab_id, time_stamp);
300 return;
301 }
302
303 compression_tasks_count_++;
304 DCHECK(compression_thread_.message_loop_proxy());
305
306 base::Callback<void(skia::RefPtr<SkPixelRef>, const gfx::Size&)>
307 post_compression_task = base::Bind(&ThumbnailStore::PostCompressionTask,
308 weak_factory_.GetWeakPtr(),
309 tab_id,
310 time_stamp,
311 scale);
312
313 compression_thread_.message_loop_proxy()->PostTask(
314 FROM_HERE,
315 base::Bind(
316 &ThumbnailStore::CompressionTask, bitmap, post_compression_task));
317 }
318
319 void ThumbnailStore::ReadNextThumbnail() {
320 if (read_queue_.empty() || read_in_progress_)
321 return;
322
323 TabId tab_id = read_queue_.front();
324 read_in_progress_ = true;
325
326 base::FilePath file_path = GetFilePath(tab_id);
327
328 base::Callback<void(skia::RefPtr<SkPixelRef>, float, const gfx::Size&)>
329 post_read_task = base::Bind(
330 &ThumbnailStore::PostReadTask, weak_factory_.GetWeakPtr(), tab_id);
331
332 content::BrowserThread::PostTask(
333 content::BrowserThread::FILE,
334 FROM_HERE,
335 base::Bind(&ThumbnailStore::ReadTask, file_path, post_read_task));
336 }
337
338 void ThumbnailStore::MakeSpaceForNewItemIfNecessary(TabId tab_id) {
339 if (cache_.Get(tab_id) ||
340 std::find(visible_ids_.begin(), visible_ids_.end(), tab_id) ==
341 visible_ids_.end() ||
342 cache_.size() < cache_.MaximumCacheSize()) {
343 return;
344 }
345
346 TabId key_to_remove;
347 bool found_key_to_remove = false;
348
349 // 1. Find a cached item not in this list
350 for (ExpiringThumbnailCache::iterator iter = cache_.begin();
351 iter != cache_.end();
352 iter++) {
353 if (std::find(visible_ids_.begin(), visible_ids_.end(), iter->first) ==
354 visible_ids_.end()) {
355 key_to_remove = iter->first;
356 found_key_to_remove = true;
357 break;
358 }
359 }
360
361 if (!found_key_to_remove) {
362 // 2. Find the least important id we can remove.
363 for (TabIdList::reverse_iterator riter = visible_ids_.rbegin();
364 riter != visible_ids_.rend();
365 riter++) {
366 if (cache_.Get(*riter)) {
367 key_to_remove = *riter;
368 break;
369 found_key_to_remove = true;
370 }
371 }
372 }
373
374 if (found_key_to_remove)
375 cache_.Remove(key_to_remove);
376 }
377
378 void ThumbnailStore::RemoveFromReadQueue(TabId tab_id) {
379 TabIdList::iterator read_iter =
380 std::find(read_queue_.begin(), read_queue_.end(), tab_id);
381 if (read_iter != read_queue_.end())
382 read_queue_.erase(read_iter);
383 }
384
385 void ThumbnailStore::InvalidateCachedThumbnail(Thumbnail* thumbnail) {
386 DCHECK(thumbnail);
387 TabId tab_id = thumbnail->tab_id();
388 cc::UIResourceId uid = thumbnail->ui_resource_id();
389
390 Thumbnail* cached_thumbnail = cache_.Get(tab_id);
391 if (cached_thumbnail && cached_thumbnail->ui_resource_id() == uid)
392 cache_.Remove(tab_id);
393
394 cached_thumbnail = approximation_cache_.Get(tab_id);
395 if (cached_thumbnail && cached_thumbnail->ui_resource_id() == uid)
396 approximation_cache_.Remove(tab_id);
397 }
398
399 base::FilePath ThumbnailStore::GetFilePath(TabId tab_id) const {
400 return disk_cache_path_.Append(base::IntToString(tab_id));
401 }
402
403 void ThumbnailStore::WriteTask(const base::FilePath& file_path,
404 skia::RefPtr<SkPixelRef> compressed_data,
405 float scale,
406 const gfx::Size& content_size,
407 const base::Callback<void()>& post_write_task) {
408 DCHECK(compressed_data);
409
410 base::File file(file_path,
411 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
412 DCHECK(file.IsValid());
413
414 compressed_data->lockPixels();
415 bool success = true;
416 int content_width = content_size.width();
417 int content_height = content_size.height();
418 int data_width = compressed_data->info().width();
419 int data_height = compressed_data->info().height();
420
421 if (file.WriteAtCurrentPos(reinterpret_cast<const char*>(&kCompressedKey),
422 sizeof(int)) < 0 ||
423 file.WriteAtCurrentPos(reinterpret_cast<const char*>(&content_width),
424 sizeof(int)) < 0 ||
425 file.WriteAtCurrentPos(reinterpret_cast<const char*>(&content_height),
426 sizeof(int)) < 0 ||
427 file.WriteAtCurrentPos(reinterpret_cast<const char*>(&data_width),
428 sizeof(int)) < 0 ||
429 file.WriteAtCurrentPos(reinterpret_cast<const char*>(&data_height),
430 sizeof(int)) < 0 ||
431 file.WriteAtCurrentPos(reinterpret_cast<const char*>(&scale),
432 sizeof(float)) < 0) {
433 success = false;
434 }
435
436 size_t compressed_bytes = etc1_get_encoded_data_size(data_width, data_height);
437 if (file.WriteAtCurrentPos(reinterpret_cast<char*>(compressed_data->pixels()),
438 compressed_bytes) < 0)
439 success = false;
440
441 compressed_data->unlockPixels();
442
443 file.Close();
444
445 if (!success)
446 base::DeleteFile(file_path, false);
447
448 content::BrowserThread::PostTask(
449 content::BrowserThread::UI, FROM_HERE, post_write_task);
450 }
451
452 void ThumbnailStore::PostWriteTask() {
453 write_tasks_count_--;
454 }
455
456 void ThumbnailStore::CompressionTask(
457 SkBitmap raw_data,
458 const base::Callback<void(skia::RefPtr<SkPixelRef>, const gfx::Size&)>&
459 post_compression_task) {
460 skia::RefPtr<SkPixelRef> compressed_data;
461 gfx::Size content_size;
462
463 if (!raw_data.empty()) {
464 SkAutoLockPixels raw_data_lock(raw_data);
465 gfx::Size raw_data_size(raw_data.width(), raw_data.height());
466 size_t pixel_size = 4; // Pixel size is 4 bytes for kARGB_8888_Config.
467 size_t stride = pixel_size * raw_data_size.width();
468
469 gfx::Size encoded_size = GetEncodedSize(raw_data_size);
470 size_t encoded_bytes =
471 etc1_get_encoded_data_size(encoded_size.width(), encoded_size.height());
472 SkImageInfo info = {encoded_size.width(),
473 encoded_size.height(),
474 kUnknown_SkColorType,
475 kUnpremul_SkAlphaType};
476 skia::RefPtr<SkData> etc1_pixel_data = skia::AdoptRef(
477 SkData::NewFromMalloc(new uint8_t[encoded_bytes], encoded_bytes));
478 skia::RefPtr<SkMallocPixelRef> etc1_pixel_ref = skia::AdoptRef(
479 SkMallocPixelRef::NewWithData(info, 0, NULL, etc1_pixel_data.get()));
480
481 etc1_pixel_ref->lockPixels();
482 bool success = etc1_encode_image(
483 reinterpret_cast<unsigned char*>(raw_data.getPixels()),
484 raw_data_size.width(),
485 raw_data_size.height(),
486 pixel_size,
487 stride,
488 reinterpret_cast<unsigned char*>(etc1_pixel_ref->pixels()),
489 encoded_size.width(),
490 encoded_size.height());
491 etc1_pixel_ref->setImmutable();
492 etc1_pixel_ref->unlockPixels();
493
494 if (success) {
495 compressed_data = etc1_pixel_ref;
496 content_size = raw_data_size;
497 }
498 }
499
500 content::BrowserThread::PostTask(
501 content::BrowserThread::UI,
502 FROM_HERE,
503 base::Bind(post_compression_task, compressed_data, content_size));
504 }
505
506 void ThumbnailStore::PostCompressionTask(
507 TabId tab_id,
508 const base::Time& time_stamp,
509 float scale,
510 skia::RefPtr<SkPixelRef> compressed_data,
511 const gfx::Size& content_size) {
512 compression_tasks_count_--;
513 if (!compressed_data) {
514 RemoveOnMatchedTimeStamp(tab_id, time_stamp);
515 return;
516 }
517
518 Thumbnail* thumbnail = cache_.Get(tab_id);
519 if (thumbnail) {
520 if (thumbnail->time_stamp() != time_stamp)
521 return;
522 thumbnail->SetCompressedBitmap(compressed_data, content_size);
523 thumbnail->CreateUIResource();
524 }
525 WriteThumbnailIfNecessary(tab_id, compressed_data, scale, content_size);
526 }
527
528 void ThumbnailStore::ReadTask(
529 const base::FilePath& file_path,
530 const base::Callback<
531 void(skia::RefPtr<SkPixelRef>, float, const gfx::Size&)>&
532 post_read_task) {
533 skia::RefPtr<SkPixelRef> compressed_data;
534 float scale = 0.f;
535 gfx::Size content_size;
536
537 if (base::PathExists(file_path)) {
538 base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
539 DCHECK(file.IsValid());
540
541 int key;
542 bool success = true;
543 if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&key), sizeof(int)) < 0 ||
544 key != kCompressedKey)
545 success = false;
546
547 int width = 0;
548 int height = 0;
549 if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&width), sizeof(int)) <
550 0 ||
551 file.ReadAtCurrentPos(reinterpret_cast<char*>(&height), sizeof(int)) <
552 0)
553 success = false;
554
555 content_size = gfx::Size(width, height);
556 if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&width), sizeof(int)) <
557 0 ||
558 file.ReadAtCurrentPos(reinterpret_cast<char*>(&height), sizeof(int)) <
559 0)
560 success = false;
561
562 gfx::Size data_size(width, height);
563 if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&scale), sizeof(float)) <
564 0)
565 success = false;
566
567 size_t compressed_bytes =
568 etc1_get_encoded_data_size(data_size.width(), data_size.height());
569 SkImageInfo info = {data_size.width(),
570 data_size.height(),
571 kUnknown_SkColorType,
572 kUnpremul_SkAlphaType};
573
574 scoped_ptr<uint8_t[]> data(new uint8_t[compressed_bytes]);
575 if (file.ReadAtCurrentPos(reinterpret_cast<char*>(data.get()),
576 compressed_bytes) < 0)
577 success = false;
578
579 file.Close();
580
581 skia::RefPtr<SkData> etc1_pixel_data =
582 skia::AdoptRef(SkData::NewFromMalloc(data.release(), compressed_bytes));
583 compressed_data = skia::AdoptRef(
584 SkMallocPixelRef::NewWithData(info, 0, NULL, etc1_pixel_data.get()));
585
586 if (!success) {
587 compressed_data.clear();
588 content_size = gfx::Size();
589 scale = 0.f;
590 base::DeleteFile(file_path, false);
591 }
592 }
593
594 content::BrowserThread::PostTask(
595 content::BrowserThread::UI,
596 FROM_HERE,
597 base::Bind(post_read_task, compressed_data, scale, content_size));
598 }
599
600 void ThumbnailStore::PostReadTask(TabId tab_id,
601 skia::RefPtr<SkPixelRef> compressed_data,
602 float scale,
603 const gfx::Size& content_size) {
604 read_in_progress_ = false;
605
606 TabIdList::iterator iter =
607 std::find(read_queue_.begin(), read_queue_.end(), tab_id);
608 if (iter == read_queue_.end()) {
609 ReadNextThumbnail();
610 return;
611 }
612
613 read_queue_.erase(iter);
614
615 if (!cache_.Get(tab_id) && compressed_data) {
616 ThumbnailMetaDataMap::iterator meta_iter =
617 thumbnail_meta_data_.find(tab_id);
618 base::Time time_stamp = base::Time::Now();
619 if (meta_iter != thumbnail_meta_data_.end())
620 time_stamp = meta_iter->second.capture_time();
621
622 MakeSpaceForNewItemIfNecessary(tab_id);
623 scoped_ptr<Thumbnail> thumbnail = Thumbnail::Create(
624 tab_id, time_stamp, scale, ui_resource_provider_, this);
625 thumbnail->SetCompressedBitmap(compressed_data,
626 content_size);
627 if (kPreferCPUMemory)
628 thumbnail->CreateUIResource();
629
630 cache_.Put(tab_id, thumbnail.Pass());
631 NotifyObserversOfThumbnailRead(tab_id);
632 }
633
634 ReadNextThumbnail();
635 }
636
637 void ThumbnailStore::NotifyObserversOfThumbnailRead(TabId tab_id) {
638 FOR_EACH_OBSERVER(
639 ThumbnailStoreObserver, observers_, OnFinishedThumbnailRead(tab_id));
640 }
641
642 void ThumbnailStore::RemoveOnMatchedTimeStamp(TabId tab_id,
643 const base::Time& time_stamp) {
644 // We remove the cached version if it matches the tab_id and the time_stamp.
645 Thumbnail* thumbnail = cache_.Get(tab_id);
646 Thumbnail* approx_thumbnail = approximation_cache_.Get(tab_id);
647 if ((thumbnail && thumbnail->time_stamp() == time_stamp) ||
648 (approx_thumbnail && approx_thumbnail->time_stamp() == time_stamp)) {
649 Remove(tab_id);
650 }
651 return;
652 }
653
654 ThumbnailStore::ThumbnailMetaData::ThumbnailMetaData() {
655 }
656
657 ThumbnailStore::ThumbnailMetaData::ThumbnailMetaData(
658 const base::Time& current_time,
659 const GURL& url)
660 : capture_time_(current_time), url_(url) {
661 }
662
663 std::pair<SkBitmap, float> ThumbnailStore::CreateApproximation(
664 const SkBitmap& bitmap,
665 float scale) {
666 DCHECK(!bitmap.empty());
667 DCHECK_GT(scale, 0);
668 SkAutoLockPixels bitmap_lock(bitmap);
669 float new_scale = 1.f / kApproximationScaleFactor;
670
671 gfx::Size dst_size = gfx::ToFlooredSize(
672 gfx::ScaleSize(gfx::Size(bitmap.width(), bitmap.height()), new_scale));
673 SkBitmap dst_bitmap;
674 dst_bitmap.allocPixels(SkImageInfo::Make(dst_size.width(),
675 dst_size.height(),
676 bitmap.info().fColorType,
677 bitmap.info().fAlphaType));
678 dst_bitmap.eraseColor(0);
679 SkAutoLockPixels dst_bitmap_lock(dst_bitmap);
680
681 SkCanvas canvas(dst_bitmap);
682 canvas.scale(new_scale, new_scale);
683 canvas.drawBitmap(bitmap, 0, 0, NULL);
684 dst_bitmap.setImmutable();
685
686 return std::make_pair(dst_bitmap, new_scale * scale);
687 }
OLDNEW
« no previous file with comments | « chrome/browser/android/thumbnail/thumbnail_store.h ('k') | chrome/chrome_browser.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698