Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(196)

Side by Side Diff: ui/gfx/image/image_skia.cc

Issue 10694045: Loading/Creating images for mutiple scale factors on the fly (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « ui/gfx/image/image_skia.h ('k') | ui/gfx/image/image_skia_rep.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 }
pkotwicz 2012/07/01 22:22:23 This code is ok. However, I would rather that if t
oshima 2012/07/02 16:43:34 ImageSkia::GetRepresentation doesn't guarantee tha
pkotwicz 2012/07/02 17:13:53 I think there are two aspects. 1) We currently som
pkotwicz 2012/07/02 17:26:21 Btw, it might be sufficient to scale the assets wh
oshima 2012/07/02 17:26:47 grit will scale if necessary. Even if it doesn't 1
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 }
141
49 ImageSkia::ImageSkia(const SkBitmap& bitmap) { 142 ImageSkia::ImageSkia(const SkBitmap& bitmap) {
50 Init(ImageSkiaRep(bitmap)); 143 Init(ImageSkiaRep(bitmap));
51 } 144 }
52 145
53 ImageSkia::ImageSkia(const ImageSkiaRep& image_rep) { 146 ImageSkia::ImageSkia(const ImageSkiaRep& image_rep) {
54 Init(image_rep); 147 Init(image_rep);
55 } 148 }
56 149
57 ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) { 150 ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) {
58 } 151 }
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
96 Init(image_rep); 189 Init(image_rep);
97 else 190 else
98 storage_->image_reps().push_back(image_rep); 191 storage_->image_reps().push_back(image_rep);
99 } 192 }
100 193
101 void ImageSkia::RemoveRepresentation(ui::ScaleFactor scale_factor) { 194 void ImageSkia::RemoveRepresentation(ui::ScaleFactor scale_factor) {
102 if (isNull()) 195 if (isNull())
103 return; 196 return;
104 197
105 ImageSkiaReps& image_reps = storage_->image_reps(); 198 ImageSkiaReps& image_reps = storage_->image_reps();
106 ImageSkiaReps::iterator it = FindRepresentation(scale_factor); 199 ImageSkiaReps::iterator it =
200 storage_->FindRepresentation(scale_factor, false);
107 if (it != image_reps.end() && it->scale_factor() == scale_factor) 201 if (it != image_reps.end() && it->scale_factor() == scale_factor)
108 image_reps.erase(it); 202 image_reps.erase(it);
109 } 203 }
110 204
111 bool ImageSkia::HasRepresentation(ui::ScaleFactor scale_factor) { 205 bool ImageSkia::HasRepresentation(ui::ScaleFactor scale_factor) {
112 if (isNull()) 206 if (isNull())
113 return false; 207 return false;
114 208
115 ImageSkiaReps::iterator it = FindRepresentation(scale_factor); 209 ImageSkiaReps::iterator it =
210 storage_->FindRepresentation(scale_factor, false);
116 return (it != storage_->image_reps().end() && 211 return (it != storage_->image_reps().end() &&
117 it->scale_factor() == scale_factor); 212 it->scale_factor() == scale_factor);
118 } 213 }
119 214
120 const ImageSkiaRep& ImageSkia::GetRepresentation( 215 const ImageSkiaRep& ImageSkia::GetRepresentation(
121 ui::ScaleFactor scale_factor) const { 216 ui::ScaleFactor scale_factor) const {
122 if (isNull()) 217 if (isNull())
123 return NullImageRep(); 218 return NullImageRep();
124 219
125 ImageSkiaReps::iterator it = FindRepresentation(scale_factor); 220 ImageSkiaReps::iterator it = storage_->FindRepresentation(scale_factor, true);
126 if (it == storage_->image_reps().end()) 221 if (it == storage_->image_reps().end())
127 return NullImageRep(); 222 return NullImageRep();
128 223
129 return *it; 224 return *it;
130 } 225 }
131 226
132 bool ImageSkia::empty() const { 227 bool ImageSkia::empty() const {
133 return isNull() || storage_->size().IsEmpty(); 228 return isNull() || storage_->size().IsEmpty();
134 } 229 }
135 230
136 int ImageSkia::width() const { 231 int ImageSkia::width() const {
137 return isNull() ? 0 : storage_->size().width(); 232 return isNull() ? 0 : storage_->size().width();
138 } 233 }
139 234
235 gfx::Size ImageSkia::size() const {
236 return gfx::Size(width(), height());
237 }
238
140 int ImageSkia::height() const { 239 int ImageSkia::height() const {
141 return isNull() ? 0 : storage_->size().height(); 240 return isNull() ? 0 : storage_->size().height();
142 } 241 }
143 242
144 bool ImageSkia::extractSubset(ImageSkia* dst, const SkIRect& subset) const { 243 bool ImageSkia::extractSubset(ImageSkia* dst, const SkIRect& subset) const {
145 if (isNull()) 244 if (isNull())
146 return false; 245 return false;
147 ImageSkia image; 246 ImageSkia image;
148 ImageSkiaReps& image_reps = storage_->image_reps(); 247 ImageSkiaReps& image_reps = storage_->image_reps();
149 for (ImageSkiaReps::iterator it = image_reps.begin(); 248 for (ImageSkiaReps::iterator it = image_reps.begin();
(...skipping 15 matching lines...) Expand all
165 return false; 264 return false;
166 265
167 *dst = image; 266 *dst = image;
168 return true; 267 return true;
169 } 268 }
170 269
171 std::vector<ImageSkiaRep> ImageSkia::image_reps() const { 270 std::vector<ImageSkiaRep> ImageSkia::image_reps() const {
172 if (isNull()) 271 if (isNull())
173 return std::vector<ImageSkiaRep>(); 272 return std::vector<ImageSkiaRep>();
174 273
175 return storage_->image_reps(); 274 return storage_->image_reps();
pkotwicz 2012/07/01 22:22:23 What happens here when you have an ImageSkiaSource
oshima 2012/07/02 16:43:34 The semantics of this api is and has been "return
pkotwicz 2012/07/02 17:13:53 A couple places where we might want to use 2 - Con
oshima 2012/07/02 17:26:47 Are both cases for mac? We have no plan to use Ima
pkotwicz 2012/07/02 18:05:12 We will most likely be using ImageSkiaSource for m
oshima 2012/07/02 18:19:30 Let's revisit if we find such case then.
176 } 275 }
177 276
178 const SkBitmap* ImageSkia::bitmap() const { 277 const SkBitmap* ImageSkia::bitmap() const {
179 if (isNull()) { 278 if (isNull()) {
180 // Callers expect a ImageSkiaRep even if it is |isNull()|. 279 // Callers expect a ImageSkiaRep even if it is |isNull()|.
181 // TODO(pkotwicz): Fix this. 280 // TODO(pkotwicz): Fix this.
182 return &NullImageRep().sk_bitmap(); 281 return &NullImageRep().sk_bitmap();
183 } 282 }
184 283
185 return &storage_->image_reps()[0].sk_bitmap(); 284 return &storage_->image_reps()[0].sk_bitmap();
186 } 285 }
187 286
188 void ImageSkia::Init(const ImageSkiaRep& image_rep) { 287 void ImageSkia::Init(const ImageSkiaRep& image_rep) {
189 // TODO(pkotwicz): The image should be null whenever image rep is null. 288 // TODO(pkotwicz): The image should be null whenever image rep is null.
190 if (image_rep.sk_bitmap().empty()) { 289 if (image_rep.sk_bitmap().empty()) {
191 storage_ = NULL; 290 storage_ = NULL;
192 return; 291 return;
193 } 292 }
194 storage_ = new internal::ImageSkiaStorage(); 293 storage_ = new internal::ImageSkiaStorage(
195 storage_->set_size(gfx::Size(image_rep.GetWidth(), image_rep.GetHeight())); 294 NULL, gfx::Size(image_rep.GetWidth(), image_rep.GetHeight()));
196 storage_->image_reps().push_back(image_rep); 295 storage_->image_reps().push_back(image_rep);
197 } 296 }
198 297
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 298 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/image/image_skia.h ('k') | ui/gfx/image/image_skia_rep.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698