• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/file_util.h"
10 #include "base/files/file_path.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 "chrome/browser/chromeos/login/users/avatar/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 
ImageInfo(const std::string & file_path,int pixels_per_side,const LoadedCallback & loaded_cb)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 
~ImageInfo()31 UserImageLoader::ImageInfo::~ImageInfo() {
32 }
33 
UserImageLoader(ImageDecoder::ImageCodec image_codec,scoped_refptr<base::SequencedTaskRunner> background_task_runner)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 
~UserImageLoader()42 UserImageLoader::~UserImageLoader() {
43 }
44 
Start(const std::string & filepath,int pixels_per_side,const LoadedCallback & loaded_cb)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 
Start(scoped_ptr<std::string> data,int pixels_per_side,const LoadedCallback & loaded_cb)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 
ReadAndDecodeImage(const ImageInfo & image_info)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 
DecodeImage(const scoped_ptr<std::string> data,const ImageInfo & image_info)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 
OnImageDecoded(const ImageDecoder * decoder,const SkBitmap & decoded_image)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   UserImage user_image(final_image_skia, decoder->get_image_data());
130   user_image.set_file_path(file_path);
131   if (image_codec_ == ImageDecoder::ROBUST_JPEG_CODEC)
132     user_image.MarkAsSafe();
133   foreground_task_runner_->PostTask(FROM_HERE,
134                                     base::Bind(loaded_cb, user_image));
135 }
136 
OnDecodeImageFailed(const ImageDecoder * decoder)137 void UserImageLoader::OnDecodeImageFailed(const ImageDecoder* decoder) {
138   DCHECK(background_task_runner_->RunsTasksOnCurrentThread());
139 
140   ImageInfoMap::iterator it = image_info_map_.find(decoder);
141   if (it == image_info_map_.end()) {
142     NOTREACHED();
143     return;
144   }
145   const LoadedCallback loaded_cb = it->second.loaded_cb;
146   image_info_map_.erase(it);
147 
148   foreground_task_runner_->PostTask(FROM_HERE,
149                                     base::Bind(loaded_cb, UserImage()));
150 }
151 
152 }  // namespace chromeos
153