15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/chromeos/login/users/avatar/user_image_loader.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h" 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/files/file_path.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/files/file_util.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/message_loop/message_loop_proxy.h" 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/sequenced_task_runner.h" 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/login/helper.h" 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "components/user_manager/user_image/user_image.h" 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "skia/ext/image_operations.h" 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h" 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/codec/png_codec.h" 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/gfx/skbitmap_operations.h" 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chromeos { 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UserImageLoader::ImageInfo::ImageInfo(const std::string& file_path, 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int pixels_per_side, 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const LoadedCallback& loaded_cb) 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : file_path(file_path), 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pixels_per_side(pixels_per_side), 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loaded_cb(loaded_cb) { 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UserImageLoader::ImageInfo::~ImageInfo() { 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UserImageLoader::UserImageLoader( 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageDecoder::ImageCodec image_codec, 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<base::SequencedTaskRunner> background_task_runner) 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : foreground_task_runner_(base::MessageLoopProxy::current()), 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_task_runner_(background_task_runner), 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) image_codec_(image_codec) { 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UserImageLoader::~UserImageLoader() { 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UserImageLoader::Start(const std::string& filepath, 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int pixels_per_side, 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const LoadedCallback& loaded_cb) { 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_task_runner_->PostTask( 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&UserImageLoader::ReadAndDecodeImage, 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this, 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageInfo(filepath, pixels_per_side, loaded_cb))); 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UserImageLoader::Start(scoped_ptr<std::string> data, 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int pixels_per_side, 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const LoadedCallback& loaded_cb) { 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) background_task_runner_->PostTask( 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FROM_HERE, 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(&UserImageLoader::DecodeImage, 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this, 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Passed(&data), 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageInfo(std::string(), pixels_per_side, loaded_cb))); 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UserImageLoader::ReadAndDecodeImage(const ImageInfo& image_info) { 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_ptr<std::string> data(new std::string); 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!base::ReadFileToString(base::FilePath(image_info.file_path), data.get())) 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(ERROR) << "Failed to read image " << image_info.file_path; 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In case ReadFileToString() fails, |data| is empty and DecodeImage() calls 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // back to OnDecodeImageFailed(). 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DecodeImage(data.Pass(), image_info); 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UserImageLoader::DecodeImage(const scoped_ptr<std::string> data, 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const ImageInfo& image_info) { 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) scoped_refptr<ImageDecoder> image_decoder = 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new ImageDecoder(this, *data, image_codec_); 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) image_info_map_.insert(std::make_pair(image_decoder.get(), image_info)); 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) image_decoder->Start(background_task_runner_); 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UserImageLoader::OnImageDecoded(const ImageDecoder* decoder, 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const SkBitmap& decoded_image) { 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ImageInfoMap::iterator it = image_info_map_.find(decoder); 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (it == image_info_map_.end()) { 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) NOTREACHED(); 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string file_path = it->second.file_path; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const int target_size = it->second.pixels_per_side; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const LoadedCallback loaded_cb = it->second.loaded_cb; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) image_info_map_.erase(it); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkBitmap final_image = decoded_image; 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (target_size > 0) { 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Auto crop the image, taking the largest square in the center. 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int pixels_per_side = 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::min(decoded_image.width(), decoded_image.height()); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int x = (decoded_image.width() - pixels_per_side) / 2; 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int y = (decoded_image.height() - pixels_per_side) / 2; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SkBitmap cropped_image = SkBitmapOperations::CreateTiledBitmap( 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) decoded_image, x, y, pixels_per_side, pixels_per_side); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (pixels_per_side > target_size) { 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Also downsize the image to save space and memory. 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) final_image = 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) skia::ImageOperations::Resize(cropped_image, 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) skia::ImageOperations::RESIZE_LANCZOS3, 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target_size, 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) target_size); 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) final_image = cropped_image; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Make the SkBitmap immutable as we won't modify it. This is important 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // because otherwise it gets duplicated during painting, wasting memory. 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) final_image.setImmutable(); 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::ImageSkia final_image_skia = 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) gfx::ImageSkia::CreateFrom1xBitmap(final_image); 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) final_image_skia.MakeThreadSafe(); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_manager::UserImage user_image(final_image_skia, 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) decoder->get_image_data()); 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_image.set_file_path(file_path); 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (image_codec_ == ImageDecoder::ROBUST_JPEG_CODEC) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) user_image.MarkAsSafe(); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) foreground_task_runner_->PostTask(FROM_HERE, 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::Bind(loaded_cb, user_image)); 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 138void UserImageLoader::OnDecodeImageFailed(const ImageDecoder* decoder) { 139 DCHECK(background_task_runner_->RunsTasksOnCurrentThread()); 140 141 ImageInfoMap::iterator it = image_info_map_.find(decoder); 142 if (it == image_info_map_.end()) { 143 NOTREACHED(); 144 return; 145 } 146 const LoadedCallback loaded_cb = it->second.loaded_cb; 147 image_info_map_.erase(it); 148 149 foreground_task_runner_->PostTask( 150 FROM_HERE, base::Bind(loaded_cb, user_manager::UserImage())); 151} 152 153} // namespace chromeos 154