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 |