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

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