Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/login/users/avatar/user_image_loader.h" | 5 #include "chrome/browser/chromeos/login/users/avatar/user_image_loader.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 39 loaded_cb(loaded_cb) {} | 39 loaded_cb(loaded_cb) {} |
| 40 ~ImageInfo() {} | 40 ~ImageInfo() {} |
| 41 | 41 |
| 42 const base::FilePath file_path; | 42 const base::FilePath file_path; |
| 43 const int pixels_per_side; | 43 const int pixels_per_side; |
| 44 const ImageDecoder::ImageCodec image_codec; | 44 const ImageDecoder::ImageCodec image_codec; |
| 45 const LoadedCallback loaded_cb; | 45 const LoadedCallback loaded_cb; |
| 46 }; | 46 }; |
| 47 | 47 |
| 48 // Crops |image| to the square format and downsizes the image to | 48 // Crops |image| to the square format and downsizes the image to |
| 49 // |target_size| in pixels. On success, returns true and stores the cropped | 49 // |target_size| in pixels. On success, returns the bytes representation and |
| 50 // image in |bitmap| and the bytes representation in |byytes|. | 50 // stores the cropped image in |bitmap|. On failure, returns nullptr. |
| 51 bool CropImage(const SkBitmap& image, | 51 scoped_refptr<base::RefCountedBytes> CropImage(const SkBitmap& image, |
| 52 int target_size, | 52 int target_size, |
| 53 SkBitmap* bitmap, | 53 SkBitmap* bitmap) { |
| 54 user_manager::UserImage::Bytes* bytes) { | |
| 55 DCHECK_GT(target_size, 0); | 54 DCHECK_GT(target_size, 0); |
| 56 | 55 |
| 57 SkBitmap final_image; | 56 SkBitmap final_image; |
| 58 // Auto crop the image, taking the largest square in the center. | 57 // Auto crop the image, taking the largest square in the center. |
| 59 int pixels_per_side = std::min(image.width(), image.height()); | 58 int pixels_per_side = std::min(image.width(), image.height()); |
| 60 int x = (image.width() - pixels_per_side) / 2; | 59 int x = (image.width() - pixels_per_side) / 2; |
| 61 int y = (image.height() - pixels_per_side) / 2; | 60 int y = (image.height() - pixels_per_side) / 2; |
| 62 SkBitmap cropped_image = SkBitmapOperations::CreateTiledBitmap( | 61 SkBitmap cropped_image = SkBitmapOperations::CreateTiledBitmap( |
| 63 image, x, y, pixels_per_side, pixels_per_side); | 62 image, x, y, pixels_per_side, pixels_per_side); |
| 64 if (pixels_per_side > target_size) { | 63 if (pixels_per_side > target_size) { |
| 65 // Also downsize the image to save space and memory. | 64 // Also downsize the image to save space and memory. |
| 66 final_image = skia::ImageOperations::Resize( | 65 final_image = skia::ImageOperations::Resize( |
| 67 cropped_image, skia::ImageOperations::RESIZE_LANCZOS3, target_size, | 66 cropped_image, skia::ImageOperations::RESIZE_LANCZOS3, target_size, |
| 68 target_size); | 67 target_size); |
| 69 } else { | 68 } else { |
| 70 final_image = cropped_image; | 69 final_image = cropped_image; |
| 71 } | 70 } |
| 72 | 71 |
| 73 // Encode the cropped image to web-compatible bytes representation | 72 // Encode the cropped image to web-compatible bytes representation |
| 74 std::unique_ptr<user_manager::UserImage::Bytes> encoded = | 73 scoped_refptr<base::RefCountedBytes> encoded = |
| 75 user_manager::UserImage::Encode(final_image); | 74 user_manager::UserImage::Encode(final_image); |
| 76 if (!encoded) | 75 if (!encoded) |
|
achuithb
2016/11/22 21:16:54
Does this early return still make sense?
Why not:
satorux1
2016/11/24 02:13:40
good idea. done!
| |
| 77 return false; | 76 return nullptr; |
| 78 | 77 |
| 79 bitmap->swap(final_image); | 78 bitmap->swap(final_image); |
| 80 bytes->swap(*encoded); | 79 return encoded; |
| 81 return true; | |
| 82 } | 80 } |
| 83 | 81 |
| 84 // Handles the decoded image returned from ImageDecoder through the | 82 // Handles the decoded image returned from ImageDecoder through the |
| 85 // ImageRequest interface. | 83 // ImageRequest interface. |
| 86 class UserImageRequest : public ImageDecoder::ImageRequest { | 84 class UserImageRequest : public ImageDecoder::ImageRequest { |
| 87 public: | 85 public: |
| 88 UserImageRequest( | 86 UserImageRequest( |
| 89 const ImageInfo& image_info, | 87 const ImageInfo& image_info, |
| 90 const std::string& image_data, | 88 const std::string& image_data, |
| 91 scoped_refptr<base::SequencedTaskRunner> background_task_runner) | 89 scoped_refptr<base::SequencedTaskRunner> background_task_runner) |
| 92 : image_info_(image_info), | 90 : image_info_(image_info), |
| 93 image_data_(image_data.begin(), image_data.end()), | 91 // TODO(crbug.com/593251): Remove the data copy here. |
| 92 image_data_(new base::RefCountedBytes( | |
| 93 reinterpret_cast<const unsigned char*>(image_data.data()), | |
| 94 image_data.size())), | |
| 94 background_task_runner_(background_task_runner), | 95 background_task_runner_(background_task_runner), |
| 95 weak_ptr_factory_(this) {} | 96 weak_ptr_factory_(this) {} |
| 96 ~UserImageRequest() override {} | 97 ~UserImageRequest() override {} |
| 97 | 98 |
| 98 // ImageDecoder::ImageRequest implementation. | 99 // ImageDecoder::ImageRequest implementation. |
| 99 void OnImageDecoded(const SkBitmap& decoded_image) override; | 100 void OnImageDecoded(const SkBitmap& decoded_image) override; |
| 100 void OnDecodeImageFailed() override; | 101 void OnDecodeImageFailed() override; |
| 101 | 102 |
| 102 // Called after the image is cropped (and downsized) as needed. | 103 // Called after the image is cropped (and downsized) as needed. |
| 103 void OnImageCropped(SkBitmap* bitmap, | 104 void OnImageCropped(SkBitmap* bitmap, |
| 104 user_manager::UserImage::Bytes* bytes, | 105 scoped_refptr<base::RefCountedBytes> bytes); |
| 105 bool succeeded); | |
| 106 | 106 |
| 107 // Called after the image is finalized. |image_bytes_regenerated| is true | 107 // Called after the image is finalized. |image_bytes_regenerated| is true |
| 108 // if |image_bytes| is regenerated from the cropped image. | 108 // if |image_bytes| is regenerated from the cropped image. |
| 109 void OnImageFinalized(const SkBitmap& image, | 109 void OnImageFinalized(const SkBitmap& image, |
| 110 const user_manager::UserImage::Bytes& image_bytes, | 110 scoped_refptr<base::RefCountedBytes> image_bytes, |
| 111 bool image_bytes_regenerated); | 111 bool image_bytes_regenerated); |
| 112 | 112 |
| 113 private: | 113 private: |
| 114 const ImageInfo image_info_; | 114 const ImageInfo image_info_; |
| 115 const user_manager::UserImage::Bytes image_data_; | 115 scoped_refptr<base::RefCountedBytes> image_data_; |
| 116 scoped_refptr<base::SequencedTaskRunner> background_task_runner_; | 116 scoped_refptr<base::SequencedTaskRunner> background_task_runner_; |
| 117 | 117 |
| 118 // This should be the last member. | 118 // This should be the last member. |
| 119 base::WeakPtrFactory<UserImageRequest> weak_ptr_factory_; | 119 base::WeakPtrFactory<UserImageRequest> weak_ptr_factory_; |
| 120 }; | 120 }; |
| 121 | 121 |
| 122 void UserImageRequest::OnImageDecoded(const SkBitmap& decoded_image) { | 122 void UserImageRequest::OnImageDecoded(const SkBitmap& decoded_image) { |
| 123 int target_size = image_info_.pixels_per_side; | 123 int target_size = image_info_.pixels_per_side; |
| 124 if (target_size > 0) { | 124 if (target_size > 0) { |
| 125 // Cropping an image could be expensive, hence posting to the background | 125 // Cropping an image could be expensive, hence posting to the background |
| 126 // thread. | 126 // thread. |
| 127 SkBitmap* bitmap = new SkBitmap; | 127 SkBitmap* bitmap = new SkBitmap; |
| 128 user_manager::UserImage::Bytes* bytes = new user_manager::UserImage::Bytes; | |
| 129 base::PostTaskAndReplyWithResult( | 128 base::PostTaskAndReplyWithResult( |
| 130 background_task_runner_.get(), FROM_HERE, | 129 background_task_runner_.get(), FROM_HERE, |
| 131 base::Bind(&CropImage, decoded_image, target_size, bitmap, bytes), | 130 base::Bind(&CropImage, decoded_image, target_size, bitmap), |
| 132 base::Bind(&UserImageRequest::OnImageCropped, | 131 base::Bind(&UserImageRequest::OnImageCropped, |
| 133 weak_ptr_factory_.GetWeakPtr(), base::Owned(bitmap), | 132 weak_ptr_factory_.GetWeakPtr(), base::Owned(bitmap))); |
| 134 base::Owned(bytes))); | |
| 135 } else { | 133 } else { |
| 136 OnImageFinalized(decoded_image, image_data_, | 134 OnImageFinalized(decoded_image, image_data_, |
| 137 false /* image_bytes_regenerated */); | 135 false /* image_bytes_regenerated */); |
| 138 } | 136 } |
| 139 } | 137 } |
| 140 | 138 |
| 141 void UserImageRequest::OnImageCropped(SkBitmap* bitmap, | 139 void UserImageRequest::OnImageCropped( |
| 142 user_manager::UserImage::Bytes* bytes, | 140 SkBitmap* bitmap, |
| 143 bool succeeded) { | 141 scoped_refptr<base::RefCountedBytes> bytes) { |
| 144 DCHECK_GT(image_info_.pixels_per_side, 0); | 142 DCHECK_GT(image_info_.pixels_per_side, 0); |
| 145 | 143 |
| 146 if (!succeeded) { | 144 if (!bytes) { |
| 147 OnDecodeImageFailed(); | 145 OnDecodeImageFailed(); |
| 148 return; | 146 return; |
| 149 } | 147 } |
| 150 OnImageFinalized(*bitmap, *bytes, true /* image_bytes_regenerated */); | 148 OnImageFinalized(*bitmap, bytes, true /* image_bytes_regenerated */); |
| 151 } | 149 } |
| 152 | 150 |
| 153 void UserImageRequest::OnImageFinalized( | 151 void UserImageRequest::OnImageFinalized( |
| 154 const SkBitmap& image, | 152 const SkBitmap& image, |
| 155 const user_manager::UserImage::Bytes& image_bytes, | 153 scoped_refptr<base::RefCountedBytes> image_bytes, |
| 156 bool image_bytes_regenerated) { | 154 bool image_bytes_regenerated) { |
| 157 SkBitmap final_image = image; | 155 SkBitmap final_image = image; |
| 158 // Make the SkBitmap immutable as we won't modify it. This is important | 156 // Make the SkBitmap immutable as we won't modify it. This is important |
| 159 // because otherwise it gets duplicated during painting, wasting memory. | 157 // because otherwise it gets duplicated during painting, wasting memory. |
| 160 final_image.setImmutable(); | 158 final_image.setImmutable(); |
| 161 gfx::ImageSkia final_image_skia = | 159 gfx::ImageSkia final_image_skia = |
| 162 gfx::ImageSkia::CreateFrom1xBitmap(final_image); | 160 gfx::ImageSkia::CreateFrom1xBitmap(final_image); |
| 163 final_image_skia.MakeThreadSafe(); | 161 final_image_skia.MakeThreadSafe(); |
| 164 std::unique_ptr<user_manager::UserImage> user_image( | 162 std::unique_ptr<user_manager::UserImage> user_image( |
| 165 new user_manager::UserImage(final_image_skia, image_bytes)); | 163 new user_manager::UserImage(final_image_skia, image_bytes)); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 220 ImageDecoder::ImageCodec image_codec, | 218 ImageDecoder::ImageCodec image_codec, |
| 221 int pixels_per_side, | 219 int pixels_per_side, |
| 222 const LoadedCallback& loaded_cb) { | 220 const LoadedCallback& loaded_cb) { |
| 223 DecodeImage( | 221 DecodeImage( |
| 224 ImageInfo(base::FilePath(), pixels_per_side, image_codec, loaded_cb), | 222 ImageInfo(base::FilePath(), pixels_per_side, image_codec, loaded_cb), |
| 225 background_task_runner, data.get(), true /* data_is_ready */); | 223 background_task_runner, data.get(), true /* data_is_ready */); |
| 226 } | 224 } |
| 227 | 225 |
| 228 } // namespace user_image_loader | 226 } // namespace user_image_loader |
| 229 } // namespace chromeos | 227 } // namespace chromeos |
| OLD | NEW |