#include <cmath>
#include "base/big_endian.h"
-#include "base/file_util.h"
#include "base/files/file.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
+#include "base/files/file_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/threading/worker_pool.h"
#include "base/time/time.h"
// Indicates whether we prefer to have more free CPU memory over GPU memory.
const bool kPreferCPUMemory = true;
-// TODO(): ETC1 texture sizes should be multiples of four, but some drivers only
-// allow power-of-two ETC1 textures. Find better work around.
size_t NextPowerOfTwo(size_t x) {
--x;
x |= x >> 1;
return x + 1;
}
-gfx::Size GetEncodedSize(const gfx::Size& bitmap_size) {
+size_t RoundUpMod4(size_t x) {
+ return (x + 3) & ~3;
+}
+
+gfx::Size GetEncodedSize(const gfx::Size& bitmap_size, bool supports_npot) {
DCHECK(!bitmap_size.IsEmpty());
- return gfx::Size(NextPowerOfTwo(bitmap_size.width()),
- NextPowerOfTwo(bitmap_size.height()));
+ if (!supports_npot)
+ return gfx::Size(NextPowerOfTwo(bitmap_size.width()),
+ NextPowerOfTwo(bitmap_size.height()));
+ else
+ return gfx::Size(RoundUpMod4(bitmap_size.width()),
+ RoundUpMod4(bitmap_size.height()));
}
template<typename T>
ReadNextThumbnail();
}
+void ThumbnailStore::DecompressThumbnailFromFile(
+ TabId tab_id,
+ const base::Callback<void(bool, SkBitmap)>&
+ post_decompress_callback) {
+ base::FilePath file_path = GetFilePath(tab_id);
+
+ base::Callback<void(skia::RefPtr<SkPixelRef>, float, const gfx::Size&)>
+ decompress_task = base::Bind(
+ &ThumbnailStore::DecompressionTask, post_decompress_callback);
+
+ content::BrowserThread::PostTask(
+ content::BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&ThumbnailStore::ReadTask, true, file_path, decompress_task));
+}
+
void ThumbnailStore::RemoveFromDisk(TabId tab_id) {
base::FilePath file_path = GetFilePath(tab_id);
base::Closure task =
time_stamp,
scale);
- base::WorkerPool::PostTask(
- FROM_HERE,
- base::Bind(
- &ThumbnailStore::CompressionTask, bitmap, post_compression_task),
- true);
+ gfx::Size raw_data_size(bitmap.width(), bitmap.height());
+ gfx::Size encoded_size = GetEncodedSize(
+ raw_data_size, ui_resource_provider_->SupportsETC1NonPowerOfTwo());
+
+ base::WorkerPool::PostTask(FROM_HERE,
+ base::Bind(&ThumbnailStore::CompressionTask,
+ bitmap,
+ encoded_size,
+ post_compression_task),
+ true);
}
void ThumbnailStore::ReadNextThumbnail() {
content::BrowserThread::PostTask(
content::BrowserThread::FILE,
FROM_HERE,
- base::Bind(&ThumbnailStore::ReadTask, file_path, post_read_task));
+ base::Bind(&ThumbnailStore::ReadTask, false, file_path, post_read_task));
}
void ThumbnailStore::MakeSpaceForNewItemIfNecessary(TabId tab_id) {
void ThumbnailStore::CompressionTask(
SkBitmap raw_data,
+ gfx::Size encoded_size,
const base::Callback<void(skia::RefPtr<SkPixelRef>, const gfx::Size&)>&
post_compression_task) {
skia::RefPtr<SkPixelRef> compressed_data;
size_t pixel_size = 4; // Pixel size is 4 bytes for kARGB_8888_Config.
size_t stride = pixel_size * raw_data_size.width();
- gfx::Size encoded_size = GetEncodedSize(raw_data_size);
size_t encoded_bytes =
etc1_get_encoded_data_size(encoded_size.width(), encoded_size.height());
- SkImageInfo info = {encoded_size.width(),
- encoded_size.height(),
- kUnknown_SkColorType,
- kUnpremul_SkAlphaType};
+ SkImageInfo info = SkImageInfo::Make(encoded_size.width(),
+ encoded_size.height(),
+ kUnknown_SkColorType,
+ kUnpremul_SkAlphaType);
skia::RefPtr<SkData> etc1_pixel_data = skia::AdoptRef(
- SkData::NewFromMalloc(new uint8_t[encoded_bytes], encoded_bytes));
+ SkData::NewUninitialized(encoded_bytes));
skia::RefPtr<SkMallocPixelRef> etc1_pixel_ref = skia::AdoptRef(
SkMallocPixelRef::NewWithData(info, 0, NULL, etc1_pixel_data.get()));
return false;
}
- skia::RefPtr<SkData> etc1_pixel_data;
int data_size = etc1_get_encoded_data_size(raw_width, raw_height);
- scoped_ptr<uint8_t[]> raw_data =
- scoped_ptr<uint8_t[]>(new uint8_t[data_size]);
+ skia::RefPtr<SkData> etc1_pixel_data =
+ skia::AdoptRef(SkData::NewUninitialized(data_size));
int pixel_bytes_read = file.ReadAtCurrentPos(
- reinterpret_cast<char*>(raw_data.get()),
+ reinterpret_cast<char*>(etc1_pixel_data->writable_data()),
data_size);
if (pixel_bytes_read != data_size)
return false;
- SkImageInfo info = {raw_width,
- raw_height,
- kUnknown_SkColorType,
- kUnpremul_SkAlphaType};
-
- etc1_pixel_data = skia::AdoptRef(
- SkData::NewFromMalloc(raw_data.release(), data_size));
+ SkImageInfo info = SkImageInfo::Make(raw_width,
+ raw_height,
+ kUnknown_SkColorType,
+ kUnpremul_SkAlphaType);
*out_pixels = skia::AdoptRef(
SkMallocPixelRef::NewWithData(info,
}// anonymous namespace
void ThumbnailStore::ReadTask(
+ bool decompress,
const base::FilePath& file_path,
const base::Callback<
void(skia::RefPtr<SkPixelRef>, float, const gfx::Size&)>&
if (base::PathExists(file_path)) {
base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
+
bool valid_contents = ReadFromFile(file,
&content_size,
&scale,
}
}
- content::BrowserThread::PostTask(
- content::BrowserThread::UI,
- FROM_HERE,
- base::Bind(post_read_task, compressed_data, scale, content_size));
+ if (decompress) {
+ base::WorkerPool::PostTask(
+ FROM_HERE,
+ base::Bind(post_read_task, compressed_data, scale, content_size),
+ true);
+ } else {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(post_read_task, compressed_data, scale, content_size));
+ }
}
void ThumbnailStore::PostReadTask(TabId tab_id,
return;
}
+void ThumbnailStore::DecompressionTask(
+ const base::Callback<void(bool, SkBitmap)>&
+ post_decompression_callback,
+ skia::RefPtr<SkPixelRef> compressed_data,
+ float scale,
+ const gfx::Size& content_size) {
+ SkBitmap raw_data_small;
+ bool success = false;
+
+ if (compressed_data.get()) {
+ gfx::Size buffer_size = gfx::Size(compressed_data->info().width(),
+ compressed_data->info().height());
+
+ SkBitmap raw_data;
+ raw_data.allocPixels(SkImageInfo::Make(buffer_size.width(),
+ buffer_size.height(),
+ kRGBA_8888_SkColorType,
+ kOpaque_SkAlphaType));
+ SkAutoLockPixels raw_data_lock(raw_data);
+ compressed_data->lockPixels();
+ success = etc1_decode_image(
+ reinterpret_cast<unsigned char*>(compressed_data->pixels()),
+ reinterpret_cast<unsigned char*>(raw_data.getPixels()),
+ buffer_size.width(),
+ buffer_size.height(),
+ raw_data.bytesPerPixel(),
+ raw_data.rowBytes());
+ compressed_data->unlockPixels();
+ raw_data.setImmutable();
+
+ if (!success) {
+ // Leave raw_data_small empty for consistency with other failure modes.
+ } else if (content_size == buffer_size) {
+ // Shallow copy the pixel reference.
+ raw_data_small = raw_data;
+ } else {
+ // The content size is smaller than the buffer size (likely because of
+ // a power-of-two rounding), so deep copy the bitmap.
+ raw_data_small.allocPixels(SkImageInfo::Make(content_size.width(),
+ content_size.height(),
+ kRGBA_8888_SkColorType,
+ kOpaque_SkAlphaType));
+ SkAutoLockPixels raw_data_small_lock(raw_data_small);
+ SkCanvas small_canvas(raw_data_small);
+ small_canvas.drawBitmap(raw_data, 0, 0);
+ raw_data_small.setImmutable();
+ }
+ }
+
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(post_decompression_callback, success, raw_data_small));
+}
+
ThumbnailStore::ThumbnailMetaData::ThumbnailMetaData() {
}