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

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

Issue 10820049: Load 2x resources on demand (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: updated comment Created 8 years, 3 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_source.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> 7 #include <algorithm>
8 #include <cmath> 8 #include <cmath>
9 #include <limits> 9 #include <limits>
10 10
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h" 12 #include "base/memory/scoped_ptr.h"
13 #include "base/threading/non_thread_safe.h"
13 #include "ui/gfx/image/image_skia_operations.h" 14 #include "ui/gfx/image/image_skia_operations.h"
14 #include "ui/gfx/image/image_skia_source.h" 15 #include "ui/gfx/image/image_skia_source.h"
15 #include "ui/gfx/rect.h" 16 #include "ui/gfx/rect.h"
16 #include "ui/gfx/size.h" 17 #include "ui/gfx/size.h"
17 #include "ui/gfx/skia_util.h" 18 #include "ui/gfx/skia_util.h"
18 19
19 namespace gfx { 20 namespace gfx {
20 namespace { 21 namespace {
21 22
22 // static 23 // static
(...skipping 18 matching lines...) Expand all
41 42
42 private: 43 private:
43 ui::ScaleFactor scale_factor_; 44 ui::ScaleFactor scale_factor_;
44 }; 45 };
45 46
46 } // namespace 47 } // namespace
47 48
48 // A helper class such that ImageSkia can be cheaply copied. ImageSkia holds a 49 // A helper class such that ImageSkia can be cheaply copied. ImageSkia holds a
49 // refptr instance of ImageSkiaStorage, which in turn holds all of ImageSkia's 50 // refptr instance of ImageSkiaStorage, which in turn holds all of ImageSkia's
50 // information. 51 // information.
51 class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> { 52 class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage>,
53 public base::NonThreadSafe {
52 public: 54 public:
53 ImageSkiaStorage(ImageSkiaSource* source, const gfx::Size& size) 55 ImageSkiaStorage(ImageSkiaSource* source, const gfx::Size& size)
54 : source_(source), 56 : source_(source),
55 size_(size) { 57 size_(size),
58 read_only_(false) {
56 } 59 }
57 60
58 bool has_source() const { return source_.get() != NULL; } 61 bool has_source() const { return source_.get() != NULL; }
59 62
60 std::vector<gfx::ImageSkiaRep>& image_reps() { return image_reps_; } 63 std::vector<gfx::ImageSkiaRep>& image_reps() { return image_reps_; }
61 64
62 const gfx::Size& size() const { return size_; } 65 const gfx::Size& size() const { return size_; }
63 66
67 bool read_only() const { return read_only_; }
68
69 void DeleteSource() {
70 source_.reset();
71 }
72
73 void SetReadOnly() {
74 read_only_ = true;
75 }
76
77 void DetachFromThread() {
78 base::NonThreadSafe::DetachFromThread();
79 }
80
81 // Checks if the current thread can safely modify the storage.
82 bool CanModify() const {
83 return !read_only_ && CalledOnValidThread();
84 }
85
86 // Checks if the current thread can safely read the storage.
87 bool CanRead() const {
88 return (read_only_ && !source_.get()) || CalledOnValidThread();
89 }
90
64 // Returns the iterator of the image rep whose density best matches 91 // Returns the iterator of the image rep whose density best matches
65 // |scale_factor|. If the image for the |scale_factor| doesn't exist 92 // |scale_factor|. If the image for the |scale_factor| doesn't exist
66 // in the storage and |storage| is set, it fetches new image by calling 93 // in the storage and |storage| is set, it fetches new image by calling
67 // |ImageSkiaSource::GetImageForScale|. If the source returns the 94 // |ImageSkiaSource::GetImageForScale|. If the source returns the
68 // image with different scale factor (if the image doesn't exist in 95 // image with different scale factor (if the image doesn't exist in
69 // resource, for example), it will fallback to closest image rep. 96 // resource, for example), it will fallback to closest image rep.
70 std::vector<ImageSkiaRep>::iterator FindRepresentation( 97 std::vector<ImageSkiaRep>::iterator FindRepresentation(
71 ui::ScaleFactor scale_factor, bool fetch_new_image) const { 98 ui::ScaleFactor scale_factor, bool fetch_new_image) const {
72 ImageSkiaStorage* non_const = const_cast<ImageSkiaStorage*>(this); 99 ImageSkiaStorage* non_const = const_cast<ImageSkiaStorage*>(this);
73 100
(...skipping 15 matching lines...) Expand all
89 break; 116 break;
90 } 117 }
91 float diff = std::abs(it->GetScale() - scale); 118 float diff = std::abs(it->GetScale() - scale);
92 if (diff < smallest_diff && !it->is_null()) { 119 if (diff < smallest_diff && !it->is_null()) {
93 closest_iter = it; 120 closest_iter = it;
94 smallest_diff = diff; 121 smallest_diff = diff;
95 } 122 }
96 } 123 }
97 124
98 if (fetch_new_image && source_.get()) { 125 if (fetch_new_image && source_.get()) {
126 DCHECK(CalledOnValidThread()) <<
127 "An ImageSkia with the source must be accessed by the same thread.";
128
99 ImageSkiaRep image = source_->GetImageForScale(scale_factor); 129 ImageSkiaRep image = source_->GetImageForScale(scale_factor);
100 130
101 // If the source returned the new image, store it. 131 // If the source returned the new image, store it.
102 if (!image.is_null() && 132 if (!image.is_null() &&
103 std::find_if(image_reps_.begin(), image_reps_.end(), 133 std::find_if(image_reps_.begin(), image_reps_.end(),
104 Matcher(image.scale_factor())) == image_reps_.end()) { 134 Matcher(image.scale_factor())) == image_reps_.end()) {
105 non_const->image_reps().push_back(image); 135 non_const->image_reps().push_back(image);
106 } 136 }
107 137
108 // If the result image's scale factor isn't same as the expected 138 // If the result image's scale factor isn't same as the expected
109 // scale factor, create null ImageSkiaRep with the |scale_factor| 139 // scale factor, create null ImageSkiaRep with the |scale_factor|
110 // so that the next lookup will fallback to the closest scale. 140 // so that the next lookup will fallback to the closest scale.
111 if (image.is_null() || image.scale_factor() != scale_factor) { 141 if (image.is_null() || image.scale_factor() != scale_factor) {
112 non_const->image_reps().push_back( 142 non_const->image_reps().push_back(
113 ImageSkiaRep(SkBitmap(), scale_factor)); 143 ImageSkiaRep(SkBitmap(), scale_factor));
114 } 144 }
115 145
116 // image_reps_ must have the exact much now, so find again. 146 // image_reps_ must have the exact much now, so find again.
117 return FindRepresentation(scale_factor, false); 147 return FindRepresentation(scale_factor, false);
118 } 148 }
119 return exact_iter != image_reps_.end() ? exact_iter : closest_iter; 149 return exact_iter != image_reps_.end() ? exact_iter : closest_iter;
120 } 150 }
121 151
122 private: 152 private:
123 ~ImageSkiaStorage() { 153 virtual ~ImageSkiaStorage() {
154 // We only care if the storage is modified by the same thread.
155 // Don't blow up even if someone else deleted the ImageSkia.
156 DetachFromThread();
124 } 157 }
125 158
126 // Vector of bitmaps and their associated scale factor. 159 // Vector of bitmaps and their associated scale factor.
127 std::vector<gfx::ImageSkiaRep> image_reps_; 160 std::vector<gfx::ImageSkiaRep> image_reps_;
128 161
129 scoped_ptr<ImageSkiaSource> source_; 162 scoped_ptr<ImageSkiaSource> source_;
130 163
131 // Size of the image in DIP. 164 // Size of the image in DIP.
132 const gfx::Size size_; 165 const gfx::Size size_;
133 166
167 bool read_only_;
168
134 friend class base::RefCounted<ImageSkiaStorage>; 169 friend class base::RefCounted<ImageSkiaStorage>;
135 }; 170 };
136 171
137 } // internal 172 } // internal
138 173
139 ImageSkia::ImageSkia() : storage_(NULL) { 174 ImageSkia::ImageSkia() : storage_(NULL) {
140 } 175 }
141 176
142 ImageSkia::ImageSkia(ImageSkiaSource* source, const gfx::Size& size) 177 ImageSkia::ImageSkia(ImageSkiaSource* source, const gfx::Size& size)
143 : storage_(new internal::ImageSkiaStorage(source, size)) { 178 : storage_(new internal::ImageSkiaStorage(source, size)) {
144 DCHECK(source); 179 DCHECK(source);
180 // No other thread has reference to this, so it's safe to detach the thread.
181 DetachStorageFromThread();
145 } 182 }
146 183
147 ImageSkia::ImageSkia(const SkBitmap& bitmap) { 184 ImageSkia::ImageSkia(const SkBitmap& bitmap) {
148 Init(ImageSkiaRep(bitmap, ui::SCALE_FACTOR_100P)); 185 Init(ImageSkiaRep(bitmap, ui::SCALE_FACTOR_100P));
186 // No other thread has reference to this, so it's safe to detach the thread.
187 DetachStorageFromThread();
149 } 188 }
150 189
151 ImageSkia::ImageSkia(const ImageSkiaRep& image_rep) { 190 ImageSkia::ImageSkia(const ImageSkiaRep& image_rep) {
152 Init(image_rep); 191 Init(image_rep);
192 // No other thread has reference to this, so it's safe to detach the thread.
193 DetachStorageFromThread();
153 } 194 }
154 195
155 ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) { 196 ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) {
156 } 197 }
157 198
158 ImageSkia& ImageSkia::operator=(const ImageSkia& other) { 199 ImageSkia& ImageSkia::operator=(const ImageSkia& other) {
159 storage_ = other.storage_; 200 storage_ = other.storage_;
160 return *this; 201 return *this;
161 } 202 }
162 203
163 ImageSkia::~ImageSkia() { 204 ImageSkia::~ImageSkia() {
164 } 205 }
165 206
207 ImageSkia ImageSkia::DeepCopy() const {
208 ImageSkia copy;
209 if (isNull())
210 return copy;
211
212 CHECK(CanRead());
213
214 std::vector<gfx::ImageSkiaRep>& reps = storage_->image_reps();
215 for (std::vector<gfx::ImageSkiaRep>::iterator iter = reps.begin();
216 iter != reps.end(); ++iter) {
217 copy.AddRepresentation(*iter);
218 }
219 // The copy has its own storage. Detach the copy from the current
220 // thread so that other thread can use this.
221 if (!copy.isNull())
222 copy.storage_->DetachFromThread();
223 return copy;
224 }
225
166 bool ImageSkia::BackedBySameObjectAs(const gfx::ImageSkia& other) const { 226 bool ImageSkia::BackedBySameObjectAs(const gfx::ImageSkia& other) const {
167 return storage_.get() == other.storage_.get(); 227 return storage_.get() == other.storage_.get();
168 } 228 }
169 229
170 void ImageSkia::AddRepresentation(const ImageSkiaRep& image_rep) { 230 void ImageSkia::AddRepresentation(const ImageSkiaRep& image_rep) {
171 DCHECK(!image_rep.is_null()); 231 DCHECK(!image_rep.is_null());
172 232
173 if (isNull()) 233 // TODO(oshima): This method should be called |SetRepresentation|
234 // and replace the existing rep if there is already one with the
235 // same scale factor so that we can guarantee that a ImageSkia
236 // instance contians only one image rep per scale factor. This is
237 // not possible now as ImageLoadingTracker currently stores need
238 // this feature, but this needs to be fixed.
239 if (isNull()) {
174 Init(image_rep); 240 Init(image_rep);
175 else 241 } else {
242 CHECK(CanModify());
176 storage_->image_reps().push_back(image_rep); 243 storage_->image_reps().push_back(image_rep);
244 }
177 } 245 }
178 246
179 void ImageSkia::RemoveRepresentation(ui::ScaleFactor scale_factor) { 247 void ImageSkia::RemoveRepresentation(ui::ScaleFactor scale_factor) {
180 if (isNull()) 248 if (isNull())
181 return; 249 return;
250 CHECK(CanModify());
182 251
183 ImageSkiaReps& image_reps = storage_->image_reps(); 252 ImageSkiaReps& image_reps = storage_->image_reps();
184 ImageSkiaReps::iterator it = 253 ImageSkiaReps::iterator it =
185 storage_->FindRepresentation(scale_factor, false); 254 storage_->FindRepresentation(scale_factor, false);
186 if (it != image_reps.end() && it->scale_factor() == scale_factor) 255 if (it != image_reps.end() && it->scale_factor() == scale_factor)
187 image_reps.erase(it); 256 image_reps.erase(it);
188 } 257 }
189 258
190 bool ImageSkia::HasRepresentation(ui::ScaleFactor scale_factor) const { 259 bool ImageSkia::HasRepresentation(ui::ScaleFactor scale_factor) const {
191 if (isNull()) 260 if (isNull())
192 return false; 261 return false;
262 CHECK(CanRead());
193 263
194 ImageSkiaReps::iterator it = 264 ImageSkiaReps::iterator it =
195 storage_->FindRepresentation(scale_factor, false); 265 storage_->FindRepresentation(scale_factor, false);
196 return (it != storage_->image_reps().end() && 266 return (it != storage_->image_reps().end() &&
197 it->scale_factor() == scale_factor); 267 it->scale_factor() == scale_factor);
198 } 268 }
199 269
200 const ImageSkiaRep& ImageSkia::GetRepresentation( 270 const ImageSkiaRep& ImageSkia::GetRepresentation(
201 ui::ScaleFactor scale_factor) const { 271 ui::ScaleFactor scale_factor) const {
202 if (isNull()) 272 if (isNull())
203 return NullImageRep(); 273 return NullImageRep();
204 274
275 CHECK(CanRead());
276
205 ImageSkiaReps::iterator it = storage_->FindRepresentation(scale_factor, true); 277 ImageSkiaReps::iterator it = storage_->FindRepresentation(scale_factor, true);
206 if (it == storage_->image_reps().end()) 278 if (it == storage_->image_reps().end())
207 return NullImageRep(); 279 return NullImageRep();
208 280
209 return *it; 281 return *it;
210 } 282 }
211 283
212 #if defined(OS_MACOSX) 284 void ImageSkia::SetReadOnly() {
213 285 CHECK(storage_);
214 std::vector<ImageSkiaRep> ImageSkia::GetRepresentations() const { 286 storage_->SetReadOnly();
215 if (isNull()) 287 DetachStorageFromThread();
216 return std::vector<ImageSkiaRep>();
217
218 if (!storage_->has_source())
219 return image_reps();
220
221 // Attempt to generate image reps for as many scale factors supported by
222 // this platform as possible.
223 // Do not build return array here because the mapping from scale factor to
224 // image rep is one to many in some cases.
225 std::vector<ui::ScaleFactor> supported_scale_factors =
226 ui::GetSupportedScaleFactors();
227 for (size_t i = 0; i < supported_scale_factors.size(); ++i)
228 storage_->FindRepresentation(supported_scale_factors[i], true);
229
230 return image_reps();
231 } 288 }
232 289
233 #endif // OS_MACOSX 290 void ImageSkia::MakeThreadSafe() {
291 CHECK(storage_);
292 EnsureRepsForSupportedScaleFactors();
293 // Delete source as we no longer needs it.
294 if (storage_)
295 storage_->DeleteSource();
296 storage_->SetReadOnly();
297 CHECK(IsThreadSafe());
298 }
299
300 bool ImageSkia::IsThreadSafe() const {
301 return !storage_ || (storage_->read_only() && !storage_->has_source());
302 }
234 303
235 int ImageSkia::width() const { 304 int ImageSkia::width() const {
236 return isNull() ? 0 : storage_->size().width(); 305 return isNull() ? 0 : storage_->size().width();
237 } 306 }
238 307
239 gfx::Size ImageSkia::size() const { 308 gfx::Size ImageSkia::size() const {
240 return gfx::Size(width(), height()); 309 return gfx::Size(width(), height());
241 } 310 }
242 311
243 int ImageSkia::height() const { 312 int ImageSkia::height() const {
244 return isNull() ? 0 : storage_->size().height(); 313 return isNull() ? 0 : storage_->size().height();
245 } 314 }
246 315
247 std::vector<ImageSkiaRep> ImageSkia::image_reps() const { 316 std::vector<ImageSkiaRep> ImageSkia::image_reps() const {
248 if (isNull()) 317 if (isNull())
249 return std::vector<ImageSkiaRep>(); 318 return std::vector<ImageSkiaRep>();
250 319
320 CHECK(CanRead());
321
251 ImageSkiaReps internal_image_reps = storage_->image_reps(); 322 ImageSkiaReps internal_image_reps = storage_->image_reps();
252 // Create list of image reps to return, skipping null image reps which were 323 // Create list of image reps to return, skipping null image reps which were
253 // added for caching purposes only. 324 // added for caching purposes only.
254 ImageSkiaReps image_reps; 325 ImageSkiaReps image_reps;
255 for (ImageSkiaReps::iterator it = internal_image_reps.begin(); 326 for (ImageSkiaReps::iterator it = internal_image_reps.begin();
256 it != internal_image_reps.end(); ++it) { 327 it != internal_image_reps.end(); ++it) {
257 if (!it->is_null()) 328 if (!it->is_null())
258 image_reps.push_back(*it); 329 image_reps.push_back(*it);
259 } 330 }
260 331
261 return image_reps; 332 return image_reps;
262 } 333 }
263 334
335 void ImageSkia::EnsureRepsForSupportedScaleFactors() const {
336 // Don't check ReadOnly because the source may generate images
337 // even for read only ImageSkia. Concurrent access will be protected
338 // by |DCHECK(CalledOnValidThread())| in FindRepresentation.
339 if (storage_ && storage_->has_source()) {
340 std::vector<ui::ScaleFactor> supported_scale_factors =
341 ui::GetSupportedScaleFactors();
342 for (size_t i = 0; i < supported_scale_factors.size(); ++i)
343 storage_->FindRepresentation(supported_scale_factors[i], true);
344 }
345 }
346
264 void ImageSkia::Init(const ImageSkiaRep& image_rep) { 347 void ImageSkia::Init(const ImageSkiaRep& image_rep) {
265 // TODO(pkotwicz): The image should be null whenever image rep is null. 348 // TODO(pkotwicz): The image should be null whenever image rep is null.
266 if (image_rep.sk_bitmap().empty()) { 349 if (image_rep.sk_bitmap().empty()) {
267 storage_ = NULL; 350 storage_ = NULL;
268 return; 351 return;
269 } 352 }
270 storage_ = new internal::ImageSkiaStorage( 353 storage_ = new internal::ImageSkiaStorage(
271 NULL, gfx::Size(image_rep.GetWidth(), image_rep.GetHeight())); 354 NULL, gfx::Size(image_rep.GetWidth(), image_rep.GetHeight()));
272 storage_->image_reps().push_back(image_rep); 355 storage_->image_reps().push_back(image_rep);
273 } 356 }
274 357
275 SkBitmap& ImageSkia::GetBitmap() const { 358 SkBitmap& ImageSkia::GetBitmap() const {
276 if (isNull()) { 359 if (isNull()) {
277 // Callers expect a ImageSkiaRep even if it is |isNull()|. 360 // Callers expect a ImageSkiaRep even if it is |isNull()|.
278 // TODO(pkotwicz): Fix this. 361 // TODO(pkotwicz): Fix this.
279 return NullImageRep().mutable_sk_bitmap(); 362 return NullImageRep().mutable_sk_bitmap();
280 } 363 }
281 364
365 CHECK(CanRead());
366
282 ImageSkiaReps::iterator it = 367 ImageSkiaReps::iterator it =
283 storage_->FindRepresentation(ui::SCALE_FACTOR_100P, true); 368 storage_->FindRepresentation(ui::SCALE_FACTOR_100P, true);
284 if (it != storage_->image_reps().end()) 369 if (it != storage_->image_reps().end())
285 return it->mutable_sk_bitmap(); 370 return it->mutable_sk_bitmap();
286 return NullImageRep().mutable_sk_bitmap(); 371 return NullImageRep().mutable_sk_bitmap();
287 } 372 }
288 373
374 bool ImageSkia::CanRead() const {
375 return !storage_ || storage_->CanRead();
376 }
377
378 bool ImageSkia::CanModify() const {
379 return !storage_ || storage_->CanModify();
380 }
381
382 void ImageSkia::DetachStorageFromThread() {
383 if (storage_)
384 storage_->DetachFromThread();
385 }
386
289 } // namespace gfx 387 } // namespace gfx
OLDNEW
« no previous file with comments | « ui/gfx/image/image_skia.h ('k') | ui/gfx/image/image_skia_source.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698