Home | History | Annotate | Download | only in login
      1 // Copyright (c) 2013 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/user_image_loader.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/file_util.h"
      9 #include "base/files/file_path.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/threading/worker_pool.h"
     13 #include "chrome/browser/chromeos/login/helper.h"
     14 #include "chrome/browser/chromeos/login/user_image.h"
     15 #include "content/public/browser/browser_thread.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 using content::BrowserThread;
     22 
     23 namespace chromeos {
     24 
     25 UserImageLoader::ImageInfo::ImageInfo(int size,
     26                                       const LoadedCallback& loaded_cb)
     27     : size(size),
     28       loaded_cb(loaded_cb) {
     29 }
     30 
     31 UserImageLoader::ImageInfo::~ImageInfo() {
     32 }
     33 
     34 UserImageLoader::UserImageLoader(ImageDecoder::ImageCodec image_codec)
     35     : target_message_loop_(NULL),
     36       image_codec_(image_codec) {
     37 }
     38 
     39 UserImageLoader::~UserImageLoader() {
     40 }
     41 
     42 void UserImageLoader::Start(const std::string& filepath,
     43                             int size,
     44                             const LoadedCallback& loaded_cb) {
     45   base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
     46   SequenceToken sequence_token = pool->GetSequenceToken();
     47   Start(filepath, size, sequence_token, loaded_cb);
     48 }
     49 
     50 void UserImageLoader::Start(const std::string& filepath,
     51                             int size,
     52                             const SequenceToken& token,
     53                             const LoadedCallback& loaded_cb) {
     54   target_message_loop_ = base::MessageLoop::current();
     55 
     56   ImageInfo image_info(size, loaded_cb);
     57   base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
     58   scoped_refptr<base::SequencedTaskRunner> task_runner = pool->
     59       GetSequencedTaskRunnerWithShutdownBehavior(token,
     60           base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN);
     61   task_runner->PostTask(
     62       FROM_HERE,
     63       base::Bind(&UserImageLoader::LoadImage, this, filepath, image_info,
     64                  task_runner));
     65 }
     66 
     67 void UserImageLoader::LoadImage(
     68     const std::string& filepath,
     69     const ImageInfo& image_info,
     70     scoped_refptr<base::SequencedTaskRunner> task_runner) {
     71   DCHECK(task_runner->RunsTasksOnCurrentThread());
     72 
     73   std::string image_data;
     74   file_util::ReadFileToString(base::FilePath(filepath), &image_data);
     75 
     76   scoped_refptr<ImageDecoder> image_decoder =
     77       new ImageDecoder(this, image_data, image_codec_);
     78   {
     79     base::AutoLock lock(lock_);
     80     image_info_map_.insert(std::make_pair(image_decoder.get(), image_info));
     81   }
     82   image_decoder->Start(task_runner);
     83 }
     84 
     85 void UserImageLoader::OnImageDecoded(const ImageDecoder* decoder,
     86                                      const SkBitmap& decoded_image) {
     87   ImageInfoMap::iterator info_it;
     88   scoped_ptr<ImageInfo> image_info;
     89   {
     90     base::AutoLock lock(lock_);
     91     info_it = image_info_map_.find(decoder);
     92     if (info_it == image_info_map_.end()) {
     93       NOTREACHED();
     94       return;
     95     }
     96     image_info.reset(
     97         new ImageInfo(info_it->second.size, info_it->second.loaded_cb));
     98     image_info_map_.erase(info_it);
     99   }
    100 
    101   SkBitmap final_image = decoded_image;
    102 
    103   if (image_info->size > 0) {
    104     // Auto crop the image, taking the largest square in the center.
    105     int size = std::min(decoded_image.width(), decoded_image.height());
    106     int x = (decoded_image.width() - size) / 2;
    107     int y = (decoded_image.height() - size) / 2;
    108     SkBitmap cropped_image =
    109         SkBitmapOperations::CreateTiledBitmap(decoded_image, x, y, size, size);
    110     if (size > image_info->size) {
    111       // Also downsize the image to save space and memory.
    112       final_image =
    113           skia::ImageOperations::Resize(cropped_image,
    114                                         skia::ImageOperations::RESIZE_LANCZOS3,
    115                                         image_info->size,
    116                                         image_info->size);
    117     } else {
    118       final_image = cropped_image;
    119     }
    120   }
    121   // Make the SkBitmap immutable as we won't modify it. This is important
    122   // because otherwise it gets duplicated during painting, wasting memory.
    123   final_image.setImmutable();
    124   gfx::ImageSkia final_image_skia =
    125       gfx::ImageSkia::CreateFrom1xBitmap(final_image);
    126   final_image_skia.MakeThreadSafe();
    127   UserImage user_image(final_image_skia, decoder->get_image_data());
    128   if (image_codec_ == ImageDecoder::ROBUST_JPEG_CODEC)
    129     user_image.MarkAsSafe();
    130   target_message_loop_->PostTask(
    131       FROM_HERE,
    132       base::Bind(image_info->loaded_cb, user_image));
    133 }
    134 
    135 void UserImageLoader::OnDecodeImageFailed(const ImageDecoder* decoder) {
    136   ImageInfoMap::iterator info_it;
    137   scoped_ptr<ImageInfo> image_info;
    138   {
    139     base::AutoLock lock(lock_);
    140     info_it = image_info_map_.find(decoder);
    141     if (info_it == image_info_map_.end()) {
    142       NOTREACHED();
    143       return;
    144     }
    145     image_info.reset(
    146         new ImageInfo(info_it->second.size, info_it->second.loaded_cb));
    147     image_info_map_.erase(decoder);
    148   }
    149 
    150   target_message_loop_->PostTask(
    151       FROM_HERE,
    152       base::Bind(image_info->loaded_cb, UserImage()));
    153 }
    154 
    155 }  // namespace chromeos
    156