| Index: ui/gfx/image/image_skia.cc
|
| diff --git a/ui/gfx/image/image_skia.cc b/ui/gfx/image/image_skia.cc
|
| index f0b90a15ffa9601481de40cdf16f74076ce7610a..37fcfe93b45d81e25129d2339ee3a9d00566fb58 100644
|
| --- a/ui/gfx/image/image_skia.cc
|
| +++ b/ui/gfx/image/image_skia.cc
|
| @@ -10,6 +10,7 @@
|
|
|
| #include "base/logging.h"
|
| #include "base/memory/scoped_ptr.h"
|
| +#include "base/threading/non_thread_safe.h"
|
| #include "ui/gfx/image/image_skia_operations.h"
|
| #include "ui/gfx/image/image_skia_source.h"
|
| #include "ui/gfx/rect.h"
|
| @@ -48,11 +49,13 @@ class Matcher {
|
| // A helper class such that ImageSkia can be cheaply copied. ImageSkia holds a
|
| // refptr instance of ImageSkiaStorage, which in turn holds all of ImageSkia's
|
| // information.
|
| -class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> {
|
| +class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage>,
|
| + public base::NonThreadSafe {
|
| public:
|
| ImageSkiaStorage(ImageSkiaSource* source, const gfx::Size& size)
|
| : source_(source),
|
| - size_(size) {
|
| + size_(size),
|
| + read_only_(false) {
|
| }
|
|
|
| bool has_source() const { return source_.get() != NULL; }
|
| @@ -61,6 +64,30 @@ class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> {
|
|
|
| const gfx::Size& size() const { return size_; }
|
|
|
| + bool read_only() const { return read_only_; }
|
| +
|
| + void DeleteSource() {
|
| + source_.reset();
|
| + }
|
| +
|
| + void SetReadOnly() {
|
| + read_only_ = true;
|
| + }
|
| +
|
| + void DetachFromThread() {
|
| + base::NonThreadSafe::DetachFromThread();
|
| + }
|
| +
|
| + // Checks if the current thread can safely modify the storage.
|
| + bool CanModify() const {
|
| + return !read_only_ && CalledOnValidThread();
|
| + }
|
| +
|
| + // Checks if the current thread can safely read the storage.
|
| + bool CanRead() const {
|
| + return (read_only_ && !source_.get()) || CalledOnValidThread();
|
| + }
|
| +
|
| // Returns the iterator of the image rep whose density best matches
|
| // |scale_factor|. If the image for the |scale_factor| doesn't exist
|
| // in the storage and |storage| is set, it fetches new image by calling
|
| @@ -96,6 +123,9 @@ class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> {
|
| }
|
|
|
| if (fetch_new_image && source_.get()) {
|
| + DCHECK(CalledOnValidThread()) <<
|
| + "An ImageSkia with the source must be accessed by the same thread.";
|
| +
|
| ImageSkiaRep image = source_->GetImageForScale(scale_factor);
|
|
|
| // If the source returned the new image, store it.
|
| @@ -120,7 +150,10 @@ class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> {
|
| }
|
|
|
| private:
|
| - ~ImageSkiaStorage() {
|
| + virtual ~ImageSkiaStorage() {
|
| + // We only care if the storage is modified by the same thread.
|
| + // Don't blow up even if someone else deleted the ImageSkia.
|
| + DetachFromThread();
|
| }
|
|
|
| // Vector of bitmaps and their associated scale factor.
|
| @@ -131,6 +164,8 @@ class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> {
|
| // Size of the image in DIP.
|
| const gfx::Size size_;
|
|
|
| + bool read_only_;
|
| +
|
| friend class base::RefCounted<ImageSkiaStorage>;
|
| };
|
|
|
| @@ -142,14 +177,20 @@ ImageSkia::ImageSkia() : storage_(NULL) {
|
| ImageSkia::ImageSkia(ImageSkiaSource* source, const gfx::Size& size)
|
| : storage_(new internal::ImageSkiaStorage(source, size)) {
|
| DCHECK(source);
|
| + // No other thread has reference to this, so it's safe to detach the thread.
|
| + DetachStorageFromThread();
|
| }
|
|
|
| ImageSkia::ImageSkia(const SkBitmap& bitmap) {
|
| Init(ImageSkiaRep(bitmap, ui::SCALE_FACTOR_100P));
|
| + // No other thread has reference to this, so it's safe to detach the thread.
|
| + DetachStorageFromThread();
|
| }
|
|
|
| ImageSkia::ImageSkia(const ImageSkiaRep& image_rep) {
|
| Init(image_rep);
|
| + // No other thread has reference to this, so it's safe to detach the thread.
|
| + DetachStorageFromThread();
|
| }
|
|
|
| ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) {
|
| @@ -163,6 +204,25 @@ ImageSkia& ImageSkia::operator=(const ImageSkia& other) {
|
| ImageSkia::~ImageSkia() {
|
| }
|
|
|
| +ImageSkia ImageSkia::DeepCopy() const {
|
| + ImageSkia copy;
|
| + if (isNull())
|
| + return copy;
|
| +
|
| + CHECK(CanRead());
|
| +
|
| + std::vector<gfx::ImageSkiaRep>& reps = storage_->image_reps();
|
| + for (std::vector<gfx::ImageSkiaRep>::iterator iter = reps.begin();
|
| + iter != reps.end(); ++iter) {
|
| + copy.AddRepresentation(*iter);
|
| + }
|
| + // The copy has its own storage. Detach the copy from the current
|
| + // thread so that other thread can use this.
|
| + if (!copy.isNull())
|
| + copy.storage_->DetachFromThread();
|
| + return copy;
|
| +}
|
| +
|
| bool ImageSkia::BackedBySameObjectAs(const gfx::ImageSkia& other) const {
|
| return storage_.get() == other.storage_.get();
|
| }
|
| @@ -170,15 +230,24 @@ bool ImageSkia::BackedBySameObjectAs(const gfx::ImageSkia& other) const {
|
| void ImageSkia::AddRepresentation(const ImageSkiaRep& image_rep) {
|
| DCHECK(!image_rep.is_null());
|
|
|
| - if (isNull())
|
| + // TODO(oshima): This method should be called |SetRepresentation|
|
| + // and replace the existing rep if there is already one with the
|
| + // same scale factor so that we can guarantee that a ImageSkia
|
| + // instance contians only one image rep per scale factor. This is
|
| + // not possible now as ImageLoadingTracker currently stores need
|
| + // this feature, but this needs to be fixed.
|
| + if (isNull()) {
|
| Init(image_rep);
|
| - else
|
| + } else {
|
| + CHECK(CanModify());
|
| storage_->image_reps().push_back(image_rep);
|
| + }
|
| }
|
|
|
| void ImageSkia::RemoveRepresentation(ui::ScaleFactor scale_factor) {
|
| if (isNull())
|
| return;
|
| + CHECK(CanModify());
|
|
|
| ImageSkiaReps& image_reps = storage_->image_reps();
|
| ImageSkiaReps::iterator it =
|
| @@ -190,6 +259,7 @@ void ImageSkia::RemoveRepresentation(ui::ScaleFactor scale_factor) {
|
| bool ImageSkia::HasRepresentation(ui::ScaleFactor scale_factor) const {
|
| if (isNull())
|
| return false;
|
| + CHECK(CanRead());
|
|
|
| ImageSkiaReps::iterator it =
|
| storage_->FindRepresentation(scale_factor, false);
|
| @@ -202,6 +272,8 @@ const ImageSkiaRep& ImageSkia::GetRepresentation(
|
| if (isNull())
|
| return NullImageRep();
|
|
|
| + CHECK(CanRead());
|
| +
|
| ImageSkiaReps::iterator it = storage_->FindRepresentation(scale_factor, true);
|
| if (it == storage_->image_reps().end())
|
| return NullImageRep();
|
| @@ -209,28 +281,25 @@ const ImageSkiaRep& ImageSkia::GetRepresentation(
|
| return *it;
|
| }
|
|
|
| -#if defined(OS_MACOSX)
|
| -
|
| -std::vector<ImageSkiaRep> ImageSkia::GetRepresentations() const {
|
| - if (isNull())
|
| - return std::vector<ImageSkiaRep>();
|
| -
|
| - if (!storage_->has_source())
|
| - return image_reps();
|
| -
|
| - // Attempt to generate image reps for as many scale factors supported by
|
| - // this platform as possible.
|
| - // Do not build return array here because the mapping from scale factor to
|
| - // image rep is one to many in some cases.
|
| - std::vector<ui::ScaleFactor> supported_scale_factors =
|
| - ui::GetSupportedScaleFactors();
|
| - for (size_t i = 0; i < supported_scale_factors.size(); ++i)
|
| - storage_->FindRepresentation(supported_scale_factors[i], true);
|
| +void ImageSkia::SetReadOnly() {
|
| + CHECK(storage_);
|
| + storage_->SetReadOnly();
|
| + DetachStorageFromThread();
|
| +}
|
|
|
| - return image_reps();
|
| +void ImageSkia::MakeThreadSafe() {
|
| + CHECK(storage_);
|
| + EnsureRepsForSupportedScaleFactors();
|
| + // Delete source as we no longer needs it.
|
| + if (storage_)
|
| + storage_->DeleteSource();
|
| + storage_->SetReadOnly();
|
| + CHECK(IsThreadSafe());
|
| }
|
|
|
| -#endif // OS_MACOSX
|
| +bool ImageSkia::IsThreadSafe() const {
|
| + return !storage_ || (storage_->read_only() && !storage_->has_source());
|
| +}
|
|
|
| int ImageSkia::width() const {
|
| return isNull() ? 0 : storage_->size().width();
|
| @@ -248,6 +317,8 @@ std::vector<ImageSkiaRep> ImageSkia::image_reps() const {
|
| if (isNull())
|
| return std::vector<ImageSkiaRep>();
|
|
|
| + CHECK(CanRead());
|
| +
|
| ImageSkiaReps internal_image_reps = storage_->image_reps();
|
| // Create list of image reps to return, skipping null image reps which were
|
| // added for caching purposes only.
|
| @@ -261,6 +332,18 @@ std::vector<ImageSkiaRep> ImageSkia::image_reps() const {
|
| return image_reps;
|
| }
|
|
|
| +void ImageSkia::EnsureRepsForSupportedScaleFactors() const {
|
| + // Don't check ReadOnly because the source may generate images
|
| + // even for read only ImageSkia. Concurrent access will be protected
|
| + // by |DCHECK(CalledOnValidThread())| in FindRepresentation.
|
| + if (storage_ && storage_->has_source()) {
|
| + std::vector<ui::ScaleFactor> supported_scale_factors =
|
| + ui::GetSupportedScaleFactors();
|
| + for (size_t i = 0; i < supported_scale_factors.size(); ++i)
|
| + storage_->FindRepresentation(supported_scale_factors[i], true);
|
| + }
|
| +}
|
| +
|
| void ImageSkia::Init(const ImageSkiaRep& image_rep) {
|
| // TODO(pkotwicz): The image should be null whenever image rep is null.
|
| if (image_rep.sk_bitmap().empty()) {
|
| @@ -279,6 +362,8 @@ SkBitmap& ImageSkia::GetBitmap() const {
|
| return NullImageRep().mutable_sk_bitmap();
|
| }
|
|
|
| + CHECK(CanRead());
|
| +
|
| ImageSkiaReps::iterator it =
|
| storage_->FindRepresentation(ui::SCALE_FACTOR_100P, true);
|
| if (it != storage_->image_reps().end())
|
| @@ -286,4 +371,17 @@ SkBitmap& ImageSkia::GetBitmap() const {
|
| return NullImageRep().mutable_sk_bitmap();
|
| }
|
|
|
| +bool ImageSkia::CanRead() const {
|
| + return !storage_ || storage_->CanRead();
|
| +}
|
| +
|
| +bool ImageSkia::CanModify() const {
|
| + return !storage_ || storage_->CanModify();
|
| +}
|
| +
|
| +void ImageSkia::DetachStorageFromThread() {
|
| + if (storage_)
|
| + storage_->DetachFromThread();
|
| +}
|
| +
|
| } // namespace gfx
|
|
|