Index: ui/gfx/image/image_skia.cc |
diff --git a/ui/gfx/image/image_skia.cc b/ui/gfx/image/image_skia.cc |
index e5fb8e3c617ce18b81fb4c00aea2918c07cd49d2..3d8acf135fb0b991938abca1660b94229af48897 100644 |
--- a/ui/gfx/image/image_skia.cc |
+++ b/ui/gfx/image/image_skia.cc |
@@ -4,30 +4,117 @@ |
#include "ui/gfx/image/image_skia.h" |
-#include <limits> |
+#include <algorithm> |
#include <cmath> |
+#include <limits> |
#include "base/logging.h" |
+#include "base/memory/scoped_ptr.h" |
+#include "ui/gfx/image/image_skia_source.h" |
#include "ui/gfx/size.h" |
#include "ui/gfx/skia_util.h" |
namespace gfx { |
+namespace { |
+ |
+// static |
+gfx::ImageSkiaRep& NullImageRep() { |
+ CR_DEFINE_STATIC_LOCAL(ImageSkiaRep, null_image_rep, ()); |
+ return null_image_rep; |
+} |
+ |
+} // namespace |
namespace internal { |
+namespace { |
+ |
+class Matcher { |
+ public: |
+ explicit Matcher(ui::ScaleFactor scale_factor) : scale_factor_(scale_factor) { |
+ } |
+ |
+ bool operator()(const ImageSkiaRep& rep) const { |
+ return rep.scale_factor() == scale_factor_; |
+ } |
+ |
+ private: |
+ ui::ScaleFactor scale_factor_; |
+}; |
+ |
+} // namespace |
// 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> { |
public: |
- ImageSkiaStorage() { |
+ ImageSkiaStorage(ImageSkiaSource* source, const gfx::Size& size) |
+ : source_(source), |
+ size_(size) { |
} |
std::vector<gfx::ImageSkiaRep>& image_reps() { return image_reps_; } |
- void set_size(const gfx::Size& size) { size_ = size; } |
const gfx::Size& size() const { return size_; } |
+ // 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 |
+ // |ImageSkiaSource::GetImageForScale|. If the source returns the |
+ // image with different scale factor (if the image doesn't exist in |
+ // resource, for example), it will fallback to closest image rep. |
+ std::vector<ImageSkiaRep>::iterator FindRepresentation( |
+ ui::ScaleFactor scale_factor, bool fetch_new_image) const { |
+ ImageSkiaStorage* non_const = const_cast<ImageSkiaStorage*>(this); |
+ |
+ float scale = ui::GetScaleFactorScale(scale_factor); |
+ 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->GetScale() == scale) { |
+ // found exact match |
+ fetch_new_image = false; |
+ if (it->is_null()) |
+ continue; |
+ exact_iter = it; |
+ break; |
+ } |
+ float diff = std::abs(it->GetScale() - scale); |
+ if (diff < smallest_diff && !it->is_null()) { |
+ closest_iter = it; |
+ smallest_diff = diff; |
+ } |
+ } |
+ |
+ if (fetch_new_image && source_.get()) { |
+ ImageSkiaRep image = source_->GetImageForScale(scale_factor); |
+ |
+ // 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_factor())) == image_reps_.end()) { |
+ non_const->image_reps().push_back(image); |
+ } |
+ |
+ // If the result image's scale factor isn't same as the expected |
+ // scale factor, create null ImageSkiaRep with the |scale_factor| |
+ // so that the next lookup will fallback to the closest scale. |
+ if (image.is_null() || image.scale_factor() != scale_factor) { |
+ non_const->image_reps().push_back( |
+ ImageSkiaRep(SkBitmap(), scale_factor)); |
+ } |
+ |
+ // image_reps_ must have the exact much now, so find again. |
+ return FindRepresentation(scale_factor, false); |
+ } |
+ return exact_iter != image_reps_.end() ? exact_iter : closest_iter; |
+ } |
+ |
private: |
~ImageSkiaStorage() { |
} |
@@ -35,8 +122,10 @@ class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> { |
// Vector of bitmaps and their associated scale factor. |
std::vector<gfx::ImageSkiaRep> image_reps_; |
+ scoped_ptr<ImageSkiaSource> source_; |
+ |
// Size of the image in DIP. |
- gfx::Size size_; |
+ const gfx::Size size_; |
friend class base::RefCounted<ImageSkiaStorage>; |
}; |
@@ -46,6 +135,11 @@ class ImageSkiaStorage : public base::RefCounted<ImageSkiaStorage> { |
ImageSkia::ImageSkia() : storage_(NULL) { |
} |
+ImageSkia::ImageSkia(ImageSkiaSource* source, const gfx::Size& size) |
+ : storage_(new internal::ImageSkiaStorage(source, size)) { |
+ DCHECK(source); |
+} |
+ |
ImageSkia::ImageSkia(const SkBitmap& bitmap) { |
Init(ImageSkiaRep(bitmap)); |
} |
@@ -103,7 +197,8 @@ void ImageSkia::RemoveRepresentation(ui::ScaleFactor scale_factor) { |
return; |
ImageSkiaReps& image_reps = storage_->image_reps(); |
- ImageSkiaReps::iterator it = FindRepresentation(scale_factor); |
+ ImageSkiaReps::iterator it = |
+ storage_->FindRepresentation(scale_factor, false); |
if (it != image_reps.end() && it->scale_factor() == scale_factor) |
image_reps.erase(it); |
} |
@@ -112,7 +207,8 @@ bool ImageSkia::HasRepresentation(ui::ScaleFactor scale_factor) { |
if (isNull()) |
return false; |
- ImageSkiaReps::iterator it = FindRepresentation(scale_factor); |
+ ImageSkiaReps::iterator it = |
+ storage_->FindRepresentation(scale_factor, false); |
return (it != storage_->image_reps().end() && |
it->scale_factor() == scale_factor); |
} |
@@ -122,7 +218,7 @@ const ImageSkiaRep& ImageSkia::GetRepresentation( |
if (isNull()) |
return NullImageRep(); |
- ImageSkiaReps::iterator it = FindRepresentation(scale_factor); |
+ ImageSkiaReps::iterator it = storage_->FindRepresentation(scale_factor, true); |
if (it == storage_->image_reps().end()) |
return NullImageRep(); |
@@ -137,6 +233,10 @@ int ImageSkia::width() const { |
return isNull() ? 0 : storage_->size().width(); |
} |
+gfx::Size ImageSkia::size() const { |
+ return gfx::Size(width(), height()); |
+} |
+ |
int ImageSkia::height() const { |
return isNull() ? 0 : storage_->size().height(); |
} |
@@ -191,36 +291,9 @@ void ImageSkia::Init(const ImageSkiaRep& image_rep) { |
storage_ = NULL; |
return; |
} |
- storage_ = new internal::ImageSkiaStorage(); |
- storage_->set_size(gfx::Size(image_rep.GetWidth(), image_rep.GetHeight())); |
+ storage_ = new internal::ImageSkiaStorage( |
+ NULL, gfx::Size(image_rep.GetWidth(), image_rep.GetHeight())); |
storage_->image_reps().push_back(image_rep); |
} |
-// static |
-ImageSkiaRep& ImageSkia::NullImageRep() { |
- CR_DEFINE_STATIC_LOCAL(ImageSkiaRep, null_image_rep, ()); |
- return null_image_rep; |
-} |
- |
-std::vector<ImageSkiaRep>::iterator ImageSkia::FindRepresentation( |
- ui::ScaleFactor scale_factor) const { |
- DCHECK(!isNull()); |
- |
- float scale = ui::GetScaleFactorScale(scale_factor); |
- ImageSkiaReps& image_reps = storage_->image_reps(); |
- ImageSkiaReps::iterator closest_iter = image_reps.end(); |
- float smallest_diff = std::numeric_limits<float>::max(); |
- for (ImageSkiaReps::iterator it = image_reps.begin(); |
- it < image_reps.end(); |
- ++it) { |
- float diff = std::abs(it->GetScale() - scale); |
- if (diff < smallest_diff) { |
- closest_iter = it; |
- smallest_diff = diff; |
- } |
- } |
- |
- return closest_iter; |
-} |
- |
} // namespace gfx |