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

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

Issue 486093002: Fix thumbnail store crashing on loading old files (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 4 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 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/android/thumbnail/thumbnail_store.h" 5 #include "chrome/browser/android/thumbnail/thumbnail_store.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <cmath> 8 #include <cmath>
9 9
10 #include "base/big_endian.h"
10 #include "base/file_util.h" 11 #include "base/file_util.h"
11 #include "base/files/file.h" 12 #include "base/files/file.h"
12 #include "base/files/file_enumerator.h" 13 #include "base/files/file_enumerator.h"
13 #include "base/files/file_path.h" 14 #include "base/files/file_path.h"
14 #include "base/strings/string_number_conversions.h" 15 #include "base/strings/string_number_conversions.h"
15 #include "base/threading/worker_pool.h" 16 #include "base/threading/worker_pool.h"
16 #include "base/time/time.h" 17 #include "base/time/time.h"
17 #include "content/public/browser/android/ui_resource_provider.h" 18 #include "content/public/browser/android/ui_resource_provider.h"
18 #include "content/public/browser/browser_thread.h" 19 #include "content/public/browser/browser_thread.h"
19 #include "third_party/android_opengl/etc1/etc1.h" 20 #include "third_party/android_opengl/etc1/etc1.h"
20 #include "third_party/skia/include/core/SkBitmap.h" 21 #include "third_party/skia/include/core/SkBitmap.h"
21 #include "third_party/skia/include/core/SkCanvas.h" 22 #include "third_party/skia/include/core/SkCanvas.h"
22 #include "third_party/skia/include/core/SkData.h" 23 #include "third_party/skia/include/core/SkData.h"
23 #include "third_party/skia/include/core/SkMallocPixelRef.h" 24 #include "third_party/skia/include/core/SkMallocPixelRef.h"
24 #include "third_party/skia/include/core/SkPixelRef.h" 25 #include "third_party/skia/include/core/SkPixelRef.h"
25 #include "ui/gfx/geometry/size_conversions.h" 26 #include "ui/gfx/geometry/size_conversions.h"
26 27
27 namespace { 28 namespace {
28 29
29 const float kApproximationScaleFactor = 4.f; 30 const float kApproximationScaleFactor = 4.f;
30 const base::TimeDelta kCaptureMinRequestTimeMs( 31 const base::TimeDelta kCaptureMinRequestTimeMs(
31 base::TimeDelta::FromMilliseconds(1000)); 32 base::TimeDelta::FromMilliseconds(1000));
32 33
33 const int kCompressedKey = 0xABABABAB; 34 const int kCompressedKey = 0xABABABAB;
35 const int kCurrentExtraVersion = 1;
36 const int kMaxDimensionSize = 2048;
34 37
35 // Indicates whether we prefer to have more free CPU memory over GPU memory. 38 // Indicates whether we prefer to have more free CPU memory over GPU memory.
36 const bool kPreferCPUMemory = true; 39 const bool kPreferCPUMemory = true;
37 40
38 // TODO(): ETC1 texture sizes should be multiples of four, but some drivers only 41 // TODO(): ETC1 texture sizes should be multiples of four, but some drivers only
39 // allow power-of-two ETC1 textures. Find better work around. 42 // allow power-of-two ETC1 textures. Find better work around.
40 size_t NextPowerOfTwo(size_t x) { 43 size_t NextPowerOfTwo(size_t x) {
41 --x; 44 --x;
42 x |= x >> 1; 45 x |= x >> 1;
43 x |= x >> 2; 46 x |= x >> 2;
44 x |= x >> 4; 47 x |= x >> 4;
45 x |= x >> 8; 48 x |= x >> 8;
46 x |= x >> 16; 49 x |= x >> 16;
47 return x + 1; 50 return x + 1;
48 } 51 }
49 52
50 gfx::Size GetEncodedSize(const gfx::Size& bitmap_size) { 53 gfx::Size GetEncodedSize(const gfx::Size& bitmap_size) {
51 DCHECK(!bitmap_size.IsEmpty()); 54 DCHECK(!bitmap_size.IsEmpty());
52 return gfx::Size(NextPowerOfTwo(bitmap_size.width()), 55 return gfx::Size(NextPowerOfTwo(bitmap_size.width()),
53 NextPowerOfTwo(bitmap_size.height())); 56 NextPowerOfTwo(bitmap_size.height()));
54 } 57 }
55 58
59 template<typename T>
60 bool ReadBigEndianFromFile(base::File& file, T* out) {
61 char buffer[sizeof(T)];
62 if (file.ReadAtCurrentPos(buffer, sizeof(T)) != sizeof(T))
63 return false;
64
65 base::ReadBigEndian(buffer, out);
66 return true;
67 }
68
69 template<typename T>
70 bool WriteBigEndianToFile(base::File& file, T val) {
71 char buffer[sizeof(T)];
72 base::WriteBigEndian(buffer, val);
73 if (file.WriteAtCurrentPos(buffer, sizeof(T)) != sizeof(T))
Ted C 2014/08/19 16:51:09 Could you also just do: return file.WriteAtCurren
David Trainor- moved to gerrit 2014/08/19 18:31:07 Good point. Done
74 return false;
75 return true;
76 }
77
56 } // anonymous namespace 78 } // anonymous namespace
57 79
58 ThumbnailStore::ThumbnailStore(const std::string& disk_cache_path_str, 80 ThumbnailStore::ThumbnailStore(const std::string& disk_cache_path_str,
59 size_t default_cache_size, 81 size_t default_cache_size,
60 size_t approximation_cache_size, 82 size_t approximation_cache_size,
61 size_t compression_queue_max_size, 83 size_t compression_queue_max_size,
62 size_t write_queue_max_size, 84 size_t write_queue_max_size,
63 bool use_approximation_thumbnail) 85 bool use_approximation_thumbnail)
64 : disk_cache_path_(disk_cache_path_str), 86 : disk_cache_path_(disk_cache_path_str),
65 compression_queue_max_size_(compression_queue_max_size), 87 compression_queue_max_size_(compression_queue_max_size),
(...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after
410 skia::RefPtr<SkPixelRef> compressed_data, 432 skia::RefPtr<SkPixelRef> compressed_data,
411 float scale, 433 float scale,
412 const gfx::Size& content_size, 434 const gfx::Size& content_size,
413 const base::Callback<void()>& post_write_task) { 435 const base::Callback<void()>& post_write_task) {
414 DCHECK(compressed_data); 436 DCHECK(compressed_data);
415 437
416 base::File file(file_path, 438 base::File file(file_path,
417 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); 439 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
418 DCHECK(file.IsValid()); 440 DCHECK(file.IsValid());
419 441
420 compressed_data->lockPixels();
421 bool success = true; 442 bool success = true;
422 int content_width = content_size.width();
423 int content_height = content_size.height();
424 int data_width = compressed_data->info().width();
425 int data_height = compressed_data->info().height();
426 443
427 if (file.WriteAtCurrentPos(reinterpret_cast<const char*>(&kCompressedKey), 444 if (file.IsValid()) {
Ted C 2014/08/19 16:51:09 Would it be possible to pull out a helper function
David Trainor- moved to gerrit 2014/08/19 18:31:06 Done.
428 sizeof(int)) < 0 || 445 if (!WriteBigEndianToFile(file, kCompressedKey))
429 file.WriteAtCurrentPos(reinterpret_cast<const char*>(&content_width), 446 success = false;
430 sizeof(int)) < 0 || 447
431 file.WriteAtCurrentPos(reinterpret_cast<const char*>(&content_height), 448 if (success && !WriteBigEndianToFile(file, content_size.width()))
432 sizeof(int)) < 0 || 449 success = false;
433 file.WriteAtCurrentPos(reinterpret_cast<const char*>(&data_width), 450
434 sizeof(int)) < 0 || 451 if (success && !WriteBigEndianToFile(file, content_size.height()))
435 file.WriteAtCurrentPos(reinterpret_cast<const char*>(&data_height), 452 success = false;
436 sizeof(int)) < 0 || 453
437 file.WriteAtCurrentPos(reinterpret_cast<const char*>(&scale), 454 // Write ETC1 header.
438 sizeof(float)) < 0) { 455 compressed_data->lockPixels();
456
457 int bytes_written = 0;
458 unsigned char etc1_buffer[ETC_PKM_HEADER_SIZE];
Ted C 2014/08/19 16:51:09 any reason these lines don't go into the condition
David Trainor- moved to gerrit 2014/08/19 18:31:06 Done.
459 etc1_pkm_format_header(etc1_buffer,
460 compressed_data->info().width(),
461 compressed_data->info().height());
462
463 if (success) {
464 bytes_written = file.WriteAtCurrentPos(
465 reinterpret_cast<char*>(etc1_buffer), ETC_PKM_HEADER_SIZE);
466 if (bytes_written != ETC_PKM_HEADER_SIZE)
467 success = false;
468 }
469
470 if (success) {
471 int data_size = etc1_get_encoded_data_size(
472 compressed_data->info().width(),
473 compressed_data->info().height());
474 bytes_written = file.WriteAtCurrentPos(
475 reinterpret_cast<char*>(compressed_data->pixels()),
476 data_size);
477 if (bytes_written != data_size)
478 success = false;
479 }
480
481 compressed_data->unlockPixels();
482
483 if (success && !WriteBigEndianToFile(file, kCurrentExtraVersion))
484 success = false;
485
486 if (success) {
487 scale = 1.f / scale;
488
489 char buffer[4];
490 memcpy(buffer, &scale, sizeof(buffer));
491
492 char tmp = buffer[0];
493 buffer[0] = buffer[3];
494 buffer[3] = tmp;
495
496 tmp = buffer[1];
497 buffer[1] = buffer[2];
498 buffer[2] = tmp;
499
500 if (file.WriteAtCurrentPos(buffer, sizeof(buffer)) != sizeof(buffer))
501 success = false;
502 }
503 } else {
439 success = false; 504 success = false;
440 } 505 }
441 506
442 size_t compressed_bytes = etc1_get_encoded_data_size(data_width, data_height);
443 if (file.WriteAtCurrentPos(reinterpret_cast<char*>(compressed_data->pixels()),
444 compressed_bytes) < 0)
445 success = false;
446
447 compressed_data->unlockPixels();
448
449 file.Close(); 507 file.Close();
450 508
451 if (!success) 509 if (!success)
452 base::DeleteFile(file_path, false); 510 base::DeleteFile(file_path, false);
453 511
454 content::BrowserThread::PostTask( 512 content::BrowserThread::PostTask(
455 content::BrowserThread::UI, FROM_HERE, post_write_task); 513 content::BrowserThread::UI, FROM_HERE, post_write_task);
456 } 514 }
457 515
458 void ThumbnailStore::PostWriteTask() { 516 void ThumbnailStore::PostWriteTask() {
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
537 void(skia::RefPtr<SkPixelRef>, float, const gfx::Size&)>& 595 void(skia::RefPtr<SkPixelRef>, float, const gfx::Size&)>&
538 post_read_task) { 596 post_read_task) {
539 skia::RefPtr<SkPixelRef> compressed_data; 597 skia::RefPtr<SkPixelRef> compressed_data;
540 float scale = 0.f; 598 float scale = 0.f;
541 gfx::Size content_size; 599 gfx::Size content_size;
542 600
543 if (base::PathExists(file_path)) { 601 if (base::PathExists(file_path)) {
544 base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ); 602 base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
545 DCHECK(file.IsValid()); 603 DCHECK(file.IsValid());
546 604
547 int key;
548 bool success = true; 605 bool success = true;
549 if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&key), sizeof(int)) < 0 || 606 int key = 0;
Ted C 2014/08/19 16:51:09 same general comment about success early bail out
David Trainor- moved to gerrit 2014/08/19 18:31:06 Done.
550 key != kCompressedKey) 607 if (!ReadBigEndianFromFile(file, &key))
551 success = false; 608 success = false;
552 609
553 int width = 0; 610 if (key != kCompressedKey)
554 int height = 0;
555 if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&width), sizeof(int)) <
556 0 ||
557 file.ReadAtCurrentPos(reinterpret_cast<char*>(&height), sizeof(int)) <
558 0)
559 success = false; 611 success = false;
560 612
561 content_size = gfx::Size(width, height); 613
562 if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&width), sizeof(int)) < 614 int content_width = 0;
563 0 || 615 if (!ReadBigEndianFromFile(file, &content_width))
564 file.ReadAtCurrentPos(reinterpret_cast<char*>(&height), sizeof(int)) <
565 0)
566 success = false; 616 success = false;
567 617
568 gfx::Size data_size(width, height); 618 int content_height = 0;
569 if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&scale), sizeof(float)) < 619 if (!ReadBigEndianFromFile(file, &content_height))
570 0)
571 success = false; 620 success = false;
572 621
573 size_t compressed_bytes = 622 content_size.SetSize(content_width, content_height);
574 etc1_get_encoded_data_size(data_size.width(), data_size.height());
575 SkImageInfo info = {data_size.width(),
576 data_size.height(),
577 kUnknown_SkColorType,
578 kUnpremul_SkAlphaType};
579 623
580 scoped_ptr<uint8_t[]> data(new uint8_t[compressed_bytes]); 624 // Read ETC1 header.
581 if (file.ReadAtCurrentPos(reinterpret_cast<char*>(data.get()), 625 int bytes_read = 0;
582 compressed_bytes) < 0) 626 unsigned char etc1_buffer[ETC_PKM_HEADER_SIZE];
627 bytes_read = file.ReadAtCurrentPos(reinterpret_cast<char*>(etc1_buffer),
628 ETC_PKM_HEADER_SIZE);
629 if (bytes_read != ETC_PKM_HEADER_SIZE) {
Ted C 2014/08/19 16:51:09 no need for parens here since it's inconsistent
David Trainor- moved to gerrit 2014/08/19 18:31:07 Done.
583 success = false; 630 success = false;
631 }
632
633 if (!etc1_pkm_is_valid(etc1_buffer))
634 success = false;
635
636 int raw_width = 0;
637 if (success)
638 raw_width = etc1_pkm_get_width(etc1_buffer);
639
640 int raw_height = 0;
641 if (success)
642 raw_height = etc1_pkm_get_height(etc1_buffer);
643
644 // Do some simple sanity check validation. This is for Android only, for
Ted C 2014/08/19 16:51:09 this directory is under android, so I don't think
David Trainor- moved to gerrit 2014/08/19 18:31:07 Ah good point I forgot we could access those. Tha
645 // other platforms we'll have to be a bit smarter. Anything over 2048x2048
646 // won't load.
647 if (content_width > kMaxDimensionSize
648 || content_height > kMaxDimensionSize
649 || raw_width > kMaxDimensionSize
650 || raw_height > kMaxDimensionSize) {
651 success = false;
652 }
653
654 skia::RefPtr<SkData> etc1_pixel_data;
655 if (success) {
656 int data_size = etc1_get_encoded_data_size(raw_width, raw_height);
657 scoped_ptr<uint8_t[]> raw_data =
658 scoped_ptr<uint8_t[]>(new uint8_t[data_size]);
659
660 bytes_read = file.ReadAtCurrentPos(
661 reinterpret_cast<char*>(raw_data.get()),
662 data_size);
663
664 if (bytes_read == data_size) {
665 SkImageInfo info = {raw_width,
666 raw_height,
667 kUnknown_SkColorType,
668 kUnpremul_SkAlphaType};
669
670 etc1_pixel_data = skia::AdoptRef(
671 SkData::NewFromMalloc(raw_data.release(), data_size));
672 compressed_data = skia::AdoptRef(
673 SkMallocPixelRef::NewWithData(info,
674 0,
675 NULL,
676 etc1_pixel_data.get()));
677 } else {
678 success = false;
679 }
680 }
681
682 int extra_data_version = 0;
683 if (!ReadBigEndianFromFile(file, &extra_data_version))
684 success = false;
685
686 scale = 1.f;
687 if (success && extra_data_version == 1) {
688 char buffer[4];
689 if (file.ReadAtCurrentPos(buffer, sizeof(buffer)) == sizeof(buffer)) {
690 char tmp = buffer[0];
691 buffer[0] = buffer[3];
692 buffer[3] = tmp;
693
694 tmp = buffer[1];
695 buffer[1] = buffer[2];
696 buffer[2] = tmp;
697
698 memcpy(&scale, buffer, sizeof(buffer));
699
700 if (scale == 0.f) {
701 success = false;
702 } else {
703 scale = 1.f / scale;
704 }
705 } else {
706 success = false;
707 }
708 }
584 709
585 file.Close(); 710 file.Close();
586 711
587 skia::RefPtr<SkData> etc1_pixel_data =
588 skia::AdoptRef(SkData::NewFromMalloc(data.release(), compressed_bytes));
589 compressed_data = skia::AdoptRef(
590 SkMallocPixelRef::NewWithData(info, 0, NULL, etc1_pixel_data.get()));
591
592 if (!success) { 712 if (!success) {
593 compressed_data.clear(); 713 compressed_data.clear();
594 content_size = gfx::Size(); 714 content_size = gfx::Size();
595 scale = 0.f; 715 scale = 0.f;
596 base::DeleteFile(file_path, false); 716 base::DeleteFile(file_path, false);
597 } 717 }
598 } 718 }
599 719
600 content::BrowserThread::PostTask( 720 content::BrowserThread::PostTask(
601 content::BrowserThread::UI, 721 content::BrowserThread::UI,
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
684 dst_bitmap.eraseColor(0); 804 dst_bitmap.eraseColor(0);
685 SkAutoLockPixels dst_bitmap_lock(dst_bitmap); 805 SkAutoLockPixels dst_bitmap_lock(dst_bitmap);
686 806
687 SkCanvas canvas(dst_bitmap); 807 SkCanvas canvas(dst_bitmap);
688 canvas.scale(new_scale, new_scale); 808 canvas.scale(new_scale, new_scale);
689 canvas.drawBitmap(bitmap, 0, 0, NULL); 809 canvas.drawBitmap(bitmap, 0, 0, NULL);
690 dst_bitmap.setImmutable(); 810 dst_bitmap.setImmutable();
691 811
692 return std::make_pair(dst_bitmap, new_scale * scale); 812 return std::make_pair(dst_bitmap, new_scale * scale);
693 } 813 }
OLDNEW
« no previous file with comments | « no previous file | third_party/android_opengl/etc1/etc1.h » ('j') | third_party/android_opengl/etc1/etc1.cpp » ('J')

Powered by Google App Engine
This is Rietveld 408576698