summaryrefslogtreecommitdiffstats
path: root/chromium/ui/gfx/image
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/ui/gfx/image')
-rw-r--r--chromium/ui/gfx/image/OWNERS2
-rw-r--r--chromium/ui/gfx/image/cairo_cached_surface.cc109
-rw-r--r--chromium/ui/gfx/image/cairo_cached_surface.h84
-rw-r--r--chromium/ui/gfx/image/image.cc393
-rw-r--r--chromium/ui/gfx/image/image.h24
-rw-r--r--chromium/ui/gfx/image/image_skia.cc94
-rw-r--r--chromium/ui/gfx/image/image_skia.h4
-rw-r--r--chromium/ui/gfx/image/image_skia_rep.cc19
-rw-r--r--chromium/ui/gfx/image/image_skia_rep.h16
-rw-r--r--chromium/ui/gfx/image/image_skia_unittest.cc185
-rw-r--r--chromium/ui/gfx/image/image_skia_util_mac.h4
-rw-r--r--chromium/ui/gfx/image/image_skia_util_mac.mm6
-rw-r--r--chromium/ui/gfx/image/image_unittest.cc53
-rw-r--r--chromium/ui/gfx/image/image_unittest_util.cc31
-rw-r--r--chromium/ui/gfx/image/image_unittest_util.h2
-rw-r--r--chromium/ui/gfx/image/image_util.cc57
-rw-r--r--chromium/ui/gfx/image/image_util.h17
-rw-r--r--chromium/ui/gfx/image/image_util_unittest.cc78
18 files changed, 588 insertions, 590 deletions
diff --git a/chromium/ui/gfx/image/OWNERS b/chromium/ui/gfx/image/OWNERS
index d3273727c23..23dbb5a958f 100644
--- a/chromium/ui/gfx/image/OWNERS
+++ b/chromium/ui/gfx/image/OWNERS
@@ -1,4 +1,4 @@
rsesek@chromium.org
# ImageSkia related classes except for _mac/_ios stuff
-per-file image_skia.*=oshima@chromium.org
+per-file image_skia*=oshima@chromium.org
diff --git a/chromium/ui/gfx/image/cairo_cached_surface.cc b/chromium/ui/gfx/image/cairo_cached_surface.cc
deleted file mode 100644
index 2de4a3210b3..00000000000
--- a/chromium/ui/gfx/image/cairo_cached_surface.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/image/cairo_cached_surface.h"
-
-#include <gtk/gtk.h>
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-
-namespace gfx {
-
-CairoCachedSurface::CairoCachedSurface() : pixbuf_(NULL) {
-}
-
-CairoCachedSurface::~CairoCachedSurface() {
- Reset();
-}
-
-void CairoCachedSurface::Reset() {
- for (SurfaceVector::iterator it = surface_map_.begin();
- it != surface_map_.end(); ++it) {
- cairo_surface_destroy(it->second);
- }
- surface_map_.clear();
-
- if (pixbuf_) {
- g_object_unref(pixbuf_);
- pixbuf_ = NULL;
- }
-}
-
-int CairoCachedSurface::Width() const {
- return pixbuf_ ? gdk_pixbuf_get_width(pixbuf_) : -1;
-}
-
-int CairoCachedSurface::Height() const {
- return pixbuf_ ? gdk_pixbuf_get_height(pixbuf_) : -1;
-}
-
-void CairoCachedSurface::UsePixbuf(GdkPixbuf* pixbuf) {
- if (pixbuf)
- g_object_ref(pixbuf);
-
- Reset();
-
- pixbuf_ = pixbuf;
-}
-
-void CairoCachedSurface::SetSource(cairo_t* cr, GtkWidget* widget,
- int x, int y) const {
- SetSource(cr, gtk_widget_get_display(widget), x, y);
-}
-
-void CairoCachedSurface::SetSource(cairo_t* cr, GdkDisplay* display,
- int x, int y) const {
- DCHECK(pixbuf_);
- DCHECK(cr);
- DCHECK(display);
-
- cairo_surface_t* surface = GetSurfaceFor(cr, display);
- cairo_set_source_surface(cr, surface, x, y);
-}
-
-void CairoCachedSurface::MaskSource(cairo_t* cr, GtkWidget* widget,
- int x, int y) const {
- MaskSource(cr, gtk_widget_get_display(widget), x, y);
-}
-
-void CairoCachedSurface::MaskSource(cairo_t* cr, GdkDisplay* display,
- int x, int y) const {
- DCHECK(pixbuf_);
- DCHECK(cr);
- DCHECK(display);
-
- cairo_surface_t* surface = GetSurfaceFor(cr, display);
- cairo_mask_surface(cr, surface, x, y);
-}
-
-cairo_surface_t* CairoCachedSurface::GetSurfaceFor(cairo_t* cr,
- GdkDisplay* display) const {
- for (SurfaceVector::const_iterator it = surface_map_.begin();
- it != surface_map_.end(); ++it) {
- if (display == it->first) {
- return it->second;
- }
- }
-
- // First time here since last UsePixbuf call. Generate the surface.
- cairo_surface_t* target = cairo_get_target(cr);
- cairo_surface_t* out = cairo_surface_create_similar(
- target,
- CAIRO_CONTENT_COLOR_ALPHA,
- gdk_pixbuf_get_width(pixbuf_),
- gdk_pixbuf_get_height(pixbuf_));
-
- DCHECK(out);
-
- cairo_t* copy_cr = cairo_create(out);
- gdk_cairo_set_source_pixbuf(copy_cr, pixbuf_, 0, 0);
- cairo_paint(copy_cr);
- cairo_destroy(copy_cr);
-
- surface_map_.push_back(std::make_pair(display, out));
- return out;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/image/cairo_cached_surface.h b/chromium/ui/gfx/image/cairo_cached_surface.h
deleted file mode 100644
index ceece4ba2d2..00000000000
--- a/chromium/ui/gfx/image/cairo_cached_surface.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_IMAGE_CAIRO_CACHED_SURFACE_H_
-#define UI_GFX_IMAGE_CAIRO_CACHED_SURFACE_H_
-
-#include <vector>
-
-#include "ui/gfx/gfx_export.h"
-
-typedef struct _GdkDisplay GdkDisplay;
-typedef struct _GdkPixbuf GdkPixbuf;
-typedef struct _GtkWidget GtkWidget;
-typedef struct _cairo cairo_t;
-typedef struct _cairo_surface cairo_surface_t;
-
-namespace gfx {
-
-// A helper class that takes a GdkPixbuf* and renders it to the screen. Unlike
-// gdk_cairo_set_source_pixbuf(), CairoCachedSurface assumes that the pixbuf is
-// immutable after UsePixbuf() is called and can be sent to the display server
-// once. From then on, that cached version is used so we don't upload the same
-// image each and every time we expose.
-//
-// Most cached surfaces are owned by the GtkThemeService, which associates
-// them with a certain XDisplay. Some users of surfaces (CustomDrawButtonBase,
-// for example) own their surfaces instead since they interact with the
-// ResourceBundle instead of the GtkThemeService.
-class GFX_EXPORT CairoCachedSurface {
- public:
- CairoCachedSurface();
- ~CairoCachedSurface();
-
- // Whether this CairoCachedSurface owns a GdkPixbuf.
- bool valid() const {
- return pixbuf_;
- }
-
- // Delete all our data.
- void Reset();
-
- // The dimensions of the underlying pixbuf/surface. (or -1 if invalid.)
- int Width() const;
- int Height() const;
-
- // Sets the pixbuf that we pass to cairo. Calling UsePixbuf() only derefs the
- // current pixbuf and surface (if they exist). Actually transfering data to
- // the X server occurs at SetSource() time. Calling UsePixbuf() should only
- // be done once as it clears cached data from the X server.
- void UsePixbuf(GdkPixbuf* pixbuf);
-
- // Sets our pixbuf as the active surface starting at (x, y), uploading it in
- // case we don't have an X backed surface cached.
- void SetSource(cairo_t* cr, GtkWidget* widget, int x, int y) const;
- void SetSource(cairo_t* cr, GdkDisplay* display, int x, int y) const;
-
- // Performs a mask operation, using this surface as the alpha channel.
- void MaskSource(cairo_t* cr, GtkWidget* widget, int x, int y) const;
- void MaskSource(cairo_t* cr, GdkDisplay* display, int x, int y) const;
-
- // Raw access to the pixbuf. May be NULL. Used for a few gdk operations
- // regarding window shaping.
- GdkPixbuf* pixbuf() { return pixbuf_; }
-
- private:
- typedef std::vector<std::pair<GdkDisplay*, cairo_surface_t*> > SurfaceVector;
-
- // Returns a surface . Caches results so only one copy of the image data
- // lives on the display server.
- cairo_surface_t* GetSurfaceFor(cairo_t* cr, GdkDisplay* display) const;
-
- // The source pixbuf.
- GdkPixbuf* pixbuf_;
-
- // Our list of cached surfaces. 99% of the time, this will only contain a
- // single entry. At most two. We need to get this right for multiple displays
- // to work correct, since each GdkDisplay is a different display server.
- mutable SurfaceVector surface_map_;
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_IMAGE_CAIRO_CACHED_SURFACE_H_
diff --git a/chromium/ui/gfx/image/image.cc b/chromium/ui/gfx/image/image.cc
index 91b9e69b289..459880742f8 100644
--- a/chromium/ui/gfx/image/image.cc
+++ b/chromium/ui/gfx/image/image.cc
@@ -5,6 +5,7 @@
#include "ui/gfx/image/image.h"
#include <algorithm>
+#include <set>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
@@ -12,21 +13,14 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/image/image_png_rep.h"
#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/size.h"
#if !defined(OS_IOS)
#include "ui/gfx/codec/png_codec.h"
#endif
-#if defined(TOOLKIT_GTK)
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <gdk/gdk.h>
-#include <glib-object.h>
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/gtk_util.h"
-#include "ui/gfx/image/cairo_cached_surface.h"
-#include "ui/gfx/scoped_gobject.h"
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
#include "base/mac/foundation_util.h"
#include "ui/gfx/image/image_skia_util_ios.h"
#elif defined(OS_MACOSX)
@@ -38,100 +32,25 @@ namespace gfx {
namespace internal {
-#if defined(TOOLKIT_GTK)
-const ImageSkia ImageSkiaFromGdkPixbuf(GdkPixbuf* pixbuf) {
- CHECK(pixbuf);
- gfx::Canvas canvas(gfx::Size(gdk_pixbuf_get_width(pixbuf),
- gdk_pixbuf_get_height(pixbuf)),
- 1.0f,
- false);
- skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas());
- cairo_t* cr = scoped_platform_paint.GetPlatformSurface();
- gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
- cairo_paint(cr);
- return ImageSkia(canvas.ExtractImageRep());
-}
-
-// Returns a 16x16 red pixbuf to visually show error in decoding PNG.
-// Also logs error to console.
-GdkPixbuf* GetErrorPixbuf() {
- LOG(ERROR) << "Unable to decode PNG.";
- GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 16, 16);
- gdk_pixbuf_fill(pixbuf, 0xff0000ff);
- return pixbuf;
-}
-
-GdkPixbuf* GdkPixbufFromPNG(
- const std::vector<gfx::ImagePNGRep>& image_png_reps) {
- scoped_refptr<base::RefCountedMemory> png_bytes(NULL);
- for (size_t i = 0; i < image_png_reps.size(); ++i) {
- if (image_png_reps[i].scale == 1.0f)
- png_bytes = image_png_reps[i].raw_data;
- }
-
- if (!png_bytes.get())
- return GetErrorPixbuf();
-
- GdkPixbuf* pixbuf = NULL;
- ui::ScopedGObject<GdkPixbufLoader>::Type loader(gdk_pixbuf_loader_new());
-
- bool ok = gdk_pixbuf_loader_write(loader.get(),
- reinterpret_cast<const guint8*>(png_bytes->front()), png_bytes->size(),
- NULL);
-
- // Calling gdk_pixbuf_loader_close forces the data to be parsed by the
- // loader. This must be done before calling gdk_pixbuf_loader_get_pixbuf.
- if (ok)
- ok = gdk_pixbuf_loader_close(loader.get(), NULL);
- if (ok)
- pixbuf = gdk_pixbuf_loader_get_pixbuf(loader.get());
-
- if (pixbuf) {
- // The pixbuf is owned by the scoped loader which will delete its ref when
- // it goes out of scope. Add a ref so that the pixbuf still exists.
- g_object_ref(pixbuf);
- } else {
- return GetErrorPixbuf();
- }
-
- return pixbuf;
-}
-
-scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromPixbuf(
- GdkPixbuf* pixbuf) {
- gchar* image = NULL;
- gsize image_size;
- GError* error = NULL;
- CHECK(gdk_pixbuf_save_to_buffer(
- pixbuf, &image, &image_size, "png", &error, NULL));
- scoped_refptr<base::RefCountedBytes> png_bytes(
- new base::RefCountedBytes());
- png_bytes->data().assign(image, image + image_size);
- g_free(image);
- return png_bytes;
-}
-
-#endif // defined(TOOLKIT_GTK)
-
#if defined(OS_IOS)
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromUIImage(
UIImage* uiimage);
// Caller takes ownership of the returned UIImage.
UIImage* CreateUIImageFromPNG(
- const std::vector<gfx::ImagePNGRep>& image_png_reps);
+ const std::vector<ImagePNGRep>& image_png_reps);
gfx::Size UIImageSize(UIImage* image);
#elif defined(OS_MACOSX)
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromNSImage(
NSImage* nsimage);
// Caller takes ownership of the returned NSImage.
-NSImage* NSImageFromPNG(const std::vector<gfx::ImagePNGRep>& image_png_reps,
+NSImage* NSImageFromPNG(const std::vector<ImagePNGRep>& image_png_reps,
CGColorSpaceRef color_space);
gfx::Size NSImageSize(NSImage* image);
#endif // defined(OS_MACOSX)
#if defined(OS_IOS)
ImageSkia* ImageSkiaFromPNG(
- const std::vector<gfx::ImagePNGRep>& image_png_reps);
+ const std::vector<ImagePNGRep>& image_png_reps);
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
const ImageSkia* skia);
#else
@@ -141,32 +60,92 @@ ImageSkia* GetErrorImageSkia() {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
bitmap.allocPixels();
- bitmap.eraseRGB(0xff, 0, 0);
- return new gfx::ImageSkia(gfx::ImageSkiaRep(bitmap, 1.0f));
+ bitmap.eraseARGB(0xff, 0xff, 0, 0);
+ return new ImageSkia(ImageSkiaRep(bitmap, 1.0f));
}
+class PNGImageSource : public ImageSkiaSource {
+ public:
+ PNGImageSource() {}
+ virtual ~PNGImageSource() {}
+
+ virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
+ if (image_skia_reps_.empty())
+ return ImageSkiaRep();
+
+ const ImageSkiaRep* rep = NULL;
+ // gfx::ImageSkia passes one of the resource scale factors. The source
+ // should return:
+ // 1) The ImageSkiaRep with the highest scale if all available
+ // scales are smaller than |scale|.
+ // 2) The ImageSkiaRep with the smallest one that is larger than |scale|.
+ for (ImageSkiaRepSet::const_iterator iter = image_skia_reps_.begin();
+ iter != image_skia_reps_.end(); ++iter) {
+ if ((*iter).scale() == scale)
+ return (*iter);
+ if (!rep || rep->scale() < (*iter).scale())
+ rep = &(*iter);
+ if (rep->scale() >= scale)
+ break;
+ }
+ return rep ? *rep : ImageSkiaRep();
+ }
+
+ const gfx::Size size() const {
+ return size_;
+ }
+
+ bool AddPNGData(const ImagePNGRep& png_rep) {
+ const gfx::ImageSkiaRep rep = ToImageSkiaRep(png_rep);
+ if (rep.is_null())
+ return false;
+ if (size_.IsEmpty())
+ size_ = gfx::Size(rep.GetWidth(), rep.GetHeight());
+ image_skia_reps_.insert(rep);
+ return true;
+ }
+
+ static ImageSkiaRep ToImageSkiaRep(const ImagePNGRep& png_rep) {
+ scoped_refptr<base::RefCountedMemory> raw_data = png_rep.raw_data;
+ CHECK(raw_data.get());
+ SkBitmap bitmap;
+ if (!PNGCodec::Decode(raw_data->front(), raw_data->size(),
+ &bitmap)) {
+ LOG(ERROR) << "Unable to decode PNG for " << png_rep.scale << ".";
+ return ImageSkiaRep();
+ }
+ return ImageSkiaRep(bitmap, png_rep.scale);
+ }
+
+ private:
+ struct Compare {
+ bool operator()(const ImageSkiaRep& rep1, const ImageSkiaRep& rep2) {
+ return rep1.scale() < rep2.scale();
+ }
+ };
+
+ typedef std::set<ImageSkiaRep, Compare> ImageSkiaRepSet;
+ ImageSkiaRepSet image_skia_reps_;
+ gfx::Size size_;
+
+ DISALLOW_COPY_AND_ASSIGN(PNGImageSource);
+};
+
ImageSkia* ImageSkiaFromPNG(
- const std::vector<gfx::ImagePNGRep>& image_png_reps) {
+ const std::vector<ImagePNGRep>& image_png_reps) {
if (image_png_reps.empty())
return GetErrorImageSkia();
+ scoped_ptr<PNGImageSource> image_source(new PNGImageSource);
- scoped_ptr<gfx::ImageSkia> image_skia(new ImageSkia());
for (size_t i = 0; i < image_png_reps.size(); ++i) {
- scoped_refptr<base::RefCountedMemory> raw_data =
- image_png_reps[i].raw_data;
- CHECK(raw_data.get());
- SkBitmap bitmap;
- if (!gfx::PNGCodec::Decode(raw_data->front(), raw_data->size(),
- &bitmap)) {
- LOG(ERROR) << "Unable to decode PNG for "
- << image_png_reps[i].scale
- << ".";
+ if (!image_source->AddPNGData(image_png_reps[i]))
return GetErrorImageSkia();
- }
- image_skia->AddRepresentation(gfx::ImageSkiaRep(
- bitmap, image_png_reps[i].scale));
}
- return image_skia.release();
+ const gfx::Size& size = image_source->size();
+ DCHECK(!size.IsEmpty());
+ if (size.IsEmpty())
+ return GetErrorImageSkia();
+ return new ImageSkia(image_source.release(), size);
}
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
@@ -175,7 +154,7 @@ scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
scoped_refptr<base::RefCountedBytes> png_bytes(new base::RefCountedBytes());
if (image_skia_rep.scale() != 1.0f ||
- !gfx::PNGCodec::EncodeBGRASkBitmap(image_skia_rep.sk_bitmap(), false,
+ !PNGCodec::EncodeBGRASkBitmap(image_skia_rep.sk_bitmap(), false,
&png_bytes->data())) {
return NULL;
}
@@ -185,8 +164,6 @@ scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
class ImageRepPNG;
class ImageRepSkia;
-class ImageRepGdk;
-class ImageRepCairo;
class ImageRepCocoa;
class ImageRepCocoaTouch;
@@ -213,18 +190,6 @@ class ImageRep {
return reinterpret_cast<ImageRepSkia*>(this);
}
-#if defined(TOOLKIT_GTK)
- ImageRepGdk* AsImageRepGdk() {
- CHECK_EQ(type_, Image::kImageRepGdk);
- return reinterpret_cast<ImageRepGdk*>(this);
- }
-
- ImageRepCairo* AsImageRepCairo() {
- CHECK_EQ(type_, Image::kImageRepCairo);
- return reinterpret_cast<ImageRepCairo*>(this);
- }
-#endif
-
#if defined(OS_IOS)
ImageRepCocoaTouch* AsImageRepCocoaTouch() {
CHECK_EQ(type_, Image::kImageRepCocoaTouch);
@@ -326,77 +291,6 @@ class ImageRepSkia : public ImageRep {
DISALLOW_COPY_AND_ASSIGN(ImageRepSkia);
};
-#if defined(TOOLKIT_GTK)
-class ImageRepGdk : public ImageRep {
- public:
- explicit ImageRepGdk(GdkPixbuf* pixbuf)
- : ImageRep(Image::kImageRepGdk),
- pixbuf_(pixbuf) {
- CHECK(pixbuf);
- }
-
- virtual ~ImageRepGdk() {
- if (pixbuf_) {
- g_object_unref(pixbuf_);
- pixbuf_ = NULL;
- }
- }
-
- virtual int Width() const OVERRIDE {
- return gdk_pixbuf_get_width(pixbuf_);
- }
-
- virtual int Height() const OVERRIDE {
- return gdk_pixbuf_get_height(pixbuf_);
- }
-
- virtual gfx::Size Size() const OVERRIDE {
- return gfx::Size(Width(), Height());
- }
-
- GdkPixbuf* pixbuf() const { return pixbuf_; }
-
- private:
- GdkPixbuf* pixbuf_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageRepGdk);
-};
-
-// Represents data that lives on the display server instead of in the client.
-class ImageRepCairo : public ImageRep {
- public:
- explicit ImageRepCairo(GdkPixbuf* pixbuf)
- : ImageRep(Image::kImageRepCairo),
- cairo_cache_(new CairoCachedSurface) {
- CHECK(pixbuf);
- cairo_cache_->UsePixbuf(pixbuf);
- }
-
- virtual ~ImageRepCairo() {
- delete cairo_cache_;
- }
-
- virtual int Width() const OVERRIDE {
- return cairo_cache_->Width();
- }
-
- virtual int Height() const OVERRIDE {
- return cairo_cache_->Height();
- }
-
- virtual gfx::Size Size() const OVERRIDE {
- return gfx::Size(Width(), Height());
- }
-
- CairoCachedSurface* surface() const { return cairo_cache_; }
-
- private:
- CairoCachedSurface* cairo_cache_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageRepCairo);
-};
-#endif // defined(TOOLKIT_GTK)
-
#if defined(OS_IOS)
class ImageRepCocoaTouch : public ImageRep {
public:
@@ -470,7 +364,7 @@ class ImageRepCocoa : public ImageRep {
// ImageReps. This way, the Image can be cheaply copied.
class ImageStorage : public base::RefCounted<ImageStorage> {
public:
- ImageStorage(gfx::Image::RepresentationType default_type)
+ ImageStorage(Image::RepresentationType default_type)
: default_representation_type_(default_type),
#if defined(OS_MACOSX) && !defined(OS_IOS)
default_representation_color_space_(
@@ -479,10 +373,10 @@ class ImageStorage : public base::RefCounted<ImageStorage> {
representations_deleter_(&representations_) {
}
- gfx::Image::RepresentationType default_representation_type() {
+ Image::RepresentationType default_representation_type() {
return default_representation_type_;
}
- gfx::Image::RepresentationMap& representations() { return representations_; }
+ Image::RepresentationMap& representations() { return representations_; }
#if defined(OS_MACOSX) && !defined(OS_IOS)
void set_default_representation_color_space(CGColorSpaceRef color_space) {
@@ -500,7 +394,7 @@ class ImageStorage : public base::RefCounted<ImageStorage> {
// The type of image that was passed to the constructor. This key will always
// exist in the |representations_| map.
- gfx::Image::RepresentationType default_representation_type_;
+ Image::RepresentationType default_representation_type_;
#if defined(OS_MACOSX) && !defined(OS_IOS)
// The default representation's colorspace. This is used for converting to
@@ -512,7 +406,7 @@ class ImageStorage : public base::RefCounted<ImageStorage> {
// All the representations of an Image. Size will always be at least one, with
// more for any converted representations.
- gfx::Image::RepresentationMap representations_;
+ Image::RepresentationMap representations_;
STLValueDeleter<Image::RepresentationMap> representations_deleter_;
@@ -550,16 +444,6 @@ Image::Image(const ImageSkia& image) {
}
}
-#if defined(TOOLKIT_GTK)
-Image::Image(GdkPixbuf* pixbuf) {
- if (pixbuf) {
- storage_ = new internal::ImageStorage(Image::kImageRepGdk);
- internal::ImageRepGdk* rep = new internal::ImageRepGdk(pixbuf);
- AddRepresentation(rep);
- }
-}
-#endif
-
#if defined(OS_IOS)
Image::Image(UIImage* image)
: storage_(new internal::ImageStorage(Image::kImageRepCocoaTouch)) {
@@ -591,20 +475,29 @@ Image::~Image() {
// static
Image Image::CreateFrom1xBitmap(const SkBitmap& bitmap) {
- return gfx::Image(ImageSkia::CreateFrom1xBitmap(bitmap));
+ return Image(ImageSkia::CreateFrom1xBitmap(bitmap));
}
// static
Image Image::CreateFrom1xPNGBytes(const unsigned char* input,
size_t input_size) {
if (input_size == 0u)
- return gfx::Image();
+ return Image();
scoped_refptr<base::RefCountedBytes> raw_data(new base::RefCountedBytes());
raw_data->data().assign(input, input + input_size);
- std::vector<gfx::ImagePNGRep> image_reps;
- image_reps.push_back(ImagePNGRep(raw_data, 1.0f));
- return gfx::Image(image_reps);
+
+ return CreateFrom1xPNGBytes(raw_data);
+}
+
+Image Image::CreateFrom1xPNGBytes(
+ const scoped_refptr<base::RefCountedMemory>& input) {
+ if (!input.get() || input->size() == 0u)
+ return Image();
+
+ std::vector<ImagePNGRep> image_reps;
+ image_reps.push_back(ImagePNGRep(input, 1.0f));
+ return Image(image_reps);
}
const SkBitmap* Image::ToSkBitmap() const {
@@ -623,15 +516,7 @@ const ImageSkia* Image::ToImageSkia() const {
internal::ImageSkiaFromPNG(png_rep->image_reps()));
break;
}
-#if defined(TOOLKIT_GTK)
- case kImageRepGdk: {
- internal::ImageRepGdk* native_rep =
- GetRepresentation(kImageRepGdk, true)->AsImageRepGdk();
- rep = new internal::ImageRepSkia(new ImageSkia(
- internal::ImageSkiaFromGdkPixbuf(native_rep->pixbuf())));
- break;
- }
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
case kImageRepCocoaTouch: {
internal::ImageRepCocoaTouch* native_rep =
GetRepresentation(kImageRepCocoaTouch, true)
@@ -658,47 +543,6 @@ const ImageSkia* Image::ToImageSkia() const {
return rep->AsImageRepSkia()->image();
}
-#if defined(TOOLKIT_GTK)
-GdkPixbuf* Image::ToGdkPixbuf() const {
- internal::ImageRep* rep = GetRepresentation(kImageRepGdk, false);
- if (!rep) {
- switch (DefaultRepresentationType()) {
- case kImageRepPNG: {
- internal::ImageRepPNG* png_rep =
- GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
- rep = new internal::ImageRepGdk(internal::GdkPixbufFromPNG(
- png_rep->image_reps()));
- break;
- }
- case kImageRepSkia: {
- internal::ImageRepSkia* skia_rep =
- GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
- rep = new internal::ImageRepGdk(gfx::GdkPixbufFromSkBitmap(
- *skia_rep->image()->bitmap()));
- break;
- }
- default:
- NOTREACHED();
- }
- CHECK(rep);
- AddRepresentation(rep);
- }
- return rep->AsImageRepGdk()->pixbuf();
-}
-
-CairoCachedSurface* const Image::ToCairo() const {
- internal::ImageRep* rep = GetRepresentation(kImageRepCairo, false);
- if (!rep) {
- // Handle any-to-Cairo conversion. This may create and cache an intermediate
- // pixbuf before sending the data to the display server.
- rep = new internal::ImageRepCairo(ToGdkPixbuf());
- CHECK(rep);
- AddRepresentation(rep);
- }
- return rep->AsImageRepCairo()->surface();
-}
-#endif
-
#if defined(OS_IOS)
UIImage* Image::ToUIImage() const {
internal::ImageRep* rep = GetRepresentation(kImageRepCocoaTouch, false);
@@ -768,7 +612,7 @@ scoped_refptr<base::RefCountedMemory> Image::As1xPNGBytes() const {
internal::ImageRep* rep = GetRepresentation(kImageRepPNG, false);
if (rep) {
- const std::vector<gfx::ImagePNGRep>& image_png_reps =
+ const std::vector<ImagePNGRep>& image_png_reps =
rep->AsImageRepPNG()->image_reps();
for (size_t i = 0; i < image_png_reps.size(); ++i) {
if (image_png_reps[i].scale == 1.0f)
@@ -779,14 +623,7 @@ scoped_refptr<base::RefCountedMemory> Image::As1xPNGBytes() const {
scoped_refptr<base::RefCountedMemory> png_bytes(NULL);
switch (DefaultRepresentationType()) {
-#if defined(TOOLKIT_GTK)
- case kImageRepGdk: {
- internal::ImageRepGdk* gdk_rep =
- GetRepresentation(kImageRepGdk, true)->AsImageRepGdk();
- png_bytes = internal::Get1xPNGBytesFromPixbuf(gdk_rep->pixbuf());
- break;
- }
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
case kImageRepCocoaTouch: {
internal::ImageRepCocoaTouch* cocoa_touch_rep =
GetRepresentation(kImageRepCocoaTouch, true)
@@ -826,7 +663,7 @@ scoped_refptr<base::RefCountedMemory> Image::As1xPNGBytes() const {
// final type eg (converting from ImageRepSkia to ImageRepPNG to get an
// ImageRepCocoa).
std::vector<ImagePNGRep> image_png_reps;
- image_png_reps.push_back(gfx::ImagePNGRep(png_bytes, 1.0f));
+ image_png_reps.push_back(ImagePNGRep(png_bytes, 1.0f));
rep = new internal::ImageRepPNG(image_png_reps);
AddRepresentation(rep);
return png_bytes;
@@ -861,14 +698,6 @@ SkBitmap* Image::CopySkBitmap() const {
return new SkBitmap(*ToSkBitmap());
}
-#if defined(TOOLKIT_GTK)
-GdkPixbuf* Image::CopyGdkPixbuf() const {
- GdkPixbuf* pixbuf = ToGdkPixbuf();
- g_object_ref(pixbuf);
- return pixbuf;
-}
-#endif
-
#if defined(OS_IOS)
UIImage* Image::CopyUIImage() const {
UIImage* image = ToUIImage();
@@ -916,7 +745,7 @@ gfx::Size Image::Size() const {
return GetRepresentation(DefaultRepresentationType(), true)->Size();
}
-void Image::SwapRepresentations(gfx::Image* other) {
+void Image::SwapRepresentations(Image* other) {
storage_.swap(other->storage_);
}
@@ -929,11 +758,7 @@ void Image::SetSourceColorSpace(CGColorSpaceRef color_space) {
Image::RepresentationType Image::DefaultRepresentationType() const {
CHECK(storage_.get());
- RepresentationType default_type = storage_->default_representation_type();
- // The conversions above assume that the default representation type is never
- // kImageRepCairo.
- DCHECK_NE(default_type, kImageRepCairo);
- return default_type;
+ return storage_->default_representation_type();
}
internal::ImageRep* Image::GetRepresentation(
diff --git a/chromium/ui/gfx/image/image.h b/chromium/ui/gfx/image/image.h
index d4093b74063..19ca93dada9 100644
--- a/chromium/ui/gfx/image/image.h
+++ b/chromium/ui/gfx/image/image.h
@@ -44,10 +44,6 @@ struct ImagePNGRep;
class ImageSkia;
class Size;
-#if defined(TOOLKIT_GTK)
-class CairoCachedSurface;
-#endif
-
namespace internal {
class ImageRep;
class ImageStorage;
@@ -56,10 +52,8 @@ class ImageStorage;
class GFX_EXPORT Image {
public:
enum RepresentationType {
- kImageRepGdk,
kImageRepCocoa,
kImageRepCocoaTouch,
- kImageRepCairo,
kImageRepSkia,
kImageRepPNG,
};
@@ -77,10 +71,7 @@ class GFX_EXPORT Image {
// representation.
explicit Image(const ImageSkia& image);
-#if defined(TOOLKIT_GTK)
- // Does not increase |pixbuf|'s reference count; expects to take ownership.
- explicit Image(GdkPixbuf* pixbuf);
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
// Does not retain |image|; expects to take ownership.
explicit Image(UIImage* image);
#elif defined(OS_MACOSX)
@@ -113,15 +104,16 @@ class GFX_EXPORT Image {
static Image CreateFrom1xPNGBytes(const unsigned char* input,
size_t input_size);
+ // Creates an image from the PNG encoded input.
+ static Image CreateFrom1xPNGBytes(
+ const scoped_refptr<base::RefCountedMemory>& input);
+
// Converts the Image to the desired representation and stores it internally.
// The returned result is a weak pointer owned by and scoped to the life of
// the Image. Must only be called if IsEmpty() is false.
const SkBitmap* ToSkBitmap() const;
const ImageSkia* ToImageSkia() const;
-#if defined(TOOLKIT_GTK)
- GdkPixbuf* ToGdkPixbuf() const;
- CairoCachedSurface* const ToCairo() const;
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
UIImage* ToUIImage() const;
#elif defined(OS_MACOSX)
NSImage* ToNSImage() const;
@@ -154,9 +146,7 @@ class GFX_EXPORT Image {
scoped_refptr<base::RefCountedMemory> Copy1xPNGBytes() const;
ImageSkia* CopyImageSkia() const;
SkBitmap* CopySkBitmap() const;
-#if defined(TOOLKIT_GTK)
- GdkPixbuf* CopyGdkPixbuf() const;
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
UIImage* CopyUIImage() const;
#elif defined(OS_MACOSX)
NSImage* CopyNSImage() const;
diff --git a/chromium/ui/gfx/image/image_skia.cc b/chromium/ui/gfx/image/image_skia.cc
index a283117db24..21d08de3003 100644
--- a/chromium/ui/gfx/image/image_skia.cc
+++ b/chromium/ui/gfx/image/image_skia.cc
@@ -8,14 +8,17 @@
#include <cmath>
#include <limits>
+#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/threading/non_thread_safe.h"
+#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "ui/gfx/skia_util.h"
+#include "ui/gfx/switches.h"
namespace gfx {
namespace {
@@ -27,6 +30,13 @@ gfx::ImageSkiaRep& NullImageRep() {
}
std::vector<float>* g_supported_scales = NULL;
+
+// The difference to fall back to the smaller scale factor rather than the
+// larger one. For example, assume 1.25 is requested but only 1.0 and 2.0 are
+// supported. In that case, not fall back to 2.0 but 1.0, and then expand
+// the image to 1.25.
+const float kFallbackToSmallerScaleDiff = 0.25f;
+
} // namespace
namespace internal {
@@ -102,12 +112,36 @@ class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>,
return (read_only_ && !source_.get()) || CalledOnValidThread();
}
+ // 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);
+ }
+
// 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
// |storage| is set, it fetches new image by calling
- // |ImageSkiaSource::GetImageForScale|. If the source returns the image with
- // different scale (if the image doesn't exist in resource, for example), it
- // will fallback to closest image rep.
+ // |ImageSkiaSource::GetImageForScale|. There are two modes to deal with
+ // arbitrary scale factors.
+ // 1: Invoke GetImageForScale with requested scale and if the source
+ // returns the image with different scale (if the image doesn't exist in
+ // resource, for example), it will fallback to closest image rep.
+ // 2: Invoke GetImageForScale with the closest known scale to the requested
+ // one and rescale the image.
+ // 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);
@@ -139,7 +173,47 @@ class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>,
DCHECK(CalledOnValidThread()) <<
"An ImageSkia with the source must be accessed by the same thread.";
- ImageSkiaRep image = source_->GetImageForScale(scale);
+ ImageSkiaRep image;
+ float resource_scale = scale;
+ if (ImageSkia::IsDSFScalingInImageSkiaEnabled() && 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 (ImageSkia::IsDSFScalingInImageSkiaEnabled() &&
+ scale != resource_scale) {
+ std::vector<ImageSkiaRep>::iterator iter = FindRepresentation(
+ resource_scale, fetch_new_image);
+
+ DCHECK(iter != image_reps_.end());
+
+ if (!iter->unscaled()) {
+ SkBitmap scaled_image;
+ gfx::Size unscaled_size(iter->pixel_width(), iter->pixel_height());
+ gfx::Size scaled_size = ToCeiledSize(
+ gfx::ScaleSize(unscaled_size, scale / iter->scale()));
+
+ image = ImageSkiaRep(skia::ImageOperations::Resize(
+ iter->sk_bitmap(),
+ skia::ImageOperations::RESIZE_LANCZOS3,
+ scaled_size.width(),
+ scaled_size.height()), scale);
+ DCHECK_EQ(image.pixel_width(), scaled_size.width());
+ DCHECK_EQ(image.pixel_height(), scaled_size.height());
+ } else {
+ image = *iter;
+ }
+ } else {
+ image = source_->GetImageForScale(scale);
+ }
// If the source returned the new image, store it.
if (!image.is_null() &&
@@ -240,7 +314,13 @@ float ImageSkia::GetMaxSupportedScale() {
// static
ImageSkia ImageSkia::CreateFrom1xBitmap(const SkBitmap& bitmap) {
- return ImageSkia(ImageSkiaRep(bitmap, 1.0f));
+ return ImageSkia(ImageSkiaRep(bitmap, 0.0f));
+}
+
+bool ImageSkia::IsDSFScalingInImageSkiaEnabled() {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ return !command_line->HasSwitch(
+ switches::kDisableArbitraryScaleFactorInImageSkia);
}
scoped_ptr<ImageSkia> ImageSkia::DeepCopy() const {
@@ -278,7 +358,9 @@ void ImageSkia::AddRepresentation(const ImageSkiaRep& image_rep) {
Init(image_rep);
} else {
CHECK(CanModify());
- storage_->image_reps().push_back(image_rep);
+ // If someone is adding ImageSkia explicitly, check if we should
+ // make the image high DPI aware.
+ storage_->AddRepresentation(image_rep);
}
}
diff --git a/chromium/ui/gfx/image/image_skia.h b/chromium/ui/gfx/image/image_skia.h
index fa5d070ad9b..8765457b432 100644
--- a/chromium/ui/gfx/image/image_skia.h
+++ b/chromium/ui/gfx/image/image_skia.h
@@ -78,6 +78,10 @@ class GFX_EXPORT ImageSkia {
// density display.
static ImageSkia CreateFrom1xBitmap(const SkBitmap& bitmap);
+ // Returns true when ImageSkia looks up the resource pack with the closest
+ // scale factor and rescale the fetched image.
+ static bool IsDSFScalingInImageSkiaEnabled();
+
// Returns a deep copy of this ImageSkia which has its own storage with
// the ImageSkiaRep instances that this ImageSkia currently has.
// This can be safely passed to and manipulated by another thread.
diff --git a/chromium/ui/gfx/image/image_skia_rep.cc b/chromium/ui/gfx/image/image_skia_rep.cc
index f8f3acb1946..f31db600465 100644
--- a/chromium/ui/gfx/image/image_skia_rep.cc
+++ b/chromium/ui/gfx/image/image_skia_rep.cc
@@ -4,9 +4,11 @@
#include "ui/gfx/image/image_skia_rep.h"
+#include "base/logging.h"
+
namespace gfx {
-ImageSkiaRep::ImageSkiaRep() : scale_(1.0f) {
+ImageSkiaRep::ImageSkiaRep() : scale_(0.0f) {
}
ImageSkiaRep::~ImageSkiaRep() {
@@ -14,9 +16,10 @@ ImageSkiaRep::~ImageSkiaRep() {
ImageSkiaRep::ImageSkiaRep(const gfx::Size& size, float scale) : scale_(scale) {
bitmap_.setConfig(SkBitmap::kARGB_8888_Config,
- static_cast<int>(size.width() * scale),
- static_cast<int>(size.height() * scale));
+ static_cast<int>(size.width() * this->scale()),
+ static_cast<int>(size.height() * this->scale()));
bitmap_.allocPixels();
+ bitmap_.eraseColor(SK_ColorRED);
}
ImageSkiaRep::ImageSkiaRep(const SkBitmap& src, float scale)
@@ -25,11 +28,17 @@ ImageSkiaRep::ImageSkiaRep(const SkBitmap& src, float scale)
}
int ImageSkiaRep::GetWidth() const {
- return static_cast<int>(bitmap_.width() / scale_);
+ return static_cast<int>(bitmap_.width() / scale());
}
int ImageSkiaRep::GetHeight() const {
- return static_cast<int>(bitmap_.height() / scale_);
+ return static_cast<int>(bitmap_.height() / scale());
+}
+
+void ImageSkiaRep::SetScaled() {
+ DCHECK_EQ(0.0f, scale_);
+ if (scale_ == 0.0f)
+ scale_ = 1.0f;
}
} // namespace gfx
diff --git a/chromium/ui/gfx/image/image_skia_rep.h b/chromium/ui/gfx/image/image_skia_rep.h
index 7a1e83709ab..47f6713acf5 100644
--- a/chromium/ui/gfx/image/image_skia_rep.h
+++ b/chromium/ui/gfx/image/image_skia_rep.h
@@ -12,14 +12,20 @@
namespace gfx {
// An ImageSkiaRep represents a bitmap and the scale factor it is intended for.
+// 0.0f scale is used to indicate that this ImageSkiaRep is used for unscaled
+// image (the image that only returns 1.0f scale image).
class GFX_EXPORT ImageSkiaRep {
public:
// Create null bitmap.
ImageSkiaRep();
~ImageSkiaRep();
+ // Note: This is for testing purpose only.
// Creates a bitmap with kARGB_8888_Config config with given |size| in DIP.
- // This allocates pixels in the bitmap.
+ // This allocates pixels in the bitmap. It is guaranteed that the data in the
+ // bitmap are initialized but the actual values are undefined.
+ // Specifying 0 scale means the image is for unscaled image. (unscaled()
+ // returns truen, and scale() returns 1.0f;)
ImageSkiaRep(const gfx::Size& size, float scale);
// Creates a bitmap with given scale.
@@ -41,7 +47,12 @@ class GFX_EXPORT ImageSkiaRep {
}
// Retrieves the scale that the bitmap will be painted at.
- float scale() const { return scale_; }
+ float scale() const { return unscaled() ? 1.0f : scale_; }
+
+ bool unscaled() const { return scale_ == 0.0f; }
+
+ // Mark the image to be used as scaled image.
+ void SetScaled();
// Returns backing bitmap.
const SkBitmap& sk_bitmap() const { return bitmap_; }
@@ -51,6 +62,7 @@ class GFX_EXPORT ImageSkiaRep {
SkBitmap& mutable_sk_bitmap() { return bitmap_; }
SkBitmap bitmap_;
+
float scale_;
};
diff --git a/chromium/ui/gfx/image/image_skia_unittest.cc b/chromium/ui/gfx/image/image_skia_unittest.cc
index 0047822122b..e3e93c73b78 100644
--- a/chromium/ui/gfx/image/image_skia_unittest.cc
+++ b/chromium/ui/gfx/image/image_skia_unittest.cc
@@ -4,6 +4,7 @@
#include "ui/gfx/image/image_skia.h"
+#include "base/command_line.h"
#include "base/logging.h"
#include "base/threading/simple_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -11,6 +12,7 @@
#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/size.h"
+#include "ui/gfx/switches.h"
// Duplicated from base/threading/non_thread_safe.h so that we can be
// good citizens there and undef the macro.
@@ -43,17 +45,27 @@ class FixedSource : public ImageSkiaSource {
class DynamicSource : public ImageSkiaSource {
public:
- DynamicSource(const gfx::Size& size) : size_(size) {}
+ DynamicSource(const gfx::Size& size)
+ : size_(size),
+ last_requested_scale_(0.0f) {}
virtual ~DynamicSource() {
}
virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
+ last_requested_scale_ = scale;
return gfx::ImageSkiaRep(size_, scale);
}
+ float GetLastRequestedScaleAndReset() {
+ float result = last_requested_scale_;
+ last_requested_scale_ = 0.0f;
+ return result;
+ }
+
private:
gfx::Size size_;
+ float last_requested_scale_;
DISALLOW_COPY_AND_ASSIGN(DynamicSource);
};
@@ -113,7 +125,28 @@ class TestOnThread : public base::SimpleThread {
} // namespace test
-TEST(ImageSkiaTest, FixedSource) {
+class ImageSkiaTest : public testing::Test {
+ public:
+ ImageSkiaTest() {
+ // In the test, we assume that we support 1.0f and 2.0f DSFs.
+ old_scales_ = ImageSkia::GetSupportedScales();
+
+ // Sets the list of scale factors supported by resource bundle.
+ std::vector<float> supported_scales;
+ supported_scales.push_back(1.0f);
+ supported_scales.push_back(2.0f);
+ ImageSkia::SetSupportedScales(supported_scales);
+ }
+ virtual ~ImageSkiaTest() {
+ ImageSkia::SetSupportedScales(old_scales_);
+ }
+
+ private:
+ std::vector<float> old_scales_;
+ DISALLOW_COPY_AND_ASSIGN(ImageSkiaTest);
+};
+
+TEST_F(ImageSkiaTest, FixedSource) {
ImageSkiaRep image(Size(100, 200), 1.0f);
ImageSkia image_skia(new FixedSource(image), Size(100, 200));
EXPECT_EQ(0U, image_skia.image_reps().size());
@@ -140,7 +173,7 @@ TEST(ImageSkiaTest, FixedSource) {
EXPECT_EQ(1U, image_skia.image_reps().size());
}
-TEST(ImageSkiaTest, DynamicSource) {
+TEST_F(ImageSkiaTest, DynamicSource) {
ImageSkia image_skia(new DynamicSource(Size(100, 200)), Size(100, 200));
EXPECT_EQ(0U, image_skia.image_reps().size());
const ImageSkiaRep& result_100p = image_skia.GetRepresentation(1.0f);
@@ -169,7 +202,7 @@ TEST(ImageSkiaTest, DynamicSource) {
// Tests that image_reps returns all of the representations in the
// image when there are multiple representations for a scale factor.
// This currently is the case with ImageLoader::LoadImages.
-TEST(ImageSkiaTest, ManyRepsPerScaleFactor) {
+TEST_F(ImageSkiaTest, ManyRepsPerScaleFactor) {
const int kSmallIcon1x = 16;
const int kSmallIcon2x = 32;
const int kLargeIcon1x = 32;
@@ -204,14 +237,14 @@ TEST(ImageSkiaTest, ManyRepsPerScaleFactor) {
EXPECT_EQ(1, num_2x);
}
-TEST(ImageSkiaTest, GetBitmap) {
+TEST_F(ImageSkiaTest, GetBitmap) {
ImageSkia image_skia(new DynamicSource(Size(100, 200)), Size(100, 200));
const SkBitmap* bitmap = image_skia.bitmap();
EXPECT_NE(static_cast<SkBitmap*>(NULL), bitmap);
EXPECT_FALSE(bitmap->isNull());
}
-TEST(ImageSkiaTest, GetBitmapFromEmpty) {
+TEST_F(ImageSkiaTest, GetBitmapFromEmpty) {
// Create an image with 1 representation and remove it so the ImageSkiaStorage
// is left with no representations.
ImageSkia empty_image(ImageSkiaRep(Size(100, 200), 1.0f));
@@ -226,7 +259,7 @@ TEST(ImageSkiaTest, GetBitmapFromEmpty) {
EXPECT_TRUE(bitmap->empty());
}
-TEST(ImageSkiaTest, BackedBySameObjectAs) {
+TEST_F(ImageSkiaTest, BackedBySameObjectAs) {
// Null images should all be backed by the same object (NULL).
ImageSkia image;
ImageSkia unrelated;
@@ -245,7 +278,7 @@ TEST(ImageSkiaTest, BackedBySameObjectAs) {
}
#if ENABLE_NON_THREAD_SAFE
-TEST(ImageSkiaTest, EmptyOnThreadTest) {
+TEST_F(ImageSkiaTest, EmptyOnThreadTest) {
ImageSkia empty;
test::TestOnThread empty_on_thread(&empty);
empty_on_thread.Start();
@@ -254,7 +287,7 @@ TEST(ImageSkiaTest, EmptyOnThreadTest) {
EXPECT_TRUE(empty_on_thread.can_modify());
}
-TEST(ImageSkiaTest, StaticOnThreadTest) {
+TEST_F(ImageSkiaTest, StaticOnThreadTest) {
ImageSkia image(ImageSkiaRep(Size(100, 200), 1.0f));
EXPECT_FALSE(image.IsThreadSafe());
@@ -323,7 +356,7 @@ TEST(ImageSkiaTest, StaticOnThreadTest) {
EXPECT_FALSE(image.CanModify());
}
-TEST(ImageSkiaTest, SourceOnThreadTest) {
+TEST_F(ImageSkiaTest, SourceOnThreadTest) {
ImageSkia image(new DynamicSource(Size(100, 200)), Size(100, 200));
EXPECT_FALSE(image.IsThreadSafe());
@@ -375,4 +408,136 @@ TEST(ImageSkiaTest, SourceOnThreadTest) {
// Just in case we ever get lumped together with other compilation units.
#undef ENABLE_NON_THREAD_SAFE
+TEST_F(ImageSkiaTest, Unscaled) {
+ SkBitmap bitmap;
+
+ // An ImageSkia created with 1x bitmap is unscaled.
+ ImageSkia image_skia = ImageSkia::CreateFrom1xBitmap(bitmap);
+ EXPECT_TRUE(image_skia.GetRepresentation(1.0f).unscaled());
+ ImageSkiaRep rep_2x(Size(100, 100), 2.0f);
+
+ // When reps for other scales are added, the unscaled image
+ // becomes scaled.
+ image_skia.AddRepresentation(rep_2x);
+ EXPECT_FALSE(image_skia.GetRepresentation(1.0f).unscaled());
+ EXPECT_FALSE(image_skia.GetRepresentation(2.0f).unscaled());
+}
+
+TEST_F(ImageSkiaTest, ArbitraryScaleFactor) {
+ // Do not test if the ImageSkia doesn't support arbitrary scale factors.
+ if (!ImageSkia::IsDSFScalingInImageSkiaEnabled())
+ return;
+
+ // source is owned by |image|
+ DynamicSource* source = new DynamicSource(Size(100, 200));
+ ImageSkia image(source, gfx::Size(100, 200));
+
+ image.GetRepresentation(1.5f);
+ EXPECT_EQ(2.0f, source->GetLastRequestedScaleAndReset());
+ std::vector<ImageSkiaRep> image_reps = image.image_reps();
+ EXPECT_EQ(2u, image_reps.size());
+
+ std::vector<float> scale_factors;
+ for (size_t i = 0; i < image_reps.size(); ++i) {
+ scale_factors.push_back(image_reps[i].scale());
+ }
+ std::sort(scale_factors.begin(), scale_factors.end());
+ EXPECT_EQ(1.5f, scale_factors[0]);
+ EXPECT_EQ(2.0f, scale_factors[1]);
+
+ // Requesting 1.75 scale factor also falls back to 2.0f and rescale.
+ // However, the image already has the 2.0f data, so it won't fetch again.
+ image.GetRepresentation(1.75f);
+ EXPECT_EQ(0.0f, source->GetLastRequestedScaleAndReset());
+ image_reps = image.image_reps();
+ EXPECT_EQ(3u, image_reps.size());
+
+ scale_factors.clear();
+ for (size_t i = 0; i < image_reps.size(); ++i) {
+ scale_factors.push_back(image_reps[i].scale());
+ }
+ std::sort(scale_factors.begin(), scale_factors.end());
+ EXPECT_EQ(1.5f, scale_factors[0]);
+ EXPECT_EQ(1.75f, scale_factors[1]);
+ EXPECT_EQ(2.0f, scale_factors[2]);
+
+ // 1.25 is falled back to 1.0.
+ image.GetRepresentation(1.25f);
+ EXPECT_EQ(1.0f, source->GetLastRequestedScaleAndReset());
+ image_reps = image.image_reps();
+ EXPECT_EQ(5u, image_reps.size());
+
+ // Scale factor less than 1.0f will be falled back to 1.0f
+ image.GetRepresentation(0.75f);
+ EXPECT_EQ(0.0f, source->GetLastRequestedScaleAndReset());
+ image_reps = image.image_reps();
+ EXPECT_EQ(6u, image_reps.size());
+
+ scale_factors.clear();
+ for (size_t i = 0; i < image_reps.size(); ++i) {
+ scale_factors.push_back(image_reps[i].scale());
+ }
+ std::sort(scale_factors.begin(), scale_factors.end());
+ EXPECT_EQ(0.75f, scale_factors[0]);
+ EXPECT_EQ(1.0f, scale_factors[1]);
+ EXPECT_EQ(1.25f, scale_factors[2]);
+ EXPECT_EQ(1.5f, scale_factors[3]);
+ EXPECT_EQ(1.75f, scale_factors[4]);
+ EXPECT_EQ(2.0f, scale_factors[5]);
+
+ // Scale factor greater than 2.0f is falled back to 2.0f because it's not
+ // supported.
+ image.GetRepresentation(3.0f);
+ EXPECT_EQ(0.0f, source->GetLastRequestedScaleAndReset());
+ image_reps = image.image_reps();
+ EXPECT_EQ(7u, image_reps.size());
+}
+
+TEST_F(ImageSkiaTest, ArbitraryScaleFactorWithMissingResource) {
+ // Do not test if the ImageSkia doesn't support arbitrary scale factors.
+ if (!ImageSkia::IsDSFScalingInImageSkiaEnabled())
+ return;
+
+ ImageSkia image(new FixedSource(
+ ImageSkiaRep(Size(100, 200), 1.0f)), Size(100, 200));
+
+ // Requesting 1.5f -- falls back to 2.0f, but couldn't find. It should
+ // look up 1.0f and then rescale it.
+ const ImageSkiaRep& rep = image.GetRepresentation(1.5f);
+ EXPECT_EQ(1.5f, rep.scale());
+ EXPECT_EQ(2U, image.image_reps().size());
+ EXPECT_EQ(1.0f, image.image_reps()[0].scale());
+ EXPECT_EQ(1.5f, image.image_reps()[1].scale());
+}
+
+TEST_F(ImageSkiaTest, UnscaledImageForArbitraryScaleFactor) {
+ // Do not test if the ImageSkia doesn't support arbitrary scale factors.
+ if (!ImageSkia::IsDSFScalingInImageSkiaEnabled())
+ return;
+
+ // 0.0f means unscaled.
+ ImageSkia image(new FixedSource(
+ ImageSkiaRep(Size(100, 200), 0.0f)), Size(100, 200));
+
+ // Requesting 2.0f, which should return 1.0f unscaled image.
+ const ImageSkiaRep& rep = image.GetRepresentation(2.0f);
+ EXPECT_EQ(1.0f, rep.scale());
+ EXPECT_EQ("100x200", rep.pixel_size().ToString());
+ EXPECT_TRUE(rep.unscaled());
+ EXPECT_EQ(1U, image.image_reps().size());
+
+ // Same for any other scale factors.
+ const ImageSkiaRep& rep15 = image.GetRepresentation(1.5f);
+ EXPECT_EQ(1.0f, rep15.scale());
+ EXPECT_EQ("100x200", rep15.pixel_size().ToString());
+ EXPECT_TRUE(rep15.unscaled());
+ EXPECT_EQ(1U, image.image_reps().size());
+
+ const ImageSkiaRep& rep12 = image.GetRepresentation(1.2f);
+ EXPECT_EQ(1.0f, rep12.scale());
+ EXPECT_EQ("100x200", rep12.pixel_size().ToString());
+ EXPECT_TRUE(rep12.unscaled());
+ EXPECT_EQ(1U, image.image_reps().size());
+}
+
} // namespace gfx
diff --git a/chromium/ui/gfx/image/image_skia_util_mac.h b/chromium/ui/gfx/image/image_skia_util_mac.h
index 553c3f8741d..fc6a65fb027 100644
--- a/chromium/ui/gfx/image/image_skia_util_mac.h
+++ b/chromium/ui/gfx/image/image_skia_util_mac.h
@@ -31,10 +31,6 @@ GFX_EXPORT gfx::ImageSkia ImageSkiaFromNSImage(NSImage* image);
GFX_EXPORT gfx::ImageSkia ImageSkiaFromResizedNSImage(NSImage* image,
NSSize size);
-// Resizes |[NSImage imageNamed:@NSApplicationIcon]| to have edge width of
-// |size| DIP and returns result as ImageSkia.
-GFX_EXPORT gfx::ImageSkia ApplicationIconAtSize(int size);
-
// Converts to NSImage from ImageSkia.
GFX_EXPORT NSImage* NSImageFromImageSkia(const gfx::ImageSkia& image_skia);
diff --git a/chromium/ui/gfx/image/image_skia_util_mac.mm b/chromium/ui/gfx/image/image_skia_util_mac.mm
index 281badc7423..26c067331a7 100644
--- a/chromium/ui/gfx/image/image_skia_util_mac.mm
+++ b/chromium/ui/gfx/image/image_skia_util_mac.mm
@@ -78,12 +78,6 @@ gfx::ImageSkia ImageSkiaFromResizedNSImage(NSImage* image,
return image_skia;
}
-gfx::ImageSkia ApplicationIconAtSize(int desired_size) {
- NSImage* image = [NSImage imageNamed:@"NSApplicationIcon"];
- return ImageSkiaFromResizedNSImage(image,
- NSMakeSize(desired_size, desired_size));
-}
-
NSImage* NSImageFromImageSkia(const gfx::ImageSkia& image_skia) {
if (image_skia.isNull())
return nil;
diff --git a/chromium/ui/gfx/image/image_unittest.cc b/chromium/ui/gfx/image/image_unittest.cc
index 039cb13f606..ca9efa0003c 100644
--- a/chromium/ui/gfx/image/image_unittest.cc
+++ b/chromium/ui/gfx/image/image_unittest.cc
@@ -10,10 +10,7 @@
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_unittest_util.h"
-#if defined(TOOLKIT_GTK)
-#include <gtk/gtk.h>
-#include "ui/gfx/gtk_util.h"
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
#include "base/mac/foundation_util.h"
#include "skia/ext/skia_utils_ios.h"
#elif defined(OS_MACOSX)
@@ -75,7 +72,7 @@ TEST_F(ImageTest, EmptyImage) {
// Test constructing a gfx::Image from an empty PlatformImage.
TEST_F(ImageTest, EmptyImageFromEmptyPlatformImage) {
-#if defined(OS_IOS) || defined(OS_MACOSX) || defined(TOOLKIT_GTK)
+#if defined(OS_IOS) || defined(OS_MACOSX)
gfx::Image image1(NULL);
EXPECT_TRUE(image1.IsEmpty());
EXPECT_EQ(0, image1.Width());
@@ -246,12 +243,24 @@ TEST_F(ImageTest, MultiResolutionPNGToImageSkia) {
scales.push_back(1.0f);
scales.push_back(2.0f);
gfx::ImageSkia image_skia = image.AsImageSkia();
- EXPECT_TRUE(gt::ImageSkiaStructureMatches(image_skia, kSize1x, kSize1x,
- scales));
EXPECT_TRUE(gt::IsEqual(bytes1x,
image_skia.GetRepresentation(1.0f).sk_bitmap()));
EXPECT_TRUE(gt::IsEqual(bytes2x,
image_skia.GetRepresentation(2.0f).sk_bitmap()));
+ EXPECT_TRUE(gt::ImageSkiaStructureMatches(image_skia, kSize1x, kSize1x,
+ scales));
+#if !defined(OS_IOS)
+ // IOS does not support arbitrary scale factors.
+ gfx::ImageSkiaRep rep_1_6x = image_skia.GetRepresentation(1.6f);
+ ASSERT_FALSE(rep_1_6x.is_null());
+ ASSERT_EQ(1.6f, rep_1_6x.scale());
+ EXPECT_EQ("40x40", rep_1_6x.pixel_size().ToString());
+
+ gfx::ImageSkiaRep rep_0_8x = image_skia.GetRepresentation(0.8f);
+ ASSERT_FALSE(rep_0_8x.is_null());
+ ASSERT_EQ(0.8f, rep_0_8x.scale());
+ EXPECT_EQ("20x20", rep_0_8x.pixel_size().ToString());
+#endif
}
TEST_F(ImageTest, MultiResolutionPNGToPlatform) {
@@ -436,27 +445,6 @@ TEST_F(ImageTest, PlatformToSkiaToCopy) {
delete bitmap;
}
-#if defined(TOOLKIT_GTK)
-TEST_F(ImageTest, SkiaToGdkCopy) {
- GdkPixbuf* pixbuf;
-
- {
- gfx::Image image(gt::CreateImageSkia(25, 25));
- pixbuf = image.CopyGdkPixbuf();
- }
-
- EXPECT_TRUE(pixbuf);
- g_object_unref(pixbuf);
-}
-
-TEST_F(ImageTest, SkiaToCairoCreatesGdk) {
- gfx::Image image(gt::CreateImageSkia(25, 25));
- EXPECT_FALSE(image.HasRepresentation(gfx::Image::kImageRepGdk));
- EXPECT_TRUE(image.ToCairo());
- EXPECT_TRUE(image.HasRepresentation(gfx::Image::kImageRepGdk));
-}
-#endif
-
#if defined(OS_IOS)
TEST_F(ImageTest, SkiaToCocoaTouchCopy) {
UIImage* ui_image;
@@ -495,9 +483,8 @@ TEST_F(ImageTest, SkBitmapConversionPreservesOrientation) {
const int width = 50;
const int height = 50;
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
- bitmap.allocPixels();
- bitmap.eraseRGB(0, 255, 0);
+ bitmap.allocN32Pixels(width, height);
+ bitmap.eraseARGB(255, 0, 255, 0);
// Paint the upper half of the image in red (lower half is in green).
SkCanvas canvas(bitmap);
@@ -538,9 +525,7 @@ TEST_F(ImageTest, SkBitmapConversionPreservesTransparency) {
const int width = 50;
const int height = 50;
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0,
- kPremul_SkAlphaType);
- bitmap.allocPixels();
+ bitmap.allocN32Pixels(width, height);
bitmap.eraseARGB(0, 0, 255, 0);
// Paint the upper half of the image in red (lower half is transparent).
diff --git a/chromium/ui/gfx/image/image_unittest_util.cc b/chromium/ui/gfx/image/image_unittest_util.cc
index 4baf30a4cc6..e9a003216d9 100644
--- a/chromium/ui/gfx/image/image_unittest_util.cc
+++ b/chromium/ui/gfx/image/image_unittest_util.cc
@@ -15,10 +15,7 @@
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image_skia.h"
-#if defined(TOOLKIT_GTK)
-#include <gtk/gtk.h>
-#include "ui/gfx/gtk_util.h"
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "skia/ext/skia_utils_ios.h"
@@ -59,7 +56,7 @@ const SkBitmap CreateBitmap(int width, int height) {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
bitmap.allocPixels();
- bitmap.eraseRGB(0, 255, 0);
+ bitmap.eraseARGB(255, 0, 255, 0);
return bitmap;
}
@@ -83,6 +80,8 @@ gfx::Image CreateImage(int width, int height) {
}
bool IsEqual(const gfx::Image& img1, const gfx::Image& img2) {
+ img1.AsImageSkia().EnsureRepsForSupportedScales();
+ img2.AsImageSkia().EnsureRepsForSupportedScales();
std::vector<gfx::ImageSkiaRep> img1_reps = img1.AsImageSkia().image_reps();
gfx::ImageSkia image_skia2 = img2.AsImageSkia();
if (image_skia2.image_reps().size() != img1_reps.size())
@@ -192,8 +191,6 @@ PlatformImage CreatePlatformImage() {
NSImage* image = gfx::SkBitmapToNSImage(bitmap);
base::mac::NSObjectRetain(image);
return image;
-#elif defined(TOOLKIT_GTK)
- return gfx::GdkPixbufFromSkBitmap(bitmap);
#else
return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
#endif
@@ -204,8 +201,6 @@ gfx::Image::RepresentationType GetPlatformRepresentationType() {
return gfx::Image::kImageRepCocoaTouch;
#elif defined(OS_MACOSX)
return gfx::Image::kImageRepCocoa;
-#elif defined(TOOLKIT_GTK)
- return gfx::Image::kImageRepGdk;
#else
return gfx::Image::kImageRepSkia;
#endif
@@ -216,8 +211,6 @@ PlatformImage ToPlatformType(const gfx::Image& image) {
return image.ToUIImage();
#elif defined(OS_MACOSX)
return image.ToNSImage();
-#elif defined(TOOLKIT_GTK)
- return image.ToGdkPixbuf();
#else
return image.AsImageSkia();
#endif
@@ -228,8 +221,6 @@ PlatformImage CopyPlatformType(const gfx::Image& image) {
return image.CopyUIImage();
#elif defined(OS_MACOSX)
return image.CopyNSImage();
-#elif defined(TOOLKIT_GTK)
- return image.CopyGdkPixbuf();
#else
return image.AsImageSkia();
#endif
@@ -237,16 +228,6 @@ PlatformImage CopyPlatformType(const gfx::Image& image) {
#if defined(OS_MACOSX)
// Defined in image_unittest_util_mac.mm.
-#elif defined(TOOLKIT_GTK)
-SkColor GetPlatformImageColor(PlatformImage image, int x, int y) {
- int n_channels = gdk_pixbuf_get_n_channels(image);
- int rowstride = gdk_pixbuf_get_rowstride(image);
- guchar* gdk_pixels = gdk_pixbuf_get_pixels(image);
-
- guchar* pixel = gdk_pixels + (y * rowstride) + (x * n_channels);
- guchar alpha = gdk_pixbuf_get_has_alpha(image) ? pixel[3] : 255;
- return SkColorSetARGB(alpha, pixel[0], pixel[1], pixel[2]);
-}
#else
SkColor GetPlatformImageColor(PlatformImage image, int x, int y) {
SkBitmap bitmap = *image.bitmap();
@@ -264,7 +245,7 @@ void CheckIsTransparent(SkColor color) {
}
bool IsPlatformImageValid(PlatformImage image) {
-#if defined(OS_MACOSX) || defined(TOOLKIT_GTK)
+#if defined(OS_MACOSX)
return image != NULL;
#else
return !image.isNull();
@@ -272,7 +253,7 @@ bool IsPlatformImageValid(PlatformImage image) {
}
bool PlatformImagesEqual(PlatformImage image1, PlatformImage image2) {
-#if defined(OS_MACOSX) || defined(TOOLKIT_GTK)
+#if defined(OS_MACOSX)
return image1 == image2;
#else
return image1.BackedBySameObjectAs(image2);
diff --git a/chromium/ui/gfx/image/image_unittest_util.h b/chromium/ui/gfx/image/image_unittest_util.h
index 4788e4e1009..cac8015eb16 100644
--- a/chromium/ui/gfx/image/image_unittest_util.h
+++ b/chromium/ui/gfx/image/image_unittest_util.h
@@ -18,8 +18,6 @@ namespace test {
typedef UIImage* PlatformImage;
#elif defined(OS_MACOSX)
typedef NSImage* PlatformImage;
-#elif defined(TOOLKIT_GTK)
-typedef GdkPixbuf* PlatformImage;
#else
typedef gfx::ImageSkia PlatformImage;
#endif
diff --git a/chromium/ui/gfx/image/image_util.cc b/chromium/ui/gfx/image/image_util.cc
index 59d631d171d..89a3f8c03b8 100644
--- a/chromium/ui/gfx/image/image_util.cc
+++ b/chromium/ui/gfx/image/image_util.cc
@@ -12,6 +12,8 @@
namespace gfx {
+const uint32_t kMinimumVisibleOpacity = 12;
+
// The iOS implementations of the JPEG functions are in image_util_ios.mm.
#if !defined(OS_IOS)
Image ImageFrom1xJPEGEncodedData(const unsigned char* input,
@@ -24,7 +26,7 @@ Image ImageFrom1xJPEGEncodedData(const unsigned char* input,
}
bool JPEG1xEncodedDataFromImage(const Image& image, int quality,
- std::vector<unsigned char>* dst) {
+ std::vector<unsigned char>* dst) {
const gfx::ImageSkiaRep& image_skia_rep =
image.AsImageSkia().GetRepresentation(1.0f);
if (image_skia_rep.scale() != 1.0f)
@@ -45,4 +47,57 @@ bool JPEG1xEncodedDataFromImage(const Image& image, int quality,
}
#endif // !defined(OS_IOS)
+bool VisibleMargins(const ImageSkia& image, int* leading, int* trailing) {
+ *leading = 0;
+ *trailing = std::max(1, image.width()) - 1;
+ if (!image.HasRepresentation(1.0))
+ return false;
+
+ const ImageSkiaRep& rep = image.GetRepresentation(1.0);
+ if (rep.is_null())
+ return false;
+
+ const SkBitmap& bitmap = rep.sk_bitmap();
+ if (bitmap.isNull() || bitmap.width() == 0)
+ return false;
+
+ if (bitmap.isOpaque())
+ return true;
+
+ SkAutoLockPixels l(bitmap);
+ int inner_min = bitmap.width();
+ for (int x = 0; x < bitmap.width(); ++x) {
+ for (int y = 0; y < bitmap.height(); ++y) {
+ if (SkColorGetA(bitmap.getColor(x, y)) > kMinimumVisibleOpacity) {
+ inner_min = x;
+ break;
+ }
+ }
+ if (inner_min < bitmap.width())
+ break;
+ }
+
+ int inner_max = -1;
+ for (int x = bitmap.width() - 1; x > inner_min; --x) {
+ for (int y = 0; y < bitmap.height(); ++y) {
+ if (SkColorGetA(bitmap.getColor(x, y)) > kMinimumVisibleOpacity) {
+ inner_max = x;
+ break;
+ }
+ }
+ if (inner_max > -1)
+ break;
+ }
+
+ if (inner_min == bitmap.width()) {
+ *leading = bitmap.width()/2;
+ *trailing = bitmap.width()/2 + 1;
+ return true;
+ }
+
+ *leading = inner_min;
+ *trailing = inner_max;
+ return true;
}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/image/image_util.h b/chromium/ui/gfx/image/image_util.h
index f33835ca232..2711850dc96 100644
--- a/chromium/ui/gfx/image/image_util.h
+++ b/chromium/ui/gfx/image/image_util.h
@@ -12,6 +12,7 @@
namespace gfx {
class Image;
+class ImageSkia;
}
namespace gfx {
@@ -31,6 +32,22 @@ GFX_EXPORT bool JPEG1xEncodedDataFromImage(const Image& image,
int quality,
std::vector<unsigned char>* dst);
+// Returns the visible (non-transparent) width of the 1x rep of the given
+// image. If the image has no transparency, the leading value will be 0 and
+// the trailing will be the image width. Return values are in the 1x width
+// pixel units. Margins are given in 0-based column format. So if the image
+// has only transparent pixels in columns 0, 1, 2, 3, then the leading value
+// will be 4. Similarly, if there are all transparent pixels in column
+// width-2, width-1, then the trailing margin value will be width-3.
+// Returns true if the value is computed from opacity, false if it is a
+// default value because of null image, missing Rep, etc.
+// This method is only suitable for fairly small images (i.e. 16x16).
+// The margins for a completely transparent image will be w/2-1, w/2, but this
+// will be an expensive operation: it isn't expected that it will be frequently
+// calculated.
+GFX_EXPORT bool VisibleMargins(const ImageSkia& image,
+ int* leading, int* trailing);
+
} // namespace gfx
#endif // UI_GFX_IMAGE_IMAGE_UTIL_H_
diff --git a/chromium/ui/gfx/image/image_util_unittest.cc b/chromium/ui/gfx/image/image_util_unittest.cc
index cd9d74898f6..74c39e68fa4 100644
--- a/chromium/ui/gfx/image/image_util_unittest.cc
+++ b/chromium/ui/gfx/image/image_util_unittest.cc
@@ -9,6 +9,8 @@
#include "base/memory/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkRect.h"
+#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_unittest_util.h"
TEST(ImageUtilTest, JPEGEncodeAndDecode) {
@@ -23,3 +25,79 @@ TEST(ImageUtilTest, JPEGEncodeAndDecode) {
// JPEG is lossy, so simply check that the image decoded successfully.
EXPECT_FALSE(decoded.IsEmpty());
}
+
+TEST(ImageUtilTest, TestVisibleMargins) {
+ // Image with non-transparent piece should return margins at those
+ // columns.
+ SkBitmap bitmap1;
+ bitmap1.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ bitmap1.allocPixels();
+ bitmap1.eraseColor(SK_ColorTRANSPARENT);
+ bitmap1.eraseArea(SkIRect::MakeLTRB(3, 3, 14, 14), SK_ColorYELLOW);
+ gfx::ImageSkia img = gfx::ImageSkia::CreateFrom1xBitmap(bitmap1);
+ int x = 0;
+ int y = 0;
+ gfx::VisibleMargins(img, &x, &y);
+ EXPECT_EQ(3, x);
+ EXPECT_EQ(13, y);
+ EXPECT_EQ(16, img.width());
+
+ // Full-width-transparent image should return margins in the center
+ // of the image.
+ SkBitmap bitmap2;
+ bitmap2.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ bitmap2.allocPixels();
+ bitmap2.eraseColor(SK_ColorTRANSPARENT);
+ gfx::ImageSkia img_transparent = gfx::ImageSkia::CreateFrom1xBitmap(bitmap2);
+ x = 0;
+ y = 0;
+ gfx::VisibleMargins(img_transparent, &x, &y);
+ EXPECT_EQ(8, x);
+ EXPECT_EQ(9, y);
+ EXPECT_EQ(16, img_transparent.width());
+
+ // Image with non-transparent piece that is skewed to one side should
+ // return margins at those columns.
+ SkBitmap bitmap3;
+ bitmap3.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ bitmap3.allocPixels();
+ bitmap3.eraseColor(SK_ColorTRANSPARENT);
+ bitmap3.eraseArea(SkIRect::MakeLTRB(3, 3, 5, 5), SK_ColorYELLOW);
+ gfx::ImageSkia img3 = gfx::ImageSkia::CreateFrom1xBitmap(bitmap3);
+ x = 0;
+ y = 0;
+ gfx::VisibleMargins(img3, &x, &y);
+ EXPECT_EQ(3, x);
+ EXPECT_EQ(4, y);
+ EXPECT_EQ(16, img3.width());
+
+ // Image with non-transparent piece that is at one edge should
+ // return margins at those columns.
+ SkBitmap bitmap4;
+ bitmap4.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ bitmap4.allocPixels();
+ bitmap4.eraseColor(SK_ColorTRANSPARENT);
+ bitmap4.eraseArea(SkIRect::MakeLTRB(0, 3, 5, 5), SK_ColorYELLOW);
+ gfx::ImageSkia img4 = gfx::ImageSkia::CreateFrom1xBitmap(bitmap4);
+ x = 0;
+ y = 0;
+ gfx::VisibleMargins(img4, &x, &y);
+ EXPECT_EQ(0, x);
+ EXPECT_EQ(4, y);
+ EXPECT_EQ(16, img4.width());
+
+ // Image with non-transparent piece that is at trailing edge should
+ // return margins at those columns.
+ SkBitmap bitmap5;
+ bitmap5.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ bitmap5.allocPixels();
+ bitmap5.eraseColor(SK_ColorTRANSPARENT);
+ bitmap5.eraseArea(SkIRect::MakeLTRB(4, 3, 16, 16), SK_ColorYELLOW);
+ gfx::ImageSkia img5 = gfx::ImageSkia::CreateFrom1xBitmap(bitmap5);
+ x = 0;
+ y = 0;
+ gfx::VisibleMargins(img5, &x, &y);
+ EXPECT_EQ(4, x);
+ EXPECT_EQ(15, y);
+ EXPECT_EQ(16, img5.width());
+}