// Copyright (c) 2013 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/chromeos/login/user_image_loader.h" #include "base/bind.h" #include "base/bind_helpers.h" #include "base/file_util.h" #include "base/files/file_path.h" #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop_proxy.h" #include "base/sequenced_task_runner.h" #include "chrome/browser/chromeos/login/helper.h" #include "chrome/browser/chromeos/login/user_image.h" #include "skia/ext/image_operations.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/codec/png_codec.h" #include "ui/gfx/skbitmap_operations.h" namespace chromeos { UserImageLoader::ImageInfo::ImageInfo(int size, const LoadedCallback& loaded_cb) : size(size), loaded_cb(loaded_cb) { } UserImageLoader::ImageInfo::~ImageInfo() { } UserImageLoader::UserImageLoader( ImageDecoder::ImageCodec image_codec, scoped_refptr background_task_runner) : foreground_task_runner_(base::MessageLoopProxy::current()), background_task_runner_(background_task_runner), image_codec_(image_codec) { } UserImageLoader::~UserImageLoader() { } void UserImageLoader::Start(const std::string& filepath, int size, const LoadedCallback& loaded_cb) { background_task_runner_->PostTask( FROM_HERE, base::Bind(&UserImageLoader::ReadAndDecodeImage, this, filepath, ImageInfo(size, loaded_cb))); } void UserImageLoader::Start(scoped_ptr data, int size, const LoadedCallback& loaded_cb) { background_task_runner_->PostTask(FROM_HERE, base::Bind(&UserImageLoader::DecodeImage, this, base::Passed(&data), ImageInfo(size, loaded_cb))); } void UserImageLoader::ReadAndDecodeImage(const std::string& filepath, const ImageInfo& image_info) { DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); scoped_ptr data(new std::string); const bool success = base::ReadFileToString(base::FilePath(filepath), data.get()); DCHECK(success); DecodeImage(data.Pass(), image_info); } void UserImageLoader::DecodeImage(const scoped_ptr data, const ImageInfo& image_info) { DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); scoped_refptr image_decoder = new ImageDecoder(this, *data, image_codec_); image_info_map_.insert(std::make_pair(image_decoder.get(), image_info)); image_decoder->Start(background_task_runner_); } void UserImageLoader::OnImageDecoded(const ImageDecoder* decoder, const SkBitmap& decoded_image) { DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); ImageInfoMap::iterator it = image_info_map_.find(decoder); if (it == image_info_map_.end()) { NOTREACHED(); return; } const int target_size = it->second.size; const LoadedCallback loaded_cb = it->second.loaded_cb; image_info_map_.erase(it); SkBitmap final_image = decoded_image; if (target_size > 0) { // Auto crop the image, taking the largest square in the center. int size = std::min(decoded_image.width(), decoded_image.height()); int x = (decoded_image.width() - size) / 2; int y = (decoded_image.height() - size) / 2; SkBitmap cropped_image = SkBitmapOperations::CreateTiledBitmap(decoded_image, x, y, size, size); if (size > target_size) { // Also downsize the image to save space and memory. final_image = skia::ImageOperations::Resize(cropped_image, skia::ImageOperations::RESIZE_LANCZOS3, target_size, target_size); } else { final_image = cropped_image; } } // Make the SkBitmap immutable as we won't modify it. This is important // because otherwise it gets duplicated during painting, wasting memory. final_image.setImmutable(); gfx::ImageSkia final_image_skia = gfx::ImageSkia::CreateFrom1xBitmap(final_image); final_image_skia.MakeThreadSafe(); UserImage user_image(final_image_skia, decoder->get_image_data()); if (image_codec_ == ImageDecoder::ROBUST_JPEG_CODEC) user_image.MarkAsSafe(); foreground_task_runner_->PostTask(FROM_HERE, base::Bind(loaded_cb, user_image)); } void UserImageLoader::OnDecodeImageFailed(const ImageDecoder* decoder) { DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); ImageInfoMap::iterator it = image_info_map_.find(decoder); if (it == image_info_map_.end()) { NOTREACHED(); return; } const LoadedCallback loaded_cb = it->second.loaded_cb; image_info_map_.erase(it); foreground_task_runner_->PostTask(FROM_HERE, base::Bind(loaded_cb, UserImage())); } } // namespace chromeos