Index: ui/gfx/image/image_skia.cc |
diff --git a/ui/gfx/image/image_skia.cc b/ui/gfx/image/image_skia.cc |
index b46d38d5ecb73c175886ba30ff785dad9589fdfd..58fb8d1e95f9054f975fa5120a431d836915c9aa 100644 |
--- a/ui/gfx/image/image_skia.cc |
+++ b/ui/gfx/image/image_skia.cc |
@@ -45,19 +45,6 @@ const float kFallbackToSmallerScaleDiff = 0.20f; |
namespace internal { |
namespace { |
-class Matcher { |
- public: |
- explicit Matcher(float scale) : scale_(scale) { |
- } |
- |
- bool operator()(const ImageSkiaRep& rep) const { |
- return rep.scale() == scale_; |
- } |
- |
- private: |
- float scale_; |
-}; |
- |
ImageSkiaRep ScaleImageSkiaRep(const ImageSkiaRep& rep, float target_scale) { |
if (rep.is_null() || rep.scale() == target_scale) |
return rep; |
@@ -76,75 +63,34 @@ ImageSkiaRep ScaleImageSkiaRep(const ImageSkiaRep& rep, float target_scale) { |
// 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. Having both |base::RefCountedThreadSafe| and |
-// |base::NonThreadSafe| may sounds strange but necessary to turn |
+// |base::NonThreadSafe| may sound strange but is necessary to turn |
// the 'thread-non-safe modifiable ImageSkiaStorage' into |
// the 'thread-safe read-only ImageSkiaStorage'. |
class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>, |
public base::NonThreadSafe { |
public: |
- ImageSkiaStorage(ImageSkiaSource* source, const gfx::Size& size) |
- : source_(source), |
- size_(size), |
- read_only_(false) { |
- } |
- |
- ImageSkiaStorage(ImageSkiaSource* source, float scale) |
- : source_(source), |
- read_only_(false) { |
- ImageSkia::ImageSkiaReps::iterator it = FindRepresentation(scale, true); |
- if (it == image_reps_.end() || it->is_null()) |
- source_.reset(); |
- else |
- size_.SetSize(it->GetWidth(), it->GetHeight()); |
- } |
- |
- bool has_source() const { return source_.get() != NULL; } |
+ ImageSkiaStorage(ImageSkiaSource* source, const gfx::Size& size); |
+ ImageSkiaStorage(ImageSkiaSource* source, float scale); |
+ bool has_source() const { return source_ != nullptr; } |
std::vector<gfx::ImageSkiaRep>& image_reps() { return image_reps_; } |
- |
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(); |
- } |
+ void DeleteSource(); |
+ void SetReadOnly(); |
+ void DetachFromThread(); |
// Checks if the current thread can safely modify the storage. |
- bool CanModify() const { |
- return !read_only_ && CalledOnValidThread(); |
- } |
+ bool CanModify() const; |
// Checks if the current thread can safely read the storage. |
- bool CanRead() const { |
- return (read_only_ && !source_.get()) || CalledOnValidThread(); |
- } |
+ bool CanRead() const; |
// Add a new representation. This checks if the scale of the added image |
// is not 1.0f, and mark the existing rep as scaled to make |
// the image high DPI aware. |
- void AddRepresentation(const ImageSkiaRep& image) { |
- if (image.scale() != 1.0f) { |
- for (ImageSkia::ImageSkiaReps::iterator it = image_reps_.begin(); |
- it < image_reps_.end(); |
- ++it) { |
- if (it->unscaled()) { |
- DCHECK_EQ(1.0f, it->scale()); |
- it->SetScaled(); |
- break; |
- } |
- } |
- } |
- image_reps_.push_back(image); |
- } |
+ void AddRepresentation(const ImageSkiaRep& image); |
// Returns the iterator of the image rep whose density best matches |
// |scale|. If the image for the |scale| doesn't exist in the storage and |
@@ -159,91 +105,13 @@ class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>, |
// Right now only Windows uses 2 and other platforms use 1 by default. |
// TODO(mukai, oshima): abandon 1 code path and use 2 for every platforms. |
std::vector<ImageSkiaRep>::iterator FindRepresentation( |
- float scale, bool fetch_new_image) const { |
- ImageSkiaStorage* non_const = const_cast<ImageSkiaStorage*>(this); |
- |
- ImageSkia::ImageSkiaReps::iterator closest_iter = |
- non_const->image_reps().end(); |
- ImageSkia::ImageSkiaReps::iterator exact_iter = |
- non_const->image_reps().end(); |
- float smallest_diff = std::numeric_limits<float>::max(); |
- for (ImageSkia::ImageSkiaReps::iterator it = |
- non_const->image_reps().begin(); |
- it < image_reps_.end(); ++it) { |
- if (it->scale() == scale) { |
- // found exact match |
- fetch_new_image = false; |
- if (it->is_null()) |
- continue; |
- exact_iter = it; |
- break; |
- } |
- float diff = std::abs(it->scale() - scale); |
- if (diff < smallest_diff && !it->is_null()) { |
- closest_iter = it; |
- smallest_diff = diff; |
- } |
- } |
- |
- if (fetch_new_image && source_.get()) { |
- DCHECK(CalledOnValidThread()) << |
- "An ImageSkia with the source must be accessed by the same thread."; |
- |
- ImageSkiaRep image; |
- float resource_scale = scale; |
- if (g_supported_scales) { |
- if (g_supported_scales->back() <= scale) { |
- resource_scale = g_supported_scales->back(); |
- } else { |
- for (size_t i = 0; i < g_supported_scales->size(); ++i) { |
- if ((*g_supported_scales)[i] + kFallbackToSmallerScaleDiff >= |
- scale) { |
- resource_scale = (*g_supported_scales)[i]; |
- break; |
- } |
- } |
- } |
- } |
- if (scale != resource_scale) { |
- std::vector<ImageSkiaRep>::iterator iter = FindRepresentation( |
- resource_scale, fetch_new_image); |
- DCHECK(iter != image_reps_.end()); |
- image = iter->unscaled() ? (*iter) : ScaleImageSkiaRep(*iter, scale); |
- } else { |
- image = source_->GetImageForScale(scale); |
- // Image may be missing for the specified scale in some cases, such like |
- // looking up 2x resources but the 2x resource pack is missing. Falls |
- // back to 1x and re-scale it. |
- if (image.is_null() && scale != 1.0f) |
- image = ScaleImageSkiaRep(source_->GetImageForScale(1.0f), scale); |
- } |
- |
- // If the source returned the new image, store it. |
- if (!image.is_null() && |
- std::find_if(image_reps_.begin(), image_reps_.end(), |
- Matcher(image.scale())) == image_reps_.end()) { |
- non_const->image_reps().push_back(image); |
- } |
- |
- // If the result image's scale isn't same as the expected scale, create |
- // null ImageSkiaRep with the |scale| so that the next lookup will |
- // fallback to the closest scale. |
- if (image.is_null() || image.scale() != scale) { |
- non_const->image_reps().push_back(ImageSkiaRep(SkBitmap(), scale)); |
- } |
- |
- // image_reps_ must have the exact much now, so find again. |
- return FindRepresentation(scale, false); |
- } |
- return exact_iter != image_reps_.end() ? exact_iter : closest_iter; |
- } |
+ float scale, |
+ bool fetch_new_image) const; |
private: |
- 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(); |
- } |
+ friend class base::RefCountedThreadSafe<ImageSkiaStorage>; |
+ |
+ virtual ~ImageSkiaStorage(); |
// Vector of bitmaps and their associated scale. |
std::vector<gfx::ImageSkiaRep> image_reps_; |
@@ -255,9 +123,142 @@ class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>, |
bool read_only_; |
- friend class base::RefCountedThreadSafe<ImageSkiaStorage>; |
+ DISALLOW_COPY_AND_ASSIGN(ImageSkiaStorage); |
}; |
+ImageSkiaStorage::ImageSkiaStorage(ImageSkiaSource* source, |
+ const gfx::Size& size) |
+ : source_(source), size_(size), read_only_(false) {} |
+ |
+ImageSkiaStorage::ImageSkiaStorage(ImageSkiaSource* source, float scale) |
+ : source_(source), read_only_(false) { |
+ ImageSkia::ImageSkiaReps::iterator it = FindRepresentation(scale, true); |
+ if (it == image_reps_.end() || it->is_null()) |
+ source_.reset(); |
+ else |
+ size_.SetSize(it->GetWidth(), it->GetHeight()); |
+} |
+ |
+void ImageSkiaStorage::DeleteSource() { |
+ source_.reset(); |
+} |
+ |
+void ImageSkiaStorage::SetReadOnly() { |
+ read_only_ = true; |
+} |
+ |
+void ImageSkiaStorage::DetachFromThread() { |
+ base::NonThreadSafe::DetachFromThread(); |
+} |
+ |
+bool ImageSkiaStorage::CanModify() const { |
+ return !read_only_ && CalledOnValidThread(); |
+} |
+ |
+bool ImageSkiaStorage::CanRead() const { |
+ return (read_only_ && !source_) || CalledOnValidThread(); |
+} |
+ |
+void ImageSkiaStorage::AddRepresentation(const ImageSkiaRep& image) { |
+ if (image.scale() != 1.0f) { |
+ for (ImageSkia::ImageSkiaReps::iterator it = image_reps_.begin(); |
+ it < image_reps_.end(); ++it) { |
+ if (it->unscaled()) { |
+ DCHECK_EQ(1.0f, it->scale()); |
+ it->SetScaled(); |
+ break; |
+ } |
+ } |
+ } |
+ image_reps_.push_back(image); |
+} |
+ |
+std::vector<ImageSkiaRep>::iterator ImageSkiaStorage::FindRepresentation( |
+ float scale, |
+ bool fetch_new_image) const { |
+ ImageSkiaStorage* non_const = const_cast<ImageSkiaStorage*>(this); |
+ |
+ ImageSkia::ImageSkiaReps::iterator closest_iter = |
+ non_const->image_reps().end(); |
+ ImageSkia::ImageSkiaReps::iterator exact_iter = non_const->image_reps().end(); |
+ float smallest_diff = std::numeric_limits<float>::max(); |
+ for (ImageSkia::ImageSkiaReps::iterator it = non_const->image_reps().begin(); |
+ it < image_reps_.end(); ++it) { |
+ if (it->scale() == scale) { |
+ // found exact match |
+ fetch_new_image = false; |
+ if (it->is_null()) |
+ continue; |
+ exact_iter = it; |
+ break; |
+ } |
+ float diff = std::abs(it->scale() - scale); |
+ if (diff < smallest_diff && !it->is_null()) { |
+ closest_iter = it; |
+ smallest_diff = diff; |
+ } |
+ } |
+ |
+ if (fetch_new_image && source_.get()) { |
+ DCHECK(CalledOnValidThread()) |
+ << "An ImageSkia with the source must be accessed by the same thread."; |
+ |
+ ImageSkiaRep image; |
+ float resource_scale = scale; |
+ if (g_supported_scales) { |
+ if (g_supported_scales->back() <= scale) { |
+ resource_scale = g_supported_scales->back(); |
+ } else { |
+ for (size_t i = 0; i < g_supported_scales->size(); ++i) { |
+ if ((*g_supported_scales)[i] + kFallbackToSmallerScaleDiff >= scale) { |
+ resource_scale = (*g_supported_scales)[i]; |
+ break; |
+ } |
+ } |
+ } |
+ } |
+ if (scale != resource_scale) { |
+ std::vector<ImageSkiaRep>::iterator iter = |
+ FindRepresentation(resource_scale, fetch_new_image); |
+ DCHECK(iter != image_reps_.end()); |
+ image = iter->unscaled() ? (*iter) : ScaleImageSkiaRep(*iter, scale); |
+ } else { |
+ image = source_->GetImageForScale(scale); |
+ // Image may be missing for the specified scale in some cases, such like |
+ // looking up 2x resources but the 2x resource pack is missing. Fall back |
+ // to 1x and re-scale it. |
+ if (image.is_null() && scale != 1.0f) |
+ image = ScaleImageSkiaRep(source_->GetImageForScale(1.0f), scale); |
+ } |
+ |
+ // If the source returned the new image, store it. |
+ if (!image.is_null() && |
+ std::find_if(image_reps_.begin(), image_reps_.end(), |
+ [&image](const ImageSkiaRep& rep) { |
+ return rep.scale() == image.scale(); |
+ }) == image_reps_.end()) { |
+ non_const->image_reps().push_back(image); |
+ } |
+ |
+ // If the result image's scale isn't same as the expected scale, create a |
+ // null ImageSkiaRep with the |scale| so that the next lookup will fall back |
+ // to the closest scale. |
+ if (image.is_null() || image.scale() != scale) { |
+ non_const->image_reps().push_back(ImageSkiaRep(SkBitmap(), scale)); |
+ } |
+ |
+ // image_reps_ must have the exact much now, so find again. |
+ return FindRepresentation(scale, false); |
+ } |
+ return exact_iter != image_reps_.end() ? exact_iter : closest_iter; |
+} |
+ |
+ImageSkiaStorage::~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(); |
+} |
+ |
} // internal |
ImageSkia::ImageSkia() : storage_(NULL) { |