| 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 <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <algorithm> | 9 #include <algorithm> |
| 10 #include <cmath> | 10 #include <cmath> |
| 11 #include <limits> | 11 #include <limits> |
| 12 #include <memory> | 12 #include <memory> |
| 13 | 13 |
| 14 #include "base/command_line.h" | 14 #include "base/command_line.h" |
| 15 #include "base/logging.h" | 15 #include "base/logging.h" |
| 16 #include "base/memory/ptr_util.h" | 16 #include "base/memory/ptr_util.h" |
| 17 #include "base/threading/non_thread_safe.h" | 17 #include "base/sequence_checker.h" |
| 18 #include "build/build_config.h" | 18 #include "build/build_config.h" |
| 19 #include "ui/gfx/geometry/rect.h" | 19 #include "ui/gfx/geometry/rect.h" |
| 20 #include "ui/gfx/geometry/size.h" | 20 #include "ui/gfx/geometry/size.h" |
| 21 #include "ui/gfx/geometry/size_conversions.h" | 21 #include "ui/gfx/geometry/size_conversions.h" |
| 22 #include "ui/gfx/image/image_skia_operations.h" | 22 #include "ui/gfx/image/image_skia_operations.h" |
| 23 #include "ui/gfx/image/image_skia_source.h" | 23 #include "ui/gfx/image/image_skia_source.h" |
| 24 #include "ui/gfx/skia_util.h" | 24 #include "ui/gfx/skia_util.h" |
| 25 #include "ui/gfx/switches.h" | 25 #include "ui/gfx/switches.h" |
| 26 | 26 |
| 27 namespace gfx { | 27 namespace gfx { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 rep.sk_bitmap(), | 67 rep.sk_bitmap(), |
| 68 skia::ImageOperations::RESIZE_LANCZOS3, | 68 skia::ImageOperations::RESIZE_LANCZOS3, |
| 69 scaled_size.width(), | 69 scaled_size.width(), |
| 70 scaled_size.height()), target_scale); | 70 scaled_size.height()), target_scale); |
| 71 } | 71 } |
| 72 | 72 |
| 73 } // namespace | 73 } // namespace |
| 74 | 74 |
| 75 // A helper class such that ImageSkia can be cheaply copied. ImageSkia holds a | 75 // A helper class such that ImageSkia can be cheaply copied. ImageSkia holds a |
| 76 // refptr instance of ImageSkiaStorage, which in turn holds all of ImageSkia's | 76 // refptr instance of ImageSkiaStorage, which in turn holds all of ImageSkia's |
| 77 // information. Having both |base::RefCountedThreadSafe| and | 77 // information. Using a |base::SequenceChecker| on a |
| 78 // |base::NonThreadSafe| may sound strange but is necessary to turn | 78 // |base::RefCountedThreadSafe| subclass may sound strange but is necessary to |
| 79 // the 'thread-non-safe modifiable ImageSkiaStorage' into | 79 // turn the 'thread-non-safe modifiable ImageSkiaStorage' into the 'thread-safe |
| 80 // the 'thread-safe read-only ImageSkiaStorage'. | 80 // read-only ImageSkiaStorage'. |
| 81 class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>, | 81 class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage> { |
| 82 public base::NonThreadSafe { | |
| 83 public: | 82 public: |
| 84 ImageSkiaStorage(ImageSkiaSource* source, const gfx::Size& size); | 83 ImageSkiaStorage(ImageSkiaSource* source, const gfx::Size& size); |
| 85 ImageSkiaStorage(ImageSkiaSource* source, float scale); | 84 ImageSkiaStorage(ImageSkiaSource* source, float scale); |
| 86 | 85 |
| 87 bool has_source() const { return source_ != nullptr; } | 86 bool has_source() const { return source_ != nullptr; } |
| 88 std::vector<gfx::ImageSkiaRep>& image_reps() { return image_reps_; } | 87 std::vector<gfx::ImageSkiaRep>& image_reps() { return image_reps_; } |
| 89 const gfx::Size& size() const { return size_; } | 88 const gfx::Size& size() const { return size_; } |
| 90 bool read_only() const { return read_only_; } | 89 bool read_only() const { return read_only_; } |
| 91 | 90 |
| 92 void DeleteSource(); | 91 void DeleteSource(); |
| 93 void SetReadOnly(); | 92 void SetReadOnly(); |
| 94 void DetachFromThread(); | 93 void DetachFromSequence(); |
| 95 | 94 |
| 96 // Checks if the current thread can safely modify the storage. | 95 // Checks if the current thread can safely modify the storage. |
| 97 bool CanModify() const; | 96 bool CanModify() const; |
| 98 | 97 |
| 99 // Checks if the current thread can safely read the storage. | 98 // Checks if the current thread can safely read the storage. |
| 100 bool CanRead() const; | 99 bool CanRead() const; |
| 101 | 100 |
| 102 // Add a new representation. This checks if the scale of the added image | 101 // Add a new representation. This checks if the scale of the added image |
| 103 // is not 1.0f, and mark the existing rep as scaled to make | 102 // is not 1.0f, and mark the existing rep as scaled to make |
| 104 // the image high DPI aware. | 103 // the image high DPI aware. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 133 // Vector of bitmaps and their associated scale. | 132 // Vector of bitmaps and their associated scale. |
| 134 std::vector<gfx::ImageSkiaRep> image_reps_; | 133 std::vector<gfx::ImageSkiaRep> image_reps_; |
| 135 | 134 |
| 136 std::unique_ptr<ImageSkiaSource> source_; | 135 std::unique_ptr<ImageSkiaSource> source_; |
| 137 | 136 |
| 138 // Size of the image in DIP. | 137 // Size of the image in DIP. |
| 139 gfx::Size size_; | 138 gfx::Size size_; |
| 140 | 139 |
| 141 bool read_only_; | 140 bool read_only_; |
| 142 | 141 |
| 142 base::SequenceChecker sequence_checker_; |
| 143 |
| 143 DISALLOW_COPY_AND_ASSIGN(ImageSkiaStorage); | 144 DISALLOW_COPY_AND_ASSIGN(ImageSkiaStorage); |
| 144 }; | 145 }; |
| 145 | 146 |
| 146 ImageSkiaStorage::ImageSkiaStorage(ImageSkiaSource* source, | 147 ImageSkiaStorage::ImageSkiaStorage(ImageSkiaSource* source, |
| 147 const gfx::Size& size) | 148 const gfx::Size& size) |
| 148 : source_(source), size_(size), read_only_(false) {} | 149 : source_(source), size_(size), read_only_(false) {} |
| 149 | 150 |
| 150 ImageSkiaStorage::ImageSkiaStorage(ImageSkiaSource* source, float scale) | 151 ImageSkiaStorage::ImageSkiaStorage(ImageSkiaSource* source, float scale) |
| 151 : source_(source), read_only_(false) { | 152 : source_(source), read_only_(false) { |
| 152 ImageSkia::ImageSkiaReps::iterator it = FindRepresentation(scale, true); | 153 ImageSkia::ImageSkiaReps::iterator it = FindRepresentation(scale, true); |
| 153 if (it == image_reps_.end() || it->is_null()) | 154 if (it == image_reps_.end() || it->is_null()) |
| 154 source_.reset(); | 155 source_.reset(); |
| 155 else | 156 else |
| 156 size_.SetSize(it->GetWidth(), it->GetHeight()); | 157 size_.SetSize(it->GetWidth(), it->GetHeight()); |
| 157 } | 158 } |
| 158 | 159 |
| 159 void ImageSkiaStorage::DeleteSource() { | 160 void ImageSkiaStorage::DeleteSource() { |
| 160 source_.reset(); | 161 source_.reset(); |
| 161 } | 162 } |
| 162 | 163 |
| 163 void ImageSkiaStorage::SetReadOnly() { | 164 void ImageSkiaStorage::SetReadOnly() { |
| 164 read_only_ = true; | 165 read_only_ = true; |
| 165 } | 166 } |
| 166 | 167 |
| 167 void ImageSkiaStorage::DetachFromThread() { | 168 void ImageSkiaStorage::DetachFromSequence() { |
| 168 base::NonThreadSafe::DetachFromThread(); | 169 sequence_checker_.DetachFromSequence(); |
| 169 } | 170 } |
| 170 | 171 |
| 171 bool ImageSkiaStorage::CanModify() const { | 172 bool ImageSkiaStorage::CanModify() const { |
| 172 return !read_only_ && CalledOnValidThread(); | 173 return !read_only_ && sequence_checker_.CalledOnValidSequence(); |
| 173 } | 174 } |
| 174 | 175 |
| 175 bool ImageSkiaStorage::CanRead() const { | 176 bool ImageSkiaStorage::CanRead() const { |
| 176 return (read_only_ && !source_) || CalledOnValidThread(); | 177 return (read_only_ && !source_) || sequence_checker_.CalledOnValidSequence(); |
| 177 } | 178 } |
| 178 | 179 |
| 179 void ImageSkiaStorage::AddRepresentation(const ImageSkiaRep& image) { | 180 void ImageSkiaStorage::AddRepresentation(const ImageSkiaRep& image) { |
| 180 // Explicitly adding a representation makes no sense for images that | 181 // Explicitly adding a representation makes no sense for images that |
| 181 // inherently have representations at all scales already. | 182 // inherently have representations at all scales already. |
| 182 DCHECK(!HasRepresentationAtAllScales()); | 183 DCHECK(!HasRepresentationAtAllScales()); |
| 183 | 184 |
| 184 if (image.scale() != 1.0f) { | 185 if (image.scale() != 1.0f) { |
| 185 for (ImageSkia::ImageSkiaReps::iterator it = image_reps_.begin(); | 186 for (ImageSkia::ImageSkiaReps::iterator it = image_reps_.begin(); |
| 186 it < image_reps_.end(); ++it) { | 187 it < image_reps_.end(); ++it) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 218 break; | 219 break; |
| 219 } | 220 } |
| 220 float diff = std::abs(it->scale() - scale); | 221 float diff = std::abs(it->scale() - scale); |
| 221 if (diff < smallest_diff && !it->is_null()) { | 222 if (diff < smallest_diff && !it->is_null()) { |
| 222 closest_iter = it; | 223 closest_iter = it; |
| 223 smallest_diff = diff; | 224 smallest_diff = diff; |
| 224 } | 225 } |
| 225 } | 226 } |
| 226 | 227 |
| 227 if (fetch_new_image && source_.get()) { | 228 if (fetch_new_image && source_.get()) { |
| 228 DCHECK(CalledOnValidThread()) | 229 DCHECK(sequence_checker_.CalledOnValidSequence()) |
| 229 << "An ImageSkia with the source must be accessed by the same thread."; | 230 << "An ImageSkia with the source must be accessed by the same " |
| 231 "sequence."; |
| 230 | 232 |
| 231 ImageSkiaRep image; | 233 ImageSkiaRep image; |
| 232 float resource_scale = scale; | 234 float resource_scale = scale; |
| 233 if (!HasRepresentationAtAllScales() && g_supported_scales) | 235 if (!HasRepresentationAtAllScales() && g_supported_scales) |
| 234 resource_scale = MapToSupportedScale(scale); | 236 resource_scale = MapToSupportedScale(scale); |
| 235 if (scale != resource_scale) { | 237 if (scale != resource_scale) { |
| 236 std::vector<ImageSkiaRep>::iterator iter = | 238 std::vector<ImageSkiaRep>::iterator iter = |
| 237 FindRepresentation(resource_scale, fetch_new_image); | 239 FindRepresentation(resource_scale, fetch_new_image); |
| 238 CHECK(iter != image_reps_.end()); | 240 CHECK(iter != image_reps_.end()); |
| 239 image = iter->unscaled() ? (*iter) : ScaleImageSkiaRep(*iter, scale); | 241 image = iter->unscaled() ? (*iter) : ScaleImageSkiaRep(*iter, scale); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 261 if (image.is_null() || image.scale() != scale) { | 263 if (image.is_null() || image.scale() != scale) { |
| 262 non_const->image_reps().push_back(ImageSkiaRep(SkBitmap(), scale)); | 264 non_const->image_reps().push_back(ImageSkiaRep(SkBitmap(), scale)); |
| 263 } | 265 } |
| 264 | 266 |
| 265 // image_reps_ must have the exact much now, so find again. | 267 // image_reps_ must have the exact much now, so find again. |
| 266 return FindRepresentation(scale, false); | 268 return FindRepresentation(scale, false); |
| 267 } | 269 } |
| 268 return exact_iter != image_reps_.end() ? exact_iter : closest_iter; | 270 return exact_iter != image_reps_.end() ? exact_iter : closest_iter; |
| 269 } | 271 } |
| 270 | 272 |
| 271 ImageSkiaStorage::~ImageSkiaStorage() { | 273 ImageSkiaStorage::~ImageSkiaStorage() = default; |
| 272 // We only care if the storage is modified by the same thread. Don't blow up | |
| 273 // even if someone else deleted the ImageSkia. | |
| 274 DetachFromThread(); | |
| 275 } | |
| 276 | 274 |
| 277 } // internal | 275 } // internal |
| 278 | 276 |
| 279 ImageSkia::ImageSkia() : storage_(NULL) { | 277 ImageSkia::ImageSkia() : storage_(NULL) { |
| 280 } | 278 } |
| 281 | 279 |
| 282 ImageSkia::ImageSkia(ImageSkiaSource* source, const gfx::Size& size) | 280 ImageSkia::ImageSkia(ImageSkiaSource* source, const gfx::Size& size) |
| 283 : storage_(new internal::ImageSkiaStorage(source, size)) { | 281 : storage_(new internal::ImageSkiaStorage(source, size)) { |
| 284 DCHECK(source); | 282 DCHECK(source); |
| 285 // No other thread has reference to this, so it's safe to detach the thread. | 283 // No other thread has reference to this, so it's safe to detach the sequence. |
| 286 DetachStorageFromThread(); | 284 DetachStorageFromSequence(); |
| 287 } | 285 } |
| 288 | 286 |
| 289 ImageSkia::ImageSkia(ImageSkiaSource* source, float scale) | 287 ImageSkia::ImageSkia(ImageSkiaSource* source, float scale) |
| 290 : storage_(new internal::ImageSkiaStorage(source, scale)) { | 288 : storage_(new internal::ImageSkiaStorage(source, scale)) { |
| 291 DCHECK(source); | 289 DCHECK(source); |
| 292 if (!storage_->has_source()) | 290 if (!storage_->has_source()) |
| 293 storage_ = NULL; | 291 storage_ = NULL; |
| 294 // No other thread has reference to this, so it's safe to detach the thread. | 292 // No other thread has reference to this, so it's safe to detach the sequence. |
| 295 DetachStorageFromThread(); | 293 DetachStorageFromSequence(); |
| 296 } | 294 } |
| 297 | 295 |
| 298 ImageSkia::ImageSkia(const ImageSkiaRep& image_rep) { | 296 ImageSkia::ImageSkia(const ImageSkiaRep& image_rep) { |
| 299 Init(image_rep); | 297 Init(image_rep); |
| 300 // No other thread has reference to this, so it's safe to detach the thread. | 298 // No other thread has reference to this, so it's safe to detach the sequence. |
| 301 DetachStorageFromThread(); | 299 DetachStorageFromSequence(); |
| 302 } | 300 } |
| 303 | 301 |
| 304 ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) { | 302 ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) { |
| 305 } | 303 } |
| 306 | 304 |
| 307 ImageSkia& ImageSkia::operator=(const ImageSkia& other) { | 305 ImageSkia& ImageSkia::operator=(const ImageSkia& other) { |
| 308 storage_ = other.storage_; | 306 storage_ = other.storage_; |
| 309 return *this; | 307 return *this; |
| 310 } | 308 } |
| 311 | 309 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 342 return base::WrapUnique(copy); | 340 return base::WrapUnique(copy); |
| 343 | 341 |
| 344 CHECK(CanRead()); | 342 CHECK(CanRead()); |
| 345 | 343 |
| 346 std::vector<gfx::ImageSkiaRep>& reps = storage_->image_reps(); | 344 std::vector<gfx::ImageSkiaRep>& reps = storage_->image_reps(); |
| 347 for (std::vector<gfx::ImageSkiaRep>::iterator iter = reps.begin(); | 345 for (std::vector<gfx::ImageSkiaRep>::iterator iter = reps.begin(); |
| 348 iter != reps.end(); ++iter) { | 346 iter != reps.end(); ++iter) { |
| 349 copy->AddRepresentation(*iter); | 347 copy->AddRepresentation(*iter); |
| 350 } | 348 } |
| 351 // The copy has its own storage. Detach the copy from the current | 349 // The copy has its own storage. Detach the copy from the current |
| 352 // thread so that other thread can use this. | 350 // sequence so that other sequences can use this. |
| 353 if (!copy->isNull()) | 351 if (!copy->isNull()) |
| 354 copy->storage_->DetachFromThread(); | 352 copy->storage_->DetachFromSequence(); |
| 355 return base::WrapUnique(copy); | 353 return base::WrapUnique(copy); |
| 356 } | 354 } |
| 357 | 355 |
| 358 bool ImageSkia::BackedBySameObjectAs(const gfx::ImageSkia& other) const { | 356 bool ImageSkia::BackedBySameObjectAs(const gfx::ImageSkia& other) const { |
| 359 return storage_.get() == other.storage_.get(); | 357 return storage_.get() == other.storage_.get(); |
| 360 } | 358 } |
| 361 | 359 |
| 362 void ImageSkia::AddRepresentation(const ImageSkiaRep& image_rep) { | 360 void ImageSkia::AddRepresentation(const ImageSkiaRep& image_rep) { |
| 363 DCHECK(!image_rep.is_null()); | 361 DCHECK(!image_rep.is_null()); |
| 364 | 362 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 415 ImageSkiaReps::iterator it = storage_->FindRepresentation(scale, true); | 413 ImageSkiaReps::iterator it = storage_->FindRepresentation(scale, true); |
| 416 if (it == storage_->image_reps().end()) | 414 if (it == storage_->image_reps().end()) |
| 417 return NullImageRep(); | 415 return NullImageRep(); |
| 418 | 416 |
| 419 return *it; | 417 return *it; |
| 420 } | 418 } |
| 421 | 419 |
| 422 void ImageSkia::SetReadOnly() { | 420 void ImageSkia::SetReadOnly() { |
| 423 CHECK(storage_.get()); | 421 CHECK(storage_.get()); |
| 424 storage_->SetReadOnly(); | 422 storage_->SetReadOnly(); |
| 425 DetachStorageFromThread(); | 423 DetachStorageFromSequence(); |
| 426 } | 424 } |
| 427 | 425 |
| 428 void ImageSkia::MakeThreadSafe() { | 426 void ImageSkia::MakeThreadSafe() { |
| 429 CHECK(storage_.get()); | 427 CHECK(storage_.get()); |
| 430 EnsureRepsForSupportedScales(); | 428 EnsureRepsForSupportedScales(); |
| 431 // Delete source as we no longer needs it. | 429 // Delete source as we no longer needs it. |
| 432 if (storage_.get()) | 430 if (storage_.get()) |
| 433 storage_->DeleteSource(); | 431 storage_->DeleteSource(); |
| 434 storage_->SetReadOnly(); | 432 storage_->SetReadOnly(); |
| 435 CHECK(IsThreadSafe()); | 433 CHECK(IsThreadSafe()); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 465 it != internal_image_reps.end(); ++it) { | 463 it != internal_image_reps.end(); ++it) { |
| 466 if (!it->is_null()) | 464 if (!it->is_null()) |
| 467 image_reps.push_back(*it); | 465 image_reps.push_back(*it); |
| 468 } | 466 } |
| 469 | 467 |
| 470 return image_reps; | 468 return image_reps; |
| 471 } | 469 } |
| 472 | 470 |
| 473 void ImageSkia::EnsureRepsForSupportedScales() const { | 471 void ImageSkia::EnsureRepsForSupportedScales() const { |
| 474 DCHECK(g_supported_scales != NULL); | 472 DCHECK(g_supported_scales != NULL); |
| 475 // Don't check ReadOnly because the source may generate images | 473 // Don't check ReadOnly because the source may generate images even for read |
| 476 // even for read only ImageSkia. Concurrent access will be protected | 474 // only ImageSkia. Concurrent access will be protected by |
| 477 // by |DCHECK(CalledOnValidThread())| in FindRepresentation. | 475 // |DCHECK(sequence_checker_.CalledOnValidSequence())| in FindRepresentation. |
| 478 if (storage_.get() && storage_->has_source()) { | 476 if (storage_.get() && storage_->has_source()) { |
| 479 for (std::vector<float>::const_iterator it = g_supported_scales->begin(); | 477 for (std::vector<float>::const_iterator it = g_supported_scales->begin(); |
| 480 it != g_supported_scales->end(); ++it) | 478 it != g_supported_scales->end(); ++it) |
| 481 storage_->FindRepresentation(*it, true); | 479 storage_->FindRepresentation(*it, true); |
| 482 } | 480 } |
| 483 } | 481 } |
| 484 | 482 |
| 485 void ImageSkia::RemoveUnsupportedRepresentationsForScale(float scale) { | 483 void ImageSkia::RemoveUnsupportedRepresentationsForScale(float scale) { |
| 486 for (const ImageSkiaRep& image_rep_to_test : image_reps()) { | 484 for (const ImageSkiaRep& image_rep_to_test : image_reps()) { |
| 487 const float test_scale = image_rep_to_test.scale(); | 485 const float test_scale = image_rep_to_test.scale(); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 521 } | 519 } |
| 522 | 520 |
| 523 bool ImageSkia::CanRead() const { | 521 bool ImageSkia::CanRead() const { |
| 524 return !storage_.get() || storage_->CanRead(); | 522 return !storage_.get() || storage_->CanRead(); |
| 525 } | 523 } |
| 526 | 524 |
| 527 bool ImageSkia::CanModify() const { | 525 bool ImageSkia::CanModify() const { |
| 528 return !storage_.get() || storage_->CanModify(); | 526 return !storage_.get() || storage_->CanModify(); |
| 529 } | 527 } |
| 530 | 528 |
| 531 void ImageSkia::DetachStorageFromThread() { | 529 void ImageSkia::DetachStorageFromSequence() { |
| 532 if (storage_.get()) | 530 if (storage_.get()) |
| 533 storage_->DetachFromThread(); | 531 storage_->DetachFromSequence(); |
| 534 } | 532 } |
| 535 | 533 |
| 536 } // namespace gfx | 534 } // namespace gfx |
| OLD | NEW |