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

Unified Diff: chrome/browser/android/thumbnail/thumbnail_impl.cc

Issue 262543002: android: add ThumbnailCache (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@codec
Patch Set: separate into multiple files Created 6 years, 6 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 side-by-side diff with in-line comments
Download patch
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();
+}

Powered by Google App Engine
This is Rietveld 408576698