Home | History | Annotate | Download | only in avatar
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/login/users/avatar/user_image_loader.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/files/file_path.h"
     10 #include "base/files/file_util.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/message_loop/message_loop_proxy.h"
     13 #include "base/sequenced_task_runner.h"
     14 #include "chrome/browser/chromeos/login/helper.h"
     15 #include "components/user_manager/user_image/user_image.h"
     16 #include "skia/ext/image_operations.h"
     17 #include "third_party/skia/include/core/SkBitmap.h"
     18 #include "ui/gfx/codec/png_codec.h"
     19 #include "ui/gfx/skbitmap_operations.h"
     20 
     21 namespace chromeos {
     22 
     23 UserImageLoader::ImageInfo::ImageInfo(const std::string& file_path,
     24                                       int pixels_per_side,
     25                                       const LoadedCallback& loaded_cb)
     26     : file_path(file_path),
     27       pixels_per_side(pixels_per_side),
     28       loaded_cb(loaded_cb) {
     29 }
     30 
     31 UserImageLoader::ImageInfo::~ImageInfo() {
     32 }
     33 
     34 UserImageLoader::UserImageLoader(
     35     ImageDecoder::ImageCodec image_codec,
     36     scoped_refptr<base::SequencedTaskRunner> background_task_runner)
     37     : foreground_task_runner_(base::MessageLoopProxy::current()),
     38       background_task_runner_(background_task_runner),
     39       image_codec_(image_codec) {
     40 }
     41 
     42 UserImageLoader::~UserImageLoader() {
     43 }
     44 
     45 void UserImageLoader::Start(const std::string& filepath,
     46                             int pixels_per_side,
     47                             const LoadedCallback& loaded_cb) {
     48   background_task_runner_->PostTask(
     49       FROM_HERE,
     50       base::Bind(&UserImageLoader::ReadAndDecodeImage,
     51                  this,
     52                  ImageInfo(filepath, pixels_per_side, loaded_cb)));
     53 }
     54 
     55 void UserImageLoader::Start(scoped_ptr<std::string> data,
     56                             int pixels_per_side,
     57                             const LoadedCallback& loaded_cb) {
     58   background_task_runner_->PostTask(
     59       FROM_HERE,
     60       base::Bind(&UserImageLoader::DecodeImage,
     61                  this,
     62                  base::Passed(&data),
     63                  ImageInfo(std::string(), pixels_per_side, loaded_cb)));
     64 }
     65 
     66 void UserImageLoader::ReadAndDecodeImage(const ImageInfo& image_info) {
     67   DCHECK(background_task_runner_->RunsTasksOnCurrentThread());
     68 
     69   scoped_ptr<std::string> data(new std::string);
     70   if (!base::ReadFileToString(base::FilePath(image_info.file_path), data.get()))
     71     LOG(ERROR) << "Failed to read image " << image_info.file_path;
     72 
     73   // In case ReadFileToString() fails, |data| is empty and DecodeImage() calls
     74   // back to OnDecodeImageFailed().
     75   DecodeImage(data.Pass(), image_info);
     76 }
     77 
     78 void UserImageLoader::DecodeImage(const scoped_ptr<std::string> data,
     79                                   const ImageInfo& image_info) {
     80   DCHECK(background_task_runner_->RunsTasksOnCurrentThread());
     81 
     82   scoped_refptr<ImageDecoder> image_decoder =
     83       new ImageDecoder(this, *data, image_codec_);
     84   image_info_map_.insert(std::make_pair(image_decoder.get(), image_info));
     85   image_decoder->Start(background_task_runner_);
     86 }
     87 
     88 void UserImageLoader::OnImageDecoded(const ImageDecoder* decoder,
     89                                      const SkBitmap& decoded_image) {
     90   DCHECK(background_task_runner_->RunsTasksOnCurrentThread());
     91 
     92   ImageInfoMap::iterator it = image_info_map_.find(decoder);
     93   if (it == image_info_map_.end()) {
     94     NOTREACHED();
     95     return;
     96   }
     97   const std::string file_path = it->second.file_path;
     98   const int target_size = it->second.pixels_per_side;
     99   const LoadedCallback loaded_cb = it->second.loaded_cb;
    100   image_info_map_.erase(it);
    101 
    102   SkBitmap final_image = decoded_image;
    103 
    104   if (target_size > 0) {
    105     // Auto crop the image, taking the largest square in the center.
    106     int pixels_per_side =
    107         std::min(decoded_image.width(), decoded_image.height());
    108     int x = (decoded_image.width() - pixels_per_side) / 2;
    109     int y = (decoded_image.height() - pixels_per_side) / 2;
    110     SkBitmap cropped_image = SkBitmapOperations::CreateTiledBitmap(
    111         decoded_image, x, y, pixels_per_side, pixels_per_side);
    112     if (pixels_per_side > target_size) {
    113       // Also downsize the image to save space and memory.
    114       final_image =
    115           skia::ImageOperations::Resize(cropped_image,
    116                                         skia::ImageOperations::RESIZE_LANCZOS3,
    117                                         target_size,
    118                                         target_size);
    119     } else {
    120       final_image = cropped_image;
    121     }
    122   }
    123   // Make the SkBitmap immutable as we won't modify it. This is important
    124   // because otherwise it gets duplicated during painting, wasting memory.
    125   final_image.setImmutable();
    126   gfx::ImageSkia final_image_skia =
    127       gfx::ImageSkia::CreateFrom1xBitmap(final_image);
    128   final_image_skia.MakeThreadSafe();
    129   user_manager::UserImage user_image(final_image_skia,
    130                                      decoder->get_image_data());
    131   user_image.set_file_path(file_path);
    132   if (image_codec_ == ImageDecoder::ROBUST_JPEG_CODEC)
    133     user_image.MarkAsSafe();
    134   foreground_task_runner_->PostTask(FROM_HERE,
    135                                     base::Bind(loaded_cb, user_image));
    136 }
    137 
    138 void 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