| 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
|
|
|