Index: chrome/browser/android/thumbnail/thumbnail_impl.cc |
diff --git a/chrome/browser/android/thumbnail/thumbnail_impl.cc b/chrome/browser/android/thumbnail/thumbnail_impl.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..e1cdb377964411e5b174c4d3d9a0151369786f12 |
--- /dev/null |
+++ b/chrome/browser/android/thumbnail/thumbnail_impl.cc |
@@ -0,0 +1,280 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/android/thumbnail/thumbnail_impl.h" |
+ |
+#include "base/files/file.h" |
+#include "base/files/file_path.h" |
+#include "cc/resources/ui_resource_bitmap.h" |
+#include "chrome/browser/android/thumbnail/thumbnail_cache.h" |
+#include "third_party/android_opengl/etc1/etc1.h" |
+#include "third_party/skia/include/core/SkBitmap.h" |
+#include "third_party/skia/include/core/SkCanvas.h" |
+#include "third_party/skia/include/core/SkData.h" |
+#include "third_party/skia/include/core/SkMallocPixelRef.h" |
+#include "third_party/skia/include/core/SkPixelRef.h" |
+#include "ui/gfx/geometry/size_conversions.h" |
+ |
+namespace { |
+ |
+const int kCompressedKey = 0xABABABAB; |
+const int kDecompressedKey = 0xCDCDCDCD; |
+ |
+// ETC1 texture sizes are multiples of four. |
+size_t NextETC1Size(size_t s) { |
+ return (s / 4 + (s % 4 ? 1 : 0)) * 4; |
+} |
+ |
+gfx::Size GetEncodedSize(gfx::Size bitmap_size) { |
David Trainor- moved to gerrit
2014/06/17 08:12:11
const gfx::Size&
powei
2014/06/19 23:05:59
Done.
|
+ return gfx::Size(NextETC1Size(bitmap_size.width()), |
+ NextETC1Size(bitmap_size.height())); |
+} |
+ |
+} // namespace |
+ |
+ThumbnailImpl::ThumbnailImpl(TabId tab_id, |
+ const SkBitmap& bitmap, |
+ float scale, |
+ ThumbnailImplManager* thumbnail_impl_manager, |
+ content::UIResourceProvider* ui_resource_provider) |
+ : tab_id_(tab_id), |
+ ui_resource_id_(0), |
+ thumbnail_impl_manager_(thumbnail_impl_manager), |
+ ui_resource_provider_(ui_resource_provider) { |
+ DCHECK(ui_resource_provider); |
+ SetRawData(bitmap, scale); |
+} |
+ |
+ThumbnailImpl::~ThumbnailImpl() { |
+ CleanupUIResource(); |
+} |
+ |
+void ThumbnailImpl::CleanupUIResource() { |
+ DCHECK(ui_resource_provider_); |
+ if (ui_resource_id_) |
+ ui_resource_provider_->DeleteUIResource(ui_resource_id_); |
+ ui_resource_id_ = 0; |
+} |
+ |
+void ThumbnailImpl::BuildUIResource() { |
+ CleanupUIResource(); |
+ if (raw_data_.empty() && !compressed_data_) |
+ return; |
+ ui_resource_id_ = ui_resource_provider_->CreateUIResource(this); |
+} |
+ |
+bool ThumbnailImpl::IsValid() const { |
+ return ui_resource_provider_ && scale_ > 0 && !data_size_.IsEmpty() && |
+ !content_size_.IsEmpty(); |
+} |
+ |
+gfx::Size ThumbnailImpl::GetScaledContentSize() const { |
+ return gfx::ToRoundedSize(gfx::ScaleSize(content_size_, 1.f / scale_)); |
+} |
+ |
+gfx::SizeF ThumbnailImpl::GetScaledDataSize() const { |
+ return gfx::ScaleSize(data_size_, 1.f / scale_); |
+} |
+ |
+void ThumbnailImpl::Compress(scoped_refptr<ThumbnailImpl> in_thumbnail, |
David Trainor- moved to gerrit
2014/06/17 08:12:11
I reviewed this before the actual cache, but why h
powei
2014/06/19 23:05:59
This is just to make this method be more functiona
David Trainor- moved to gerrit
2014/06/25 07:40:16
Could it still act on the same class that's passed
|
+ scoped_refptr<ThumbnailImpl> out_thumbnail) { |
+ SkBitmap raw_data = in_thumbnail->raw_data_; |
+ if (raw_data.empty()) |
+ return; |
+ |
+ SkAutoLockPixels raw_data_lock(raw_data); |
+ gfx::Size raw_data_size(raw_data.width(), raw_data.height()); |
+ DCHECK_EQ(raw_data.config(), SkBitmap::kARGB_8888_Config); |
+ 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}; |
+ skia::RefPtr<SkData> etc1_pixel_data = skia::AdoptRef( |
+ SkData::NewFromMalloc(new uint8_t[encoded_bytes], encoded_bytes)); |
+ skia::RefPtr<SkMallocPixelRef> etc1_pixel_ref = skia::AdoptRef( |
+ SkMallocPixelRef::NewWithData(info, 0, NULL, etc1_pixel_data.get())); |
+ |
+ etc1_pixel_ref->lockPixels(); |
+ bool success = etc1_encode_image( |
+ reinterpret_cast<unsigned char*>(raw_data.getPixels()), |
+ raw_data_size.width(), |
+ raw_data_size.height(), |
+ pixel_size, |
+ stride, |
+ reinterpret_cast<unsigned char*>(etc1_pixel_ref->pixels()), |
+ encoded_size.width(), |
+ encoded_size.height()); |
+ etc1_pixel_ref->setImmutable(); |
+ etc1_pixel_ref->unlockPixels(); |
+ if (success) { |
+ out_thumbnail->SetCompressedData( |
+ etc1_pixel_ref, in_thumbnail->scale_, raw_data_size); |
+ } |
+} |
+ |
+bool ThumbnailImpl::WriteToFile(scoped_refptr<ThumbnailImpl> thumbnail, |
+ base::File& file) { |
+ // We assume caller has already initialized the file and will also close it. |
+ DCHECK(file.IsValid()); |
+ DCHECK(thumbnail); |
+ DCHECK(thumbnail->compressed_data_); |
+ |
+ thumbnail->compressed_data_->lockPixels(); |
+ bool success = true; |
+ int content_width = thumbnail->content_size_.width(); |
+ int content_height = thumbnail->content_size_.height(); |
+ int data_width = thumbnail->data_size_.width(); |
+ int data_height = thumbnail->data_size_.height(); |
+ |
+ if (file.WriteAtCurrentPos(reinterpret_cast<const char*>(&kCompressedKey), |
+ sizeof(int)) < 0 || |
+ file.WriteAtCurrentPos(reinterpret_cast<const char*>(&content_width), |
+ sizeof(int)) < 0 || |
+ file.WriteAtCurrentPos(reinterpret_cast<const char*>(&content_height), |
+ sizeof(int)) < 0 || |
+ file.WriteAtCurrentPos(reinterpret_cast<const char*>(&data_width), |
+ sizeof(int)) < 0 || |
+ file.WriteAtCurrentPos(reinterpret_cast<const char*>(&data_height), |
+ sizeof(int)) < 0 || |
+ file.WriteAtCurrentPos(reinterpret_cast<const char*>(&thumbnail->scale_), |
+ sizeof(float)) < 0) { |
+ success = false; |
+ } |
+ |
+ size_t compressed_bytes = etc1_get_encoded_data_size( |
+ thumbnail->data_size_.width(), thumbnail->data_size_.height()); |
+ |
+ if (file.WriteAtCurrentPos( |
+ reinterpret_cast<char*>(thumbnail->compressed_data_->pixels()), |
+ compressed_bytes) < 0) |
+ success = false; |
+ |
+ thumbnail->compressed_data_->unlockPixels(); |
+ return success; |
+} |
+ |
+bool ThumbnailImpl::ReadFromFile(base::File& file, |
+ scoped_refptr<ThumbnailImpl> thumbnail) { |
+ // We assume caller has already initialized the file and will also close it. |
+ DCHECK(file.IsValid()); |
+ |
+ int key; |
+ bool success = true; |
+ if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&key), sizeof(int)) < 0 || |
+ key != kCompressedKey) |
+ success = false; |
+ |
+ int width, height; |
+ if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&width), sizeof(int)) < 0 || |
+ file.ReadAtCurrentPos(reinterpret_cast<char*>(&height), sizeof(int)) < 0) |
+ success = false; |
+ gfx::Size content_size = gfx::Size(width, height); |
David Trainor- moved to gerrit
2014/06/17 08:12:11
gfx::Size content_size(width, height);
Same for b
powei
2014/06/19 23:05:59
Done.
|
+ |
+ if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&width), sizeof(int)) < 0 || |
+ file.ReadAtCurrentPos(reinterpret_cast<char*>(&height), sizeof(int)) < 0) |
+ success = false; |
+ gfx::Size data_size = gfx::Size(width, height); |
+ |
+ float scale = 0.f; |
+ if (file.ReadAtCurrentPos(reinterpret_cast<char*>(&scale), sizeof(float)) < 0) |
+ success = false; |
+ |
+ size_t compressed_bytes = |
+ etc1_get_encoded_data_size(data_size.width(), data_size.height()); |
+ |
+ SkImageInfo info = {data_size.width(), |
+ data_size.height(), |
+ kUnknown_SkColorType, |
+ kUnpremul_SkAlphaType}; |
+ |
+ scoped_ptr<uint8_t[]> data(new uint8_t[compressed_bytes]); |
+ if (file.ReadAtCurrentPos(reinterpret_cast<char*>(data.get()), |
+ compressed_bytes) < 0) |
+ success = false; |
+ |
+ skia::RefPtr<SkData> etc1_pixel_data = |
+ skia::AdoptRef(SkData::NewFromMalloc(data.release(), compressed_bytes)); |
+ skia::RefPtr<SkPixelRef> compressed_data = skia::AdoptRef( |
+ SkMallocPixelRef::NewWithData(info, 0, NULL, etc1_pixel_data.get())); |
+ |
+ if (success) |
+ thumbnail->SetCompressedData(compressed_data, scale, content_size); |
+ return success; |
+} |
+ |
+scoped_refptr<ThumbnailImpl> ThumbnailImpl::PassDataToNewThumbnail() { |
+ scoped_refptr<ThumbnailImpl> new_thumbnail = |
+ make_scoped_refptr(new ThumbnailImpl(tab_id_, |
+ SkBitmap(), |
+ 0.f, |
+ thumbnail_impl_manager_, |
+ ui_resource_provider_)); |
+ new_thumbnail->raw_data_ = raw_data_; |
+ new_thumbnail->compressed_data_ = compressed_data_; |
+ new_thumbnail->scale_ = scale_; |
+ new_thumbnail->data_size_ = data_size_; |
+ new_thumbnail->content_size_ = content_size_; |
+ |
+ // Release this Thumbnail's reference to the data. |
+ raw_data_ = SkBitmap(); |
+ compressed_data_.clear(); |
+ return new_thumbnail; |
+} |
+ |
+cc::UIResourceBitmap ThumbnailImpl::GetBitmap(cc::UIResourceId uid, |
+ bool resource_lost) { |
+ if (!raw_data_.empty()) { |
+ DCHECK(!compressed_data_); |
+ return cc::UIResourceBitmap(raw_data_); |
+ } else if (compressed_data_) { |
+ DCHECK(raw_data_.empty()); |
+ return cc::UIResourceBitmap(compressed_data_, data_size_); |
+ } |
+ |
+ // Return a place holder for all other calls to GetBitmap. |
+ SkBitmap tiny_bitmap; |
+ SkCanvas canvas(tiny_bitmap); |
+ tiny_bitmap.setConfig( |
+ SkBitmap::kARGB_8888_Config, 1, 1, 0, kOpaque_SkAlphaType); |
+ tiny_bitmap.allocPixels(); |
+ canvas.drawColor(SK_ColorWHITE); |
+ tiny_bitmap.setImmutable(); |
+ return cc::UIResourceBitmap(tiny_bitmap); |
+} |
+ |
+void ThumbnailImpl::UIResourceIsInvalid() { |
+ ui_resource_id_ = 0; |
+ if (thumbnail_impl_manager_) { |
+ scoped_refptr<ThumbnailImpl> this_thumbnail(this); |
+ thumbnail_impl_manager_->InvalidateCachedThumbnail(this_thumbnail); |
+ } |
+} |
+ |
+void ThumbnailImpl::SetCompressedData(skia::RefPtr<SkPixelRef> compressed_data, |
+ float scale, |
+ const gfx::Size& content_size) { |
+ DCHECK(compressed_data); |
+ compressed_data_ = compressed_data; |
+ raw_data_ = SkBitmap(); |
+ scale_ = scale; |
+ content_size_ = content_size; |
+ data_size_ = gfx::Size(compressed_data_->info().width(), |
+ compressed_data_->info().height()); |
+ BuildUIResource(); |
powei
2014/06/19 23:05:59
Just realized this can be called on the wrong thre
David Trainor- moved to gerrit
2014/06/25 07:40:16
Won't this defeat the purpose of using the UI reso
|
+} |
+ |
+void ThumbnailImpl::SetRawData(SkBitmap bitmap, float scale) { |
+ raw_data_ = bitmap; |
+ compressed_data_.clear(); |
+ data_size_ = gfx::Size(bitmap.width(), bitmap.height()); |
+ content_size_ = data_size_; |
+ scale_ = scale; |
+ BuildUIResource(); |
+} |