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.
5 #include "chrome/browser/chromeos/login/user_image_loader.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/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"
23 UserImageLoader::ImageInfo::ImageInfo(int size
,
24 const LoadedCallback
& loaded_cb
)
26 loaded_cb(loaded_cb
) {
29 UserImageLoader::ImageInfo::~ImageInfo() {
32 UserImageLoader::UserImageLoader(
33 ImageDecoder::ImageCodec image_codec
,
34 scoped_refptr
<base::SequencedTaskRunner
> background_task_runner
)
35 : foreground_task_runner_(base::MessageLoopProxy::current()),
36 background_task_runner_(background_task_runner
),
37 image_codec_(image_codec
) {
40 UserImageLoader::~UserImageLoader() {
43 void UserImageLoader::Start(const std::string
& filepath
,
45 const LoadedCallback
& loaded_cb
) {
46 background_task_runner_
->PostTask(
48 base::Bind(&UserImageLoader::ReadAndDecodeImage
,
51 ImageInfo(size
, loaded_cb
)));
54 void UserImageLoader::Start(scoped_ptr
<std::string
> data
,
56 const LoadedCallback
& loaded_cb
) {
57 background_task_runner_
->PostTask(FROM_HERE
,
58 base::Bind(&UserImageLoader::DecodeImage
,
61 ImageInfo(size
, loaded_cb
)));
64 void UserImageLoader::ReadAndDecodeImage(const std::string
& filepath
,
65 const ImageInfo
& image_info
) {
66 DCHECK(background_task_runner_
->RunsTasksOnCurrentThread());
68 scoped_ptr
<std::string
> data(new std::string
);
70 base::ReadFileToString(base::FilePath(filepath
), data
.get());
73 DecodeImage(data
.Pass(), image_info
);
76 void UserImageLoader::DecodeImage(const scoped_ptr
<std::string
> data
,
77 const ImageInfo
& image_info
) {
78 DCHECK(background_task_runner_
->RunsTasksOnCurrentThread());
80 scoped_refptr
<ImageDecoder
> image_decoder
=
81 new ImageDecoder(this, *data
, image_codec_
);
82 image_info_map_
.insert(std::make_pair(image_decoder
.get(), image_info
));
83 image_decoder
->Start(background_task_runner_
);
86 void UserImageLoader::OnImageDecoded(const ImageDecoder
* decoder
,
87 const SkBitmap
& decoded_image
) {
88 DCHECK(background_task_runner_
->RunsTasksOnCurrentThread());
90 ImageInfoMap::iterator it
= image_info_map_
.find(decoder
);
91 if (it
== image_info_map_
.end()) {
95 const int target_size
= it
->second
.size
;
96 const LoadedCallback loaded_cb
= it
->second
.loaded_cb
;
97 image_info_map_
.erase(it
);
99 SkBitmap final_image
= decoded_image
;
101 if (target_size
> 0) {
102 // Auto crop the image, taking the largest square in the center.
103 int size
= std::min(decoded_image
.width(), decoded_image
.height());
104 int x
= (decoded_image
.width() - size
) / 2;
105 int y
= (decoded_image
.height() - size
) / 2;
106 SkBitmap cropped_image
=
107 SkBitmapOperations::CreateTiledBitmap(decoded_image
, x
, y
, size
, size
);
108 if (size
> target_size
) {
109 // Also downsize the image to save space and memory.
111 skia::ImageOperations::Resize(cropped_image
,
112 skia::ImageOperations::RESIZE_LANCZOS3
,
116 final_image
= cropped_image
;
119 // Make the SkBitmap immutable as we won't modify it. This is important
120 // because otherwise it gets duplicated during painting, wasting memory.
121 final_image
.setImmutable();
122 gfx::ImageSkia final_image_skia
=
123 gfx::ImageSkia::CreateFrom1xBitmap(final_image
);
124 final_image_skia
.MakeThreadSafe();
125 UserImage
user_image(final_image_skia
, decoder
->get_image_data());
126 if (image_codec_
== ImageDecoder::ROBUST_JPEG_CODEC
)
127 user_image
.MarkAsSafe();
128 foreground_task_runner_
->PostTask(FROM_HERE
,
129 base::Bind(loaded_cb
, user_image
));
132 void UserImageLoader::OnDecodeImageFailed(const ImageDecoder
* decoder
) {
133 DCHECK(background_task_runner_
->RunsTasksOnCurrentThread());
135 ImageInfoMap::iterator it
= image_info_map_
.find(decoder
);
136 if (it
== image_info_map_
.end()) {
140 const LoadedCallback loaded_cb
= it
->second
.loaded_cb
;
141 image_info_map_
.erase(it
);
143 foreground_task_runner_
->PostTask(FROM_HERE
,
144 base::Bind(loaded_cb
, UserImage()));
147 } // namespace chromeos