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

Unified 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, 4 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« 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