| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 "ui/gfx/image/image_skia.h" | 5 #include "ui/gfx/image/image_skia.h" |
| 6 | 6 |
| 7 #include <algorithm> |
| 8 #include <cmath> |
| 7 #include <limits> | 9 #include <limits> |
| 8 #include <cmath> | |
| 9 | 10 |
| 10 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/memory/scoped_ptr.h" |
| 13 #include "ui/gfx/image/image_skia_source.h" |
| 11 #include "ui/gfx/size.h" | 14 #include "ui/gfx/size.h" |
| 12 #include "ui/gfx/skia_util.h" | 15 #include "ui/gfx/skia_util.h" |
| 13 | 16 |
| 14 namespace gfx { | 17 namespace gfx { |
| 18 namespace { |
| 19 |
| 20 // static |
| 21 gfx::ImageSkiaRep& NullImageRep() { |
| 22 CR_DEFINE_STATIC_LOCAL(ImageSkiaRep, null_image_rep, ()); |
| 23 return null_image_rep; |
| 24 } |
| 25 |
| 26 } // namespace |
| 15 | 27 |
| 16 namespace internal { | 28 namespace internal { |
| 29 namespace { |
| 30 |
| 31 class Matcher { |
| 32 public: |
| 33 explicit Matcher(ui::ScaleFactor scale_factor) : scale_factor_(scale_factor) { |
| 34 } |
| 35 |
| 36 bool operator()(const ImageSkiaRep& rep) const { |
| 37 return rep.scale_factor() == scale_factor_; |
| 38 } |
| 39 |
| 40 private: |
| 41 ui::ScaleFactor scale_factor_; |
| 42 }; |
| 43 |
| 44 } // namespace |
| 17 | 45 |
| 18 // A helper class such that ImageSkia can be cheaply copied. ImageSkia holds a | 46 // A helper class such that ImageSkia can be cheaply copied. ImageSkia holds a |
| 19 // refptr instance of ImageSkiaStorage, which in turn holds all of ImageSkia's | 47 // refptr instance of ImageSkiaStorage, which in turn holds all of ImageSkia's |
| 20 // information. | 48 // information. |
| 21 class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> { | 49 class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> { |
| 22 public: | 50 public: |
| 23 ImageSkiaStorage() { | 51 ImageSkiaStorage(ImageSkiaSource* source, const gfx::Size& size) |
| 52 : source_(source), |
| 53 size_(size) { |
| 24 } | 54 } |
| 25 | 55 |
| 26 std::vector<gfx::ImageSkiaRep>& image_reps() { return image_reps_; } | 56 std::vector<gfx::ImageSkiaRep>& image_reps() { return image_reps_; } |
| 27 | 57 |
| 28 void set_size(const gfx::Size& size) { size_ = size; } | |
| 29 const gfx::Size& size() const { return size_; } | 58 const gfx::Size& size() const { return size_; } |
| 30 | 59 |
| 60 // Returns the iterator of the image rep whose density best matches |
| 61 // |scale_factor|. If the image for the |scale_factor| doesn't exist |
| 62 // in the storage and |storage| is set, it fetches new image by calling |
| 63 // |ImageSkiaSource::GetImageForScale|. If the source returns the |
| 64 // image with different scale factor (if the image doesn't exist in |
| 65 // resource, for example), it will fallback to closest image rep. |
| 66 std::vector<ImageSkiaRep>::iterator FindRepresentation( |
| 67 ui::ScaleFactor scale_factor, bool fetch_new_image) const { |
| 68 ImageSkiaStorage* non_const = const_cast<ImageSkiaStorage*>(this); |
| 69 |
| 70 float scale = ui::GetScaleFactorScale(scale_factor); |
| 71 ImageSkia::ImageSkiaReps::iterator closest_iter = |
| 72 non_const->image_reps().end(); |
| 73 ImageSkia::ImageSkiaReps::iterator exact_iter = |
| 74 non_const->image_reps().end(); |
| 75 float smallest_diff = std::numeric_limits<float>::max(); |
| 76 for (ImageSkia::ImageSkiaReps::iterator it = |
| 77 non_const->image_reps().begin(); |
| 78 it < image_reps_.end(); ++it) { |
| 79 if (it->GetScale() == scale) { |
| 80 // found exact match |
| 81 fetch_new_image = false; |
| 82 if (it->is_null()) |
| 83 continue; |
| 84 exact_iter = it; |
| 85 break; |
| 86 } |
| 87 float diff = std::abs(it->GetScale() - scale); |
| 88 if (diff < smallest_diff && !it->is_null()) { |
| 89 closest_iter = it; |
| 90 smallest_diff = diff; |
| 91 } |
| 92 } |
| 93 |
| 94 if (fetch_new_image && source_.get()) { |
| 95 ImageSkiaRep image = source_->GetImageForScale(scale_factor); |
| 96 |
| 97 // If the source returned the new image, store it. |
| 98 if (!image.is_null() && |
| 99 std::find_if(image_reps_.begin(), image_reps_.end(), |
| 100 Matcher(image.scale_factor())) == image_reps_.end()) { |
| 101 non_const->image_reps().push_back(image); |
| 102 } |
| 103 |
| 104 // If the result image's scale factor isn't same as the expected |
| 105 // scale factor, create null ImageSkiaRep with the |scale_factor| |
| 106 // so that the next lookup will fallback to the closest scale. |
| 107 if (image.is_null() || image.scale_factor() != scale_factor) { |
| 108 non_const->image_reps().push_back( |
| 109 ImageSkiaRep(SkBitmap(), scale_factor)); |
| 110 } |
| 111 |
| 112 // image_reps_ must have the exact much now, so find again. |
| 113 return FindRepresentation(scale_factor, false); |
| 114 } |
| 115 return exact_iter != image_reps_.end() ? exact_iter : closest_iter; |
| 116 } |
| 117 |
| 31 private: | 118 private: |
| 32 ~ImageSkiaStorage() { | 119 ~ImageSkiaStorage() { |
| 33 } | 120 } |
| 34 | 121 |
| 35 // Vector of bitmaps and their associated scale factor. | 122 // Vector of bitmaps and their associated scale factor. |
| 36 std::vector<gfx::ImageSkiaRep> image_reps_; | 123 std::vector<gfx::ImageSkiaRep> image_reps_; |
| 37 | 124 |
| 125 scoped_ptr<ImageSkiaSource> source_; |
| 126 |
| 38 // Size of the image in DIP. | 127 // Size of the image in DIP. |
| 39 gfx::Size size_; | 128 const gfx::Size size_; |
| 40 | 129 |
| 41 friend class base::RefCounted<ImageSkiaStorage>; | 130 friend class base::RefCounted<ImageSkiaStorage>; |
| 42 }; | 131 }; |
| 43 | 132 |
| 44 } // internal | 133 } // internal |
| 45 | 134 |
| 46 ImageSkia::ImageSkia() : storage_(NULL) { | 135 ImageSkia::ImageSkia() : storage_(NULL) { |
| 47 } | 136 } |
| 48 | 137 |
| 138 ImageSkia::ImageSkia(ImageSkiaSource* source, const gfx::Size& size) |
| 139 : storage_(new internal::ImageSkiaStorage(source, size)) { |
| 140 DCHECK(source); |
| 141 } |
| 142 |
| 49 ImageSkia::ImageSkia(const SkBitmap& bitmap) { | 143 ImageSkia::ImageSkia(const SkBitmap& bitmap) { |
| 50 Init(ImageSkiaRep(bitmap)); | 144 Init(ImageSkiaRep(bitmap)); |
| 51 } | 145 } |
| 52 | 146 |
| 53 ImageSkia::ImageSkia(const ImageSkiaRep& image_rep) { | 147 ImageSkia::ImageSkia(const ImageSkiaRep& image_rep) { |
| 54 Init(image_rep); | 148 Init(image_rep); |
| 55 } | 149 } |
| 56 | 150 |
| 57 ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) { | 151 ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) { |
| 58 } | 152 } |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 Init(image_rep); | 190 Init(image_rep); |
| 97 else | 191 else |
| 98 storage_->image_reps().push_back(image_rep); | 192 storage_->image_reps().push_back(image_rep); |
| 99 } | 193 } |
| 100 | 194 |
| 101 void ImageSkia::RemoveRepresentation(ui::ScaleFactor scale_factor) { | 195 void ImageSkia::RemoveRepresentation(ui::ScaleFactor scale_factor) { |
| 102 if (isNull()) | 196 if (isNull()) |
| 103 return; | 197 return; |
| 104 | 198 |
| 105 ImageSkiaReps& image_reps = storage_->image_reps(); | 199 ImageSkiaReps& image_reps = storage_->image_reps(); |
| 106 ImageSkiaReps::iterator it = FindRepresentation(scale_factor); | 200 ImageSkiaReps::iterator it = |
| 201 storage_->FindRepresentation(scale_factor, false); |
| 107 if (it != image_reps.end() && it->scale_factor() == scale_factor) | 202 if (it != image_reps.end() && it->scale_factor() == scale_factor) |
| 108 image_reps.erase(it); | 203 image_reps.erase(it); |
| 109 } | 204 } |
| 110 | 205 |
| 111 bool ImageSkia::HasRepresentation(ui::ScaleFactor scale_factor) { | 206 bool ImageSkia::HasRepresentation(ui::ScaleFactor scale_factor) { |
| 112 if (isNull()) | 207 if (isNull()) |
| 113 return false; | 208 return false; |
| 114 | 209 |
| 115 ImageSkiaReps::iterator it = FindRepresentation(scale_factor); | 210 ImageSkiaReps::iterator it = |
| 211 storage_->FindRepresentation(scale_factor, false); |
| 116 return (it != storage_->image_reps().end() && | 212 return (it != storage_->image_reps().end() && |
| 117 it->scale_factor() == scale_factor); | 213 it->scale_factor() == scale_factor); |
| 118 } | 214 } |
| 119 | 215 |
| 120 const ImageSkiaRep& ImageSkia::GetRepresentation( | 216 const ImageSkiaRep& ImageSkia::GetRepresentation( |
| 121 ui::ScaleFactor scale_factor) const { | 217 ui::ScaleFactor scale_factor) const { |
| 122 if (isNull()) | 218 if (isNull()) |
| 123 return NullImageRep(); | 219 return NullImageRep(); |
| 124 | 220 |
| 125 ImageSkiaReps::iterator it = FindRepresentation(scale_factor); | 221 ImageSkiaReps::iterator it = storage_->FindRepresentation(scale_factor, true); |
| 126 if (it == storage_->image_reps().end()) | 222 if (it == storage_->image_reps().end()) |
| 127 return NullImageRep(); | 223 return NullImageRep(); |
| 128 | 224 |
| 129 return *it; | 225 return *it; |
| 130 } | 226 } |
| 131 | 227 |
| 132 bool ImageSkia::empty() const { | 228 bool ImageSkia::empty() const { |
| 133 return isNull() || storage_->size().IsEmpty(); | 229 return isNull() || storage_->size().IsEmpty(); |
| 134 } | 230 } |
| 135 | 231 |
| 136 int ImageSkia::width() const { | 232 int ImageSkia::width() const { |
| 137 return isNull() ? 0 : storage_->size().width(); | 233 return isNull() ? 0 : storage_->size().width(); |
| 138 } | 234 } |
| 139 | 235 |
| 236 gfx::Size ImageSkia::size() const { |
| 237 return gfx::Size(width(), height()); |
| 238 } |
| 239 |
| 140 int ImageSkia::height() const { | 240 int ImageSkia::height() const { |
| 141 return isNull() ? 0 : storage_->size().height(); | 241 return isNull() ? 0 : storage_->size().height(); |
| 142 } | 242 } |
| 143 | 243 |
| 144 bool ImageSkia::extractSubset(ImageSkia* dst, const SkIRect& subset) const { | 244 bool ImageSkia::extractSubset(ImageSkia* dst, const SkIRect& subset) const { |
| 145 if (isNull()) | 245 if (isNull()) |
| 146 return false; | 246 return false; |
| 147 ImageSkia image; | 247 ImageSkia image; |
| 148 ImageSkiaReps& image_reps = storage_->image_reps(); | 248 ImageSkiaReps& image_reps = storage_->image_reps(); |
| 149 for (ImageSkiaReps::iterator it = image_reps.begin(); | 249 for (ImageSkiaReps::iterator it = image_reps.begin(); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 184 | 284 |
| 185 return &storage_->image_reps()[0].sk_bitmap(); | 285 return &storage_->image_reps()[0].sk_bitmap(); |
| 186 } | 286 } |
| 187 | 287 |
| 188 void ImageSkia::Init(const ImageSkiaRep& image_rep) { | 288 void ImageSkia::Init(const ImageSkiaRep& image_rep) { |
| 189 // TODO(pkotwicz): The image should be null whenever image rep is null. | 289 // TODO(pkotwicz): The image should be null whenever image rep is null. |
| 190 if (image_rep.sk_bitmap().empty()) { | 290 if (image_rep.sk_bitmap().empty()) { |
| 191 storage_ = NULL; | 291 storage_ = NULL; |
| 192 return; | 292 return; |
| 193 } | 293 } |
| 194 storage_ = new internal::ImageSkiaStorage(); | 294 storage_ = new internal::ImageSkiaStorage( |
| 195 storage_->set_size(gfx::Size(image_rep.GetWidth(), image_rep.GetHeight())); | 295 NULL, gfx::Size(image_rep.GetWidth(), image_rep.GetHeight())); |
| 196 storage_->image_reps().push_back(image_rep); | 296 storage_->image_reps().push_back(image_rep); |
| 197 } | 297 } |
| 198 | 298 |
| 199 // static | |
| 200 ImageSkiaRep& ImageSkia::NullImageRep() { | |
| 201 CR_DEFINE_STATIC_LOCAL(ImageSkiaRep, null_image_rep, ()); | |
| 202 return null_image_rep; | |
| 203 } | |
| 204 | |
| 205 std::vector<ImageSkiaRep>::iterator ImageSkia::FindRepresentation( | |
| 206 ui::ScaleFactor scale_factor) const { | |
| 207 DCHECK(!isNull()); | |
| 208 | |
| 209 float scale = ui::GetScaleFactorScale(scale_factor); | |
| 210 ImageSkiaReps& image_reps = storage_->image_reps(); | |
| 211 ImageSkiaReps::iterator closest_iter = image_reps.end(); | |
| 212 float smallest_diff = std::numeric_limits<float>::max(); | |
| 213 for (ImageSkiaReps::iterator it = image_reps.begin(); | |
| 214 it < image_reps.end(); | |
| 215 ++it) { | |
| 216 float diff = std::abs(it->GetScale() - scale); | |
| 217 if (diff < smallest_diff) { | |
| 218 closest_iter = it; | |
| 219 smallest_diff = diff; | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 return closest_iter; | |
| 224 } | |
| 225 | |
| 226 } // namespace gfx | 299 } // namespace gfx |
| OLD | NEW |