diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/base/resource/resource_bundle.cc | 22 | ||||
-rw-r--r-- | ui/gfx/canvas.cc | 107 | ||||
-rw-r--r-- | ui/gfx/canvas.h | 56 | ||||
-rw-r--r-- | ui/gfx/image/image.cc | 35 | ||||
-rw-r--r-- | ui/gfx/image/image.h | 8 | ||||
-rw-r--r-- | ui/gfx/image/image_mac.mm | 37 | ||||
-rw-r--r-- | ui/gfx/image/image_mac_unittest.mm | 96 | ||||
-rw-r--r-- | ui/gfx/image/image_skia.cc | 255 | ||||
-rw-r--r-- | ui/gfx/image/image_skia.h | 155 | ||||
-rw-r--r-- | ui/gfx/image/image_unittest.cc | 66 |
10 files changed, 322 insertions, 515 deletions
diff --git a/ui/base/resource/resource_bundle.cc b/ui/base/resource/resource_bundle.cc index f84e8db..bb011ab 100644 --- a/ui/base/resource/resource_bundle.cc +++ b/ui/base/resource/resource_bundle.cc @@ -24,7 +24,6 @@ #include "ui/base/ui_base_switches.h" #include "ui/gfx/codec/jpeg_codec.h" #include "ui/gfx/codec/png_codec.h" -#include "ui/gfx/image/image_skia.h" namespace ui { @@ -232,26 +231,25 @@ gfx::Image& ResourceBundle::GetImageNamed(int resource_id) { if (image.IsEmpty()) { DCHECK(!delegate_ && !data_packs_.empty()) << "Missing call to SetResourcesDataDLL?"; - gfx::ImageSkia image_skia; + ScopedVector<const SkBitmap> bitmaps; for (size_t i = 0; i < data_packs_.size(); ++i) { - scoped_ptr<SkBitmap> bitmap(LoadBitmap(*data_packs_[i], resource_id)); - if (bitmap.get()) { -#if defined(ENABLE_DIP) - image_skia.AddBitmapForScale(*bitmap, data_packs_[i]->GetScaleFactor()); -#else - image_skia.AddBitmapForScale(*bitmap, 1.0f); -#endif - } + SkBitmap* bitmap = LoadBitmap(*data_packs_[i], resource_id); + if (bitmap) + bitmaps.push_back(bitmap); } - if (image_skia.empty()) { + if (bitmaps.empty()) { LOG(WARNING) << "Unable to load image with id " << resource_id; NOTREACHED(); // Want to assert in debug mode. // The load failed to retrieve the image; show a debugging red square. return GetEmptyImage(); } - image = gfx::Image(image_skia); + std::vector<const SkBitmap*> tmp_bitmaps; + bitmaps.release(&tmp_bitmaps); + + // Takes ownership of bitmaps. + image = gfx::Image(tmp_bitmaps); } // The load was successful, so cache the image. diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc index aeabc12..288d192 100644 --- a/ui/gfx/canvas.cc +++ b/ui/gfx/canvas.cc @@ -254,42 +254,42 @@ void Canvas::DrawFocusRect(const gfx::Rect& rect) { DrawDashedRect(rect, SK_ColorGRAY); } -void Canvas::DrawBitmapInt(const gfx::ImageSkia& image, int x, int y) { - SkPaint paint; - DrawBitmapInt(image, x, y, paint); +void Canvas::DrawBitmapInt(const SkBitmap& bitmap, int x, int y) { + canvas_->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y)); } -void Canvas::DrawBitmapInt(const gfx::ImageSkia& image, +void Canvas::DrawBitmapInt(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) { - float bitmap_scale; - const SkBitmap& bitmap = GetBitmapToPaint(image, &bitmap_scale); - if (bitmap.isNull()) - return; - - canvas_->save(); - canvas_->scale(SkFloatToScalar(1.0f / bitmap_scale), - SkFloatToScalar(1.0f / bitmap_scale)); - canvas_->drawBitmap(bitmap, - SkFloatToScalar(x * bitmap_scale), - SkFloatToScalar(y * bitmap_scale)); - canvas_->restore(); + canvas_->drawBitmap(bitmap, SkIntToScalar(x), SkIntToScalar(y), &paint); } -void Canvas::DrawBitmapInt(const gfx::ImageSkia& image, +void Canvas::DrawBitmapInt(const SkBitmap& bitmap, int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, int dest_w, int dest_h, bool filter) { SkPaint p; - DrawBitmapInt(image, src_x, src_y, src_w, src_h, dest_x, dest_y, + DrawBitmapInt(bitmap, src_x, src_y, src_w, src_h, dest_x, dest_y, dest_w, dest_h, filter, p); } -void Canvas::DrawBitmapInt(const gfx::ImageSkia& image, +void Canvas::DrawBitmapInt(const SkBitmap& bitmap, int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, int dest_w, int dest_h, bool filter, const SkPaint& paint) { + DrawBitmapFloat(bitmap, static_cast<float>(src_x), static_cast<float>(src_y), + static_cast<float>(src_w), static_cast<float>(src_h), + static_cast<float>(dest_x), static_cast<float>(dest_y), + static_cast<float>(dest_w), static_cast<float>(dest_h), + filter, paint); +} + +void Canvas::DrawBitmapFloat(const SkBitmap& bitmap, + float src_x, float src_y, float src_w, float src_h, + float dest_x, float dest_y, float dest_w, float dest_h, + bool filter, + const SkPaint& paint) { DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() && src_y + src_h < std::numeric_limits<int16_t>::max()); if (src_w <= 0 || src_h <= 0) { @@ -300,22 +300,12 @@ void Canvas::DrawBitmapInt(const gfx::ImageSkia& image, if (!IntersectsClipRectInt(dest_x, dest_y, dest_w, dest_h)) return; - float user_scale_x = static_cast<float>(dest_w) / src_w; - float user_scale_y = static_cast<float>(dest_h) / src_h; + SkRect dest_rect = { SkFloatToScalar(dest_x), + SkFloatToScalar(dest_y), + SkFloatToScalar(dest_x + dest_w), + SkFloatToScalar(dest_y + dest_h) }; - float bitmap_scale; - const SkBitmap& bitmap = GetBitmapToPaint(image, user_scale_x, user_scale_y, - &bitmap_scale); - if (bitmap.isNull()) - return; - - SkRect dest_rect = { SkIntToScalar(dest_x), - SkIntToScalar(dest_y), - SkIntToScalar(dest_x + dest_w), - SkIntToScalar(dest_y + dest_h) }; - - if (src_w == dest_w && src_h == dest_h && - bitmap_scale == 1.0f && bitmap_scale == 1.0f) { + if (src_w == dest_w && src_h == dest_h) { // Workaround for apparent bug in Skia that causes image to occasionally // shift. SkIRect src_rect = { src_x, src_y, src_x + src_w, src_y + src_h }; @@ -331,13 +321,10 @@ void Canvas::DrawBitmapInt(const gfx::ImageSkia& image, SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode); SkMatrix shader_scale; - shader_scale.setScale(SkFloatToScalar(user_scale_x), - SkFloatToScalar(user_scale_y)); - shader_scale.preTranslate(SkFloatToScalar(-src_x * bitmap_scale), - SkFloatToScalar(-src_y * bitmap_scale)); - shader_scale.postTranslate(SkFloatToScalar(dest_x * bitmap_scale), - SkFloatToScalar(dest_y * bitmap_scale)); - shader_scale.postScale(1.0f / bitmap_scale, 1.0f / bitmap_scale); + shader_scale.setScale(SkFloatToScalar(dest_w / src_w), + SkFloatToScalar(dest_h / src_h)); + shader_scale.preTranslate(SkFloatToScalar(-src_x), SkFloatToScalar(-src_y)); + shader_scale.postTranslate(SkFloatToScalar(dest_x), SkFloatToScalar(dest_y)); shader->setLocalMatrix(shader_scale); // Set up our paint to use the shader & release our reference (now just owned @@ -379,22 +366,17 @@ void Canvas::DrawStringInt(const string16& text, std::vector<ShadowValue>()); } -void Canvas::TileImageInt(const gfx::ImageSkia& image, +void Canvas::TileImageInt(const SkBitmap& bitmap, int x, int y, int w, int h) { - TileImageInt(image, 0, 0, x, y, w, h); + TileImageInt(bitmap, 0, 0, x, y, w, h); } -void Canvas::TileImageInt(const gfx::ImageSkia& image, +void Canvas::TileImageInt(const SkBitmap& bitmap, int src_x, int src_y, int dest_x, int dest_y, int w, int h) { if (!IntersectsClipRectInt(dest_x, dest_y, w, h)) return; - float bitmap_scale; - const SkBitmap& bitmap = GetBitmapToPaint(image, &bitmap_scale); - if (bitmap.isNull()) - return; - SkPaint paint; SkShader* shader = SkShader::CreateBitmapShader(bitmap, @@ -410,8 +392,6 @@ void Canvas::TileImageInt(const gfx::ImageSkia& image, canvas_->translate(SkIntToScalar(dest_x - src_x), SkIntToScalar(dest_y - src_y)); ClipRect(gfx::Rect(src_x, src_y, w, h)); - canvas_->scale(SkFloatToScalar(1.0f / bitmap_scale), - SkFloatToScalar(1.0f / bitmap_scale)); canvas_->drawPaint(paint); canvas_->restore(); } @@ -440,29 +420,4 @@ bool Canvas::IntersectsClipRect(const gfx::Rect& rect) { rect.width(), rect.height()); } - -const SkBitmap& Canvas::GetBitmapToPaint(const gfx::ImageSkia& image, - float* bitmap_scale_factor) const { - return GetBitmapToPaint(image, 1.0f, 1.0f, bitmap_scale_factor); -} - -const SkBitmap& Canvas::GetBitmapToPaint(const gfx::ImageSkia& image, - float user_additional_scale_x, - float user_additional_scale_y, - float* bitmap_scale_factor) const { - SkMatrix m = canvas_->getTotalMatrix(); - float scale_x = SkScalarToFloat(SkScalarAbs(m.getScaleX())) * - user_additional_scale_x; - float scale_y = SkScalarToFloat(SkScalarAbs(m.getScaleY())) * - user_additional_scale_y; - - const SkBitmap& bitmap = image.GetBitmapForScale(scale_x, scale_y, - bitmap_scale_factor); - if (!bitmap.isNull() && - (scale_x < *bitmap_scale_factor || scale_y < *bitmap_scale_factor)) - const_cast<SkBitmap&>(bitmap).buildMipMap(); - - return bitmap; -} - } // namespace gfx diff --git a/ui/gfx/canvas.h b/ui/gfx/canvas.h index 69f402b..7653f39 100644 --- a/ui/gfx/canvas.h +++ b/ui/gfx/canvas.h @@ -12,7 +12,6 @@ #include "base/memory/scoped_ptr.h" #include "base/string16.h" #include "skia/ext/platform_canvas.h" -#include "ui/gfx/image/image_skia.h" #include "ui/gfx/native_widget_types.h" class SkBitmap; @@ -241,43 +240,47 @@ class UI_EXPORT Canvas { // Draws the given path using the given |paint| parameters. void DrawPath(const SkPath& path, const SkPaint& paint); - // Draws an image with the origin at the specified location. The upper left + // Draws a bitmap with the origin at the specified location. The upper left // corner of the bitmap is rendered at the specified location. - // Parameters are specified relative to current canvas scale not in pixels. - // Thus, |x| is 2 pixels if canvas scale = 2 & |x| = 1. - void DrawBitmapInt(const gfx::ImageSkia&, int x, int y); + void DrawBitmapInt(const SkBitmap& bitmap, int x, int y); - // Draws an image with the origin at the specified location, using the + // Draws a bitmap with the origin at the specified location, using the // specified paint. The upper left corner of the bitmap is rendered at the // specified location. - // Parameters are specified relative to current canvas scale not in pixels. - // Thus, |x| is 2 pixels if canvas scale = 2 & |x| = 1. - void DrawBitmapInt(const gfx::ImageSkia& image, + void DrawBitmapInt(const SkBitmap& bitmap, int x, int y, const SkPaint& paint); - // Draws a portion of an image in the specified location. The src parameters + // Draws a portion of a bitmap in the specified location. The src parameters // correspond to the region of the bitmap to draw in the region defined // by the dest coordinates. // // If the width or height of the source differs from that of the destination, - // the image will be scaled. When scaling down, a mipmap will be generated. - // Set |filter| to use filtering for images, otherwise the nearest-neighbor - // algorithm is used for resampling. + // the bitmap will be scaled. When scaling down, it is highly recommended + // that you call buildMipMap(false) on your bitmap to ensure that it has + // a mipmap, which will result in much higher-quality output. Set |filter| + // to use filtering for bitmaps, otherwise the nearest-neighbor algorithm + // is used for resampling. // // An optional custom SkPaint can be provided. - // Parameters are specified relative to current canvas scale not in pixels. - // Thus, |x| is 2 pixels if canvas scale = 2 & |x| = 1. - void DrawBitmapInt(const gfx::ImageSkia& image, + void DrawBitmapInt(const SkBitmap& bitmap, int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, int dest_w, int dest_h, bool filter); - void DrawBitmapInt(const gfx::ImageSkia& image, + void DrawBitmapInt(const SkBitmap& bitmap, int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, int dest_w, int dest_h, bool filter, const SkPaint& paint); + // TODO(pkotwicz): make this function private once gfx::ImageSkia stops + // calling this method. + void DrawBitmapFloat(const SkBitmap& bitmap, + float src_x, float src_y, float src_w, float src_h, + float dest_x, float dest_y, float dest_w, float dest_h, + bool filter, + const SkPaint& paint); + // Draws text with the specified color, font and location. The text is // aligned to the left, vertically centered, clipped to the region. If the // text is too big, it is truncated and '...' is added to the end. @@ -312,11 +315,9 @@ class UI_EXPORT Canvas { void DrawFocusRect(const gfx::Rect& rect); // Tiles the image in the specified region. - // Parameters are specified relative to current canvas scale not in pixels. - // Thus, |x| is 2 pixels if canvas scale = 2 & |x| = 1. - void TileImageInt(const gfx::ImageSkia& image, + void TileImageInt(const SkBitmap& bitmap, int x, int y, int w, int h); - void TileImageInt(const gfx::ImageSkia& image, + void TileImageInt(const SkBitmap& bitmap, int src_x, int src_y, int dest_x, int dest_y, int w, int h); @@ -353,19 +354,6 @@ class UI_EXPORT Canvas { bool IntersectsClipRectInt(int x, int y, int w, int h); bool IntersectsClipRect(const gfx::Rect& rect); - // Returns the bitmap whose density best matches the current canvas scale. - // Returns a null bitmap if |image| contains no bitmaps. - // |bitmap_scale_factor| is set to the scale factor of the returned bitmap. - // Builds mip map for returned bitmap if necessary. - // - // An optional additional user defined scale can be provided. - const SkBitmap& GetBitmapToPaint(const gfx::ImageSkia& image, - float* bitmap_scale_factor) const; - const SkBitmap& GetBitmapToPaint(const gfx::ImageSkia& image, - float user_defined_scale_factor_x, - float user_defined_scale_factor_y, - float* bitmap_scale_factor) const; - #if defined(OS_WIN) // Draws text with the specified color, font and location. The text is // aligned to the left, vertically centered, clipped to the region. If the diff --git a/ui/gfx/image/image.cc b/ui/gfx/image/image.cc index dac2ccc..e748dd9 100644 --- a/ui/gfx/image/image.cc +++ b/ui/gfx/image/image.cc @@ -31,8 +31,7 @@ namespace internal { #if defined(OS_MACOSX) // This is a wrapper around gfx::NSImageToSkBitmap() because this cross-platform // file cannot include the [square brackets] of ObjC. -ImageSkia NSImageToImageSkia(NSImage* image); -NSImage* ImageSkiaToNSImage(const ImageSkia* image); +bool NSImageToSkBitmaps(NSImage* image, std::vector<const SkBitmap*>* bitmaps); #endif #if defined(TOOLKIT_GTK) @@ -98,7 +97,6 @@ class ImageRep { class ImageRepSkia : public ImageRep { public: - // Takes ownership of |image|. explicit ImageRepSkia(ImageSkia* image) : ImageRep(Image::kImageRepSkia), image_(image) { @@ -226,13 +224,6 @@ Image::Image() { // |storage_| is NULL for empty Images. } -Image::Image(const ImageSkia& image) - : storage_(new internal::ImageStorage(Image::kImageRepSkia)) { - internal::ImageRepSkia* rep = new internal::ImageRepSkia( - new ImageSkia(image)); - AddRepresentation(rep); -} - Image::Image(const SkBitmap* bitmap) : storage_(new internal::ImageStorage(Image::kImageRepSkia)) { internal::ImageRepSkia* rep = new internal::ImageRepSkia( @@ -247,6 +238,13 @@ Image::Image(const SkBitmap& bitmap) AddRepresentation(rep); } +Image::Image(const std::vector<const SkBitmap*>& bitmaps) + : storage_(new internal::ImageStorage(Image::kImageRepSkia)) { + internal::ImageRepSkia* rep = new internal::ImageRepSkia( + new ImageSkia(bitmaps)); + AddRepresentation(rep); +} + #if defined(TOOLKIT_GTK) Image::Image(GdkPixbuf* pixbuf) : storage_(new internal::ImageStorage(Image::kImageRepGdk)) { @@ -276,7 +274,7 @@ Image::~Image() { const SkBitmap* Image::ToSkBitmap() const { internal::ImageRep* rep = GetRepresentation(Image::kImageRepSkia); - return rep->AsImageRepSkia()->image()->bitmap(); + return rep->AsImageRepSkia()->image()->bitmaps()[0]; } const ImageSkia* Image::ToImageSkia() const { @@ -303,10 +301,6 @@ NSImage* Image::ToNSImage() const { } #endif -ImageSkia* Image::CopyImageSkia() const { - return new ImageSkia(*ToImageSkia()); -} - SkBitmap* Image::CopySkBitmap() const { return new SkBitmap(*ToSkBitmap()); } @@ -392,8 +386,9 @@ internal::ImageRep* Image::GetRepresentation( #elif defined(OS_MACOSX) if (storage_->default_representation_type() == Image::kImageRepCocoa) { internal::ImageRepCocoa* nsimage_rep = default_rep->AsImageRepCocoa(); - ImageSkia image_skia = internal::NSImageToImageSkia(nsimage_rep->image()); - rep = new internal::ImageRepSkia(new ImageSkia(image_skia)); + std::vector<const SkBitmap*> bitmaps; + CHECK(internal::NSImageToSkBitmaps(nsimage_rep->image(), &bitmaps)); + rep = new internal::ImageRepSkia(new ImageSkia(bitmaps)); } #endif CHECK(rep); @@ -422,13 +417,13 @@ internal::ImageRep* Image::GetRepresentation( #elif defined(TOOLKIT_GTK) if (rep_type == Image::kImageRepGdk) { GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap( - default_rep->AsImageRepSkia()->image()->bitmap()); + default_rep->AsImageRepSkia()->image()->bitmaps()[0]); native_rep = new internal::ImageRepGdk(pixbuf); } #elif defined(OS_MACOSX) if (rep_type == Image::kImageRepCocoa) { - NSImage* image = internal::ImageSkiaToNSImage( - default_rep->AsImageRepSkia()->image()); + NSImage* image = gfx::SkBitmapsToNSImage( + default_rep->AsImageRepSkia()->image()->bitmaps()); base::mac::NSObjectRetain(image); native_rep = new internal::ImageRepCocoa(image); } diff --git a/ui/gfx/image/image.h b/ui/gfx/image/image.h index b5bb3bf..9c0e6eb 100644 --- a/ui/gfx/image/image.h +++ b/ui/gfx/image/image.h @@ -62,9 +62,6 @@ class UI_EXPORT Image { // Creates an empty image with no representations. Image(); - // Creates a new image with the default representation. - explicit Image(const ImageSkia& image); - // Creates a new image with the default representation. The object will take // ownership of the image. explicit Image(const SkBitmap* bitmap); @@ -73,6 +70,10 @@ class UI_EXPORT Image { // representation. explicit Image(const SkBitmap& bitmap); + // To create an Image that supports multiple resolutions pass a vector + // of bitmaps, one for each resolution. + explicit Image(const std::vector<const SkBitmap*>& bitmaps); + #if defined(TOOLKIT_GTK) // Does not increase |pixbuf|'s reference count; expects to take ownership. explicit Image(GdkPixbuf* pixbuf); @@ -111,7 +112,6 @@ class UI_EXPORT Image { // backing pixels are shared amongst all copies (a fact of each of the // converted representations, rather than a limitation imposed by Image) and // so the result should be considered immutable. - ImageSkia* CopyImageSkia() const; SkBitmap* CopySkBitmap() const; #if defined(TOOLKIT_GTK) GdkPixbuf* CopyGdkPixbuf() const; diff --git a/ui/gfx/image/image_mac.mm b/ui/gfx/image/image_mac.mm index eeed857..55b4aa4 100644 --- a/ui/gfx/image/image_mac.mm +++ b/ui/gfx/image/image_mac.mm @@ -1,46 +1,25 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// 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. #import <AppKit/AppKit.h> -#import <vector> -#include "base/memory/scoped_nsobject.h" #include "base/memory/scoped_ptr.h" #include "skia/ext/skia_utils_mac.h" #include "third_party/skia/include/core/SkBitmap.h" -#include "ui/gfx/image/image_skia.h" namespace gfx { namespace internal { -gfx::ImageSkia NSImageToImageSkia(NSImage* image) { - gfx::ImageSkia image_skia; +bool NSImageToSkBitmaps(NSImage* image, std::vector<const SkBitmap*>* bitmaps) { for (NSImageRep* imageRep in [image representations]) { - NSSize imageRepSize = [imageRep size]; - SkBitmap bitmap(gfx::NSImageRepToSkBitmap(imageRep, imageRepSize, false)); - if (!bitmap.isNull() && !bitmap.empty()) { - float scaleFactor = imageRepSize.width / [image size].width; - image_skia.AddBitmapForScale(bitmap, scaleFactor); - } + scoped_ptr<SkBitmap> bitmap(new SkBitmap( + gfx::NSImageRepToSkBitmap(imageRep, [imageRep size], false))); + if (bitmap->isNull()) + return false; + bitmaps->push_back(bitmap.release()); } - return image_skia; -} - -NSImage* ImageSkiaToNSImage(const gfx::ImageSkia* image_skia) { - if (image_skia->empty()) - return nil; - - scoped_nsobject<NSImage> image([[NSImage alloc] init]); - - const std::vector<SkBitmap> bitmaps = image_skia->bitmaps(); - for (std::vector<SkBitmap>::const_iterator it = bitmaps.begin(); - it != bitmaps.end(); ++it) { - [image addRepresentation:gfx::SkBitmapToNSBitmapImageRep(*it)]; - } - - [image setSize:NSMakeSize(image_skia->width(), image_skia->height())]; - return [image.release() autorelease]; + return true; } } // namespace internal diff --git a/ui/gfx/image/image_mac_unittest.mm b/ui/gfx/image/image_mac_unittest.mm index 1de9c64..f0ed004 100644 --- a/ui/gfx/image/image_mac_unittest.mm +++ b/ui/gfx/image/image_mac_unittest.mm @@ -6,7 +6,6 @@ #include "base/logging.h" #include "base/memory/scoped_nsobject.h" -#include "base/memory/scoped_ptr.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/image/image.h" @@ -32,61 +31,57 @@ class ImageMacTest : public testing::Test { namespace gt = gfx::test; -TEST_F(ImageMacTest, MultiResolutionNSImageToImageSkia) { - const int width1x = 10; - const int height1x = 12; - const int width2x = 20; - const int height2x = 24; +TEST_F(ImageMacTest, MultiResolutionNSImageToSkBitmap) { + const int width1 = 10; + const int height1 = 12; + const int width2 = 20; + const int height2 = 24; NSImageRep* image_rep_1; - CreateBitmapImageRep(width1x, height1x, &image_rep_1); + CreateBitmapImageRep(width1, height1, &image_rep_1); NSImageRep* image_rep_2; - CreateBitmapImageRep(width2x, height2x, &image_rep_2); + CreateBitmapImageRep(width2, height2, &image_rep_2); scoped_nsobject<NSImage> ns_image( - [[NSImage alloc] initWithSize:NSMakeSize(width1x, height1x)]); + [[NSImage alloc] initWithSize:NSMakeSize(width1, height1)]); [ns_image addRepresentation:image_rep_1]; [ns_image addRepresentation:image_rep_2]; gfx::Image image(ns_image.release()); EXPECT_EQ(1u, image.RepresentationCount()); - - const gfx::ImageSkia* image_skia = image.ToImageSkia(); - EXPECT_EQ(2u, image_skia->bitmaps().size()); - - float scale_factor; - const SkBitmap& bitmap1x = image_skia->GetBitmapForScale(1.0f, 1.0f, - &scale_factor); - EXPECT_TRUE(!bitmap1x.isNull()); - EXPECT_EQ(1.0f, scale_factor); - EXPECT_EQ(width1x, bitmap1x.width()); - EXPECT_EQ(height1x, bitmap1x.height()); - - const SkBitmap& bitmap2x = image_skia->GetBitmapForScale(2.0f, 2.0f, - &scale_factor); - EXPECT_TRUE(!bitmap2x.isNull()); - EXPECT_EQ(2.0f, scale_factor); - EXPECT_EQ(width2x, bitmap2x.width()); - EXPECT_EQ(height2x, bitmap2x.height()); + const std::vector<const SkBitmap*>& bitmaps = image.ToImageSkia()->bitmaps(); + EXPECT_EQ(2u, bitmaps.size()); + + const SkBitmap* bitmap1 = bitmaps[0]; + EXPECT_TRUE(bitmap1); + const SkBitmap* bitmap2 = bitmaps[1]; + EXPECT_TRUE(bitmap2); + + if (bitmap1->width() == width1) { + EXPECT_EQ(bitmap1->height(), height1); + EXPECT_EQ(bitmap2->width(), width2); + EXPECT_EQ(bitmap2->height(), height2); + } else { + EXPECT_EQ(bitmap1->width(), width2); + EXPECT_EQ(bitmap1->height(), height2); + EXPECT_EQ(bitmap2->width(), width1); + EXPECT_EQ(bitmap2->height(), height1); + } // ToImageSkia should create a second representation. EXPECT_EQ(2u, image.RepresentationCount()); } -TEST_F(ImageMacTest, MultiResolutionImageSkiaToNSImage) { - const int width1x = 10; - const int height1x= 12; - const int width2x = 20; - const int height2x = 24; - - scoped_ptr<SkBitmap> bitmap1x(gt::CreateBitmap(width1x, height1x)); - scoped_ptr<SkBitmap> bitmap2x(gt::CreateBitmap(width2x, height2x)); +TEST_F(ImageMacTest, MultiResolutionSkBitmapToNSImage) { + const int width1 = 10; + const int height1 = 12; + const int width2 = 20; + const int height2 = 24; - gfx::ImageSkia image_skia; - image_skia.AddBitmapForScale(*bitmap1x, 1.0f); - image_skia.AddBitmapForScale(*bitmap2x, 2.0f); - - gfx::Image image(image_skia); + std::vector<const SkBitmap*> bitmaps; + bitmaps.push_back(gt::CreateBitmap(width1, height1)); + bitmaps.push_back(gt::CreateBitmap(width2, height2)); + gfx::Image image(bitmaps); EXPECT_EQ(1u, image.RepresentationCount()); EXPECT_EQ(2u, image.ToImageSkia()->bitmaps().size()); @@ -94,24 +89,19 @@ TEST_F(ImageMacTest, MultiResolutionImageSkiaToNSImage) { NSImage* ns_image = image; EXPECT_TRUE(ns_image); - // Image size should be the same as the 1x bitmap. - EXPECT_EQ([ns_image size].width, width1x); - EXPECT_EQ([ns_image size].height, height1x); - EXPECT_EQ(2u, [[image representations] count]); NSImageRep* image_rep_1 = [[image representations] objectAtIndex:0]; NSImageRep* image_rep_2 = [[image representations] objectAtIndex:1]; - if ([image_rep_1 size].width == width1x) { - EXPECT_EQ([image_rep_1 size].width, width1x); - EXPECT_EQ([image_rep_1 size].height, height1x); - EXPECT_EQ([image_rep_2 size].width, width2x); - EXPECT_EQ([image_rep_2 size].height, height2x); + if ([image_rep_1 size].width == width1) { + EXPECT_EQ([image_rep_1 size].height, height1); + EXPECT_EQ([image_rep_2 size].width, width2); + EXPECT_EQ([image_rep_2 size].height, height2); } else { - EXPECT_EQ([image_rep_1 size].width, width2x); - EXPECT_EQ([image_rep_1 size].height, height2x); - EXPECT_EQ([image_rep_2 size].width, width1x); - EXPECT_EQ([image_rep_2 size].height, height1x); + EXPECT_EQ([image_rep_1 size].width, width2); + EXPECT_EQ([image_rep_1 size].height, height2); + EXPECT_EQ([image_rep_2 size].width, width1); + EXPECT_EQ([image_rep_2 size].height, height1); } // Cast to NSImage* should create a second representation. diff --git a/ui/gfx/image/image_skia.cc b/ui/gfx/image/image_skia.cc index d7ad469c..3c2e94f 100644 --- a/ui/gfx/image/image_skia.cc +++ b/ui/gfx/image/image_skia.cc @@ -8,200 +8,139 @@ #include <cmath> #include "base/logging.h" -#include "ui/gfx/size.h" -#include "base/message_loop.h" -#include "third_party/skia/include/core/SkPixelRef.h" +#include "base/stl_util.h" namespace gfx { -namespace internal { - -// 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() { - } - - void AddBitmap(const SkBitmap& bitmap) { - bitmaps_.push_back(bitmap); - } - - const std::vector<SkBitmap>& bitmaps() const { return bitmaps_; } - - void set_size(const gfx::Size& size) { size_ = size; } - const gfx::Size& size() const { return size_; } - - private: - ~ImageSkiaStorage() { +ImageSkia::ImageSkia(const SkBitmap* bitmap) + : size_(bitmap->width(), bitmap->height()), + mip_map_build_pending_(false) { + CHECK(bitmap); + // TODO(pkotwicz): Add a CHECK to ensure that !bitmap->isNull() + bitmaps_.push_back(bitmap); +} + +ImageSkia::ImageSkia(const std::vector<const SkBitmap*>& bitmaps) + : bitmaps_(bitmaps), + mip_map_build_pending_(false) { + CHECK(!bitmaps_.empty()); + // TODO(pkotwicz): Add a CHECK to ensure that !bitmap->isNull() for each + // vector element. + // Assume that the smallest bitmap represents 1x scale factor. + for (size_t i = 0; i < bitmaps_.size(); ++i) { + gfx::Size bitmap_size(bitmaps_[i]->width(), bitmaps_[i]->height()); + if (size_.IsEmpty() || bitmap_size.GetArea() < size_.GetArea()) + size_ = bitmap_size; } +} - // Bitmaps at different densities. - std::vector<SkBitmap> bitmaps_; - - // Size of the image in DIP. - gfx::Size size_; - - friend class base::RefCounted<ImageSkiaStorage>; -}; - -} // internal - -ImageSkia::ImageSkia() : storage_(NULL) { +ImageSkia::~ImageSkia() { + STLDeleteElements(&bitmaps_); } -ImageSkia::ImageSkia(const SkBitmap& bitmap) { - Init(bitmap); +void ImageSkia::BuildMipMap() { + mip_map_build_pending_ = true; } -ImageSkia::ImageSkia(const SkBitmap& bitmap, float dip_scale_factor) { - Init(bitmap, dip_scale_factor); +void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, int x, int y) { + SkPaint p; + DrawToCanvasInt(canvas, x, y, p); } -ImageSkia::ImageSkia(const SkBitmap* bitmap) { - Init(*bitmap); +void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, + int x, int y, + const SkPaint& paint) { + + if (IsZeroSized()) + return; + + SkMatrix m = canvas->sk_canvas()->getTotalMatrix(); + float scale_x = std::abs(SkScalarToFloat(m.getScaleX())); + float scale_y = std::abs(SkScalarToFloat(m.getScaleY())); + + const SkBitmap* bitmap = GetBitmapForScale(scale_x, scale_y); - if (MessageLoop::current()) { - // Use DeleteSoon such that |bitmap| is still valid if caller uses |bitmap| - // immediately after having called constructor. - MessageLoop::current()->DeleteSoon(FROM_HERE, bitmap); - } else { - // Hit in unittests. - delete bitmap; + if (mip_map_build_pending_) { + const_cast<SkBitmap*>(bitmap)->buildMipMap(); + mip_map_build_pending_ = false; } -} -ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) { -} + float bitmap_scale_x = static_cast<float>(bitmap->width()) / width(); + float bitmap_scale_y = static_cast<float>(bitmap->height()) / height(); -ImageSkia& ImageSkia::operator=(const ImageSkia& other) { - storage_ = other.storage_; - return *this; + canvas->Save(); + canvas->sk_canvas()->scale(1.0f / bitmap_scale_x, + 1.0f / bitmap_scale_y); + canvas->sk_canvas()->drawBitmap(*bitmap, SkFloatToScalar(x * bitmap_scale_x), + SkFloatToScalar(y * bitmap_scale_y)); + canvas->Restore(); } -ImageSkia& ImageSkia::operator=(const SkBitmap& other) { - Init(other); - return *this; +void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, + int src_x, int src_y, int src_w, int src_h, + int dest_x, int dest_y, int dest_w, int dest_h, + bool filter) { + SkPaint p; + DrawToCanvasInt(canvas, src_x, src_y, src_w, src_h, dest_x, dest_y, + dest_w, dest_h, filter, p); } -ImageSkia::operator SkBitmap&() const { - if (isNull()) { - // TODO(pkotwicz): This is temporary till conversion to gfx::ImageSkia is - // done. - // Static null bitmap such that we are not returning a temporary. - static SkBitmap* null_bitmap = new SkBitmap(); - return *null_bitmap; - } +void ImageSkia::DrawToCanvasInt(gfx::Canvas* canvas, + int src_x, int src_y, int src_w, int src_h, + int dest_x, int dest_y, int dest_w, int dest_h, + bool filter, + const SkPaint& paint) { + if (IsZeroSized()) + return; - return const_cast<SkBitmap&>(storage_->bitmaps()[0]); -} + SkMatrix m = canvas->sk_canvas()->getTotalMatrix(); + float scale_x = std::abs(SkScalarToFloat(m.getScaleX())); + float scale_y = std::abs(SkScalarToFloat(m.getScaleY())); -ImageSkia::~ImageSkia() { -} + const SkBitmap* bitmap = GetBitmapForScale(scale_x, scale_y); -void ImageSkia::AddBitmapForScale(const SkBitmap& bitmap, - float dip_scale_factor) { - DCHECK(!bitmap.isNull()); - - if (isNull()) { - Init(bitmap, dip_scale_factor); - } else { - // We currently assume that the bitmap size = 1x size * |dip_scale_factor|. - // TODO(pkotwicz): Do something better because of rounding errors when - // |dip_scale_factor| is not an int. - // TODO(pkotwicz): Remove DCHECK for dip_scale_factor == 1.0f once - // image_loading_tracker correctly handles multiple sized images. - DCHECK(dip_scale_factor == 1.0f || - static_cast<int>(width() * dip_scale_factor) == bitmap.width()); - DCHECK(dip_scale_factor == 1.0f || - static_cast<int>(height() * dip_scale_factor) == bitmap.height()); - storage_->AddBitmap(bitmap); + if (mip_map_build_pending_) { + const_cast<SkBitmap*>(bitmap)->buildMipMap(); + mip_map_build_pending_ = false; } -} -const SkBitmap& ImageSkia::GetBitmapForScale(float x_scale_factor, - float y_scale_factor, - float* bitmap_scale_factor) const { + float bitmap_scale_x = static_cast<float>(bitmap->width()) / width(); + float bitmap_scale_y = static_cast<float>(bitmap->height()) / height(); - // Static null bitmap such that we are not returning a temporary. - static SkBitmap* null_bitmap = new SkBitmap(); + canvas->Save(); + canvas->sk_canvas()->scale(1.0f / bitmap_scale_x, + 1.0f / bitmap_scale_y); + canvas->DrawBitmapFloat(*bitmap, + src_x * bitmap_scale_x, src_y * bitmap_scale_x, + src_w * bitmap_scale_x, src_h * bitmap_scale_y, + dest_x * bitmap_scale_x, dest_y * bitmap_scale_y, + dest_w * bitmap_scale_x, dest_h * bitmap_scale_y, + filter, paint); - if (empty()) - return *null_bitmap; + canvas->Restore(); +} +const SkBitmap* ImageSkia::GetBitmapForScale(float x_scale_factor, + float y_scale_factor) const { // Get the desired bitmap width and height given |x_scale_factor|, - // |y_scale_factor| and size at 1x density. - float desired_width = width() * x_scale_factor; - float desired_height = height() * y_scale_factor; + // |y_scale_factor| and |size_| at 1x density. + float desired_width = size_.width() * x_scale_factor; + float desired_height = size_.height() * y_scale_factor; - const std::vector<SkBitmap>& bitmaps = storage_->bitmaps(); size_t closest_index = 0; float smallest_diff = std::numeric_limits<float>::max(); - for (size_t i = 0; i < bitmaps.size(); ++i) { - float diff = std::abs(bitmaps[i].width() - desired_width) + - std::abs(bitmaps[i].height() - desired_height); + for (size_t i = 0; i < bitmaps_.size(); ++i) { + if (bitmaps_[i]->isNull()) + continue; + + float diff = std::abs(bitmaps_[i]->width() - desired_width) + + std::abs(bitmaps_[i]->height() - desired_height); if (diff < smallest_diff) { closest_index = i; smallest_diff = diff; } } - if (smallest_diff < std::numeric_limits<float>::max()) { - *bitmap_scale_factor = bitmaps[closest_index].width() / width(); - return bitmaps[closest_index]; - } - - return *null_bitmap; -} - -bool ImageSkia::empty() const { - return isNull() || storage_->size().IsEmpty(); -} - -int ImageSkia::width() const { - return isNull() ? 0 : storage_->size().width(); -} - -int ImageSkia::height() const { - return isNull() ? 0 : storage_->size().height(); -} - -bool ImageSkia::extractSubset(ImageSkia* dst, SkIRect& subset) const { - if (isNull()) - return false; - SkBitmap dst_bitmap; - bool return_value = storage_->bitmaps()[0].extractSubset(&dst_bitmap, - subset); - *dst = ImageSkia(dst_bitmap); - return return_value; -} - -const std::vector<SkBitmap> ImageSkia::bitmaps() const { - return storage_->bitmaps(); -} - -const SkBitmap* ImageSkia::bitmap() const { - if (isNull()) - return NULL; - - return &storage_->bitmaps()[0]; -} - -void ImageSkia::Init(const SkBitmap& bitmap) { - Init(bitmap, 1.0f); -} - -void ImageSkia::Init(const SkBitmap& bitmap, float scale_factor) { - DCHECK_GT(scale_factor, 0.0f); - // TODO(pkotwicz): The image should be null whenever bitmap is null. - if (bitmap.empty()) { - storage_ = NULL; - return; - } - storage_ = new internal::ImageSkiaStorage(); - storage_->set_size(gfx::Size(static_cast<int>(bitmap.width() / scale_factor), - static_cast<int>(bitmap.height() / scale_factor))); - storage_->AddBitmap(bitmap); + return bitmaps_[closest_index]; } } // namespace gfx diff --git a/ui/gfx/image/image_skia.h b/ui/gfx/image/image_skia.h index 8b911cb..bdfb53f 100644 --- a/ui/gfx/image/image_skia.h +++ b/ui/gfx/image/image_skia.h @@ -9,119 +9,80 @@ #include <vector> #include "base/basictypes.h" -#include "base/memory/ref_counted.h" #include "third_party/skia/include/core/SkBitmap.h" -#include "ui/base/ui_export.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/size.h" namespace gfx { -namespace internal { -class ImageSkiaStorage; -} // namespace internal - // Container for the same image at different densities, similar to NSImage. -// Image height and width are in DIP (Device Indepent Pixel) coordinates. -// -// ImageSkia should be used whenever possible instead of SkBitmap. -// Functions that mutate the image should operate on the SkBitmap returned -// from ImageSkia::GetBitmapForScale, not on ImageSkia. -// -// ImageSkia is cheap to copy and intentionally supports copy semantics. +// Smallest image is assumed to represent 1x density. + +// ImageSkia should be used for caching and drawing images of different +// densities. It should not be used as an SkBitmap wrapper. class UI_EXPORT ImageSkia { public: - // Creates instance with no bitmaps. - ImageSkia(); - - // Adds ref to passed in bitmap. - // DIP width and height are set based on scale factor of 1x. - // TODO(pkotwicz): This is temporary till conversion to gfx::ImageSkia is - // done. - ImageSkia(const SkBitmap& bitmap); - - // Adds ref to passed in bitmap. - // DIP width and height are set based on |dip_scale_factor|. - ImageSkia(const SkBitmap& bitmap, float dip_scale_factor); - - // Takes ownership of passed in bitmap. - // Caller should not assume that |bitmap| will be valid after constructor - // is called. - // DIP width and height are set based on scale factor of 1x. - // TODO(pkotwicz): This is temporary till conversion to gfx::ImageSkia is - // done. explicit ImageSkia(const SkBitmap* bitmap); - - // Copies a reference to |other|'s storage. - ImageSkia(const ImageSkia& other); - - // Copies a reference to |other|'s storage. - ImageSkia& operator=(const ImageSkia& other); - - // Converts from SkBitmap. - // Adds ref to passed in bitmap. - // DIP width and height are set based on scale factor of 1x. - // TODO(pkotwicz): This is temporary till conversion to gfx::ImageSkia is - // done. - ImageSkia& operator=(const SkBitmap& other); - - // Converts to SkBitmap. - // TODO(pkotwicz): This is temporary till conversion to gfx::ImageSkia is - // done. - operator SkBitmap&() const; - + explicit ImageSkia(const std::vector<const SkBitmap*>& bitmaps); ~ImageSkia(); - // Adds |bitmap| for |dip_scale_factor| to bitmaps contained by this object. - // Adds ref to passed in bitmap. - // DIP width and height are set based on |dip_scale_factor|. - void AddBitmapForScale(const SkBitmap& bitmap, float dip_scale_factor); - - // Returns the bitmap whose density best matches |x_scale_factor| and - // |y_scale_factor|. - // Returns a null bitmap if object contains no bitmaps. - // |bitmap_scale_factor| is set to the scale factor of the returned bitmap. - const SkBitmap& GetBitmapForScale(float x_scale_factor, - float y_scale_factor, - float* bitmap_scale_factor) const; - - // Returns true if object is null or |size_| is empty. - bool empty() const; - - // Returns true if this is a null object. - // TODO(pkotwicz): Merge this function into empty(). - bool isNull() const { return storage_ == NULL; } + // Build mipmap at time of next call to |DrawToCanvasInt|. + void BuildMipMap(); + + // Draws the image with the origin at the specified location. The upper left + // corner of the image is rendered at the specified location. + void DrawToCanvasInt(Canvas* canvas, int x, int y); + + // Draws the image with the origin at the specified location, using the + // specified paint. The upper left corner of the image is rendered at the + // specified location. + void DrawToCanvasInt(Canvas* canvas, + int x, int y, + const SkPaint& paint); + + // Draws a portion of the image in the specified location. The src parameters + // correspond to the region of the image to draw in the region defined + // by the dest coordinates. + // + // If the width or height of the source differs from that of the destination, + // the image will be scaled. When scaling down, it is highly recommended + // that you call BuildMipMap() on your image to ensure that it has + // a mipmap, which will result in much higher-quality output. Set |filter| to + // use filtering for bitmaps, otherwise the nearest-neighbor algorithm is used + // for resampling. + // + // An optional custom SkPaint can be provided. + void DrawToCanvasInt(Canvas* canvas, + int src_x, int src_y, int src_w, int src_h, + int dest_x, int dest_y, int dest_w, int dest_h, + bool filter); + void DrawToCanvasInt(Canvas* canvas, + int src_x, int src_y, int src_w, int src_h, + int dest_x, int dest_y, int dest_w, int dest_h, + bool filter, + const SkPaint& paint); + + // Returns true if |size_| is empty. + bool IsZeroSized() const { return size_.IsEmpty(); } // Width and height of image in DIP coordinate system. - int width() const; - int height() const; - - // Wrapper function for SkBitmap::extractBitmap. - // Operates on bitmap at index 0 if available. - // TODO(pkotwicz): This is temporary till conversion to gfx::ImageSkia is - // done. - bool extractSubset(ImageSkia* dst, SkIRect& subset) const; - - // Returns pointer to an SkBitmap contained by this object. - // TODO(pkotwicz): This is temporary till conversion to gfx::ImageSkia is - // done. - const SkBitmap* bitmap() const; + int width() const { return size_.width(); } + int height() const { return size_.height(); } // Returns a vector with the SkBitmaps contained in this object. - const std::vector<SkBitmap> bitmaps() const; + const std::vector<const SkBitmap*>& bitmaps() const { return bitmaps_; } private: - // Initialize ImageStorage with passed in parameters. - // If |bitmap.isNull()|, ImageStorage is set to NULL. - // Scale factor is set based on default scale factor of 1x. - // TODO(pkotwicz): This is temporary till conversion to gfx::ImageSkia is - // done. - void Init(const SkBitmap& bitmap); - - // Initialize ImageStorage with passed in parameters. - // If |bitmap.isNull()|, ImageStorage is set to NULL. - void Init(const SkBitmap& bitmap, float scale_factor); - - // A refptr so that ImageRepSkia can be copied cheaply. - scoped_refptr<internal::ImageSkiaStorage> storage_; + // Returns the bitmap whose density best matches |x_scale_factor| and + // |y_scale_factor|. + const SkBitmap* GetBitmapForScale(float x_scale_factor, + float y_scale_factor) const; + + std::vector<const SkBitmap*> bitmaps_; + gfx::Size size_; + bool mip_map_build_pending_; + + DISALLOW_COPY_AND_ASSIGN(ImageSkia); }; } // namespace gfx diff --git a/ui/gfx/image/image_unittest.cc b/ui/gfx/image/image_unittest.cc index 7b50be8..8793562 100644 --- a/ui/gfx/image/image_unittest.cc +++ b/ui/gfx/image/image_unittest.cc @@ -251,39 +251,41 @@ TEST_F(ImageTest, Assign) { EXPECT_EQ(image1.ToSkBitmap(), image2.ToSkBitmap()); } -TEST_F(ImageTest, MultiResolutionImage) { - const int width1x = 10; - const int height1x = 12; - const int width2x = 20; - const int height2x = 24; - - scoped_ptr<SkBitmap> bitmap1(gt::CreateBitmap(width1x, height1x)); - scoped_ptr<SkBitmap> bitmap2(gt::CreateBitmap(width2x, height2x)); - - gfx::ImageSkia image_skia; - image_skia.AddBitmapForScale(*bitmap1, 1.0f); - image_skia.AddBitmapForScale(*bitmap2, 2.0f); - - EXPECT_EQ(2u, image_skia.bitmaps().size()); - - float scale_factor; - const SkBitmap& bitmap1x = image_skia.GetBitmapForScale(1.0f, 1.0f, - &scale_factor); - EXPECT_TRUE(!bitmap1x.isNull()); - EXPECT_EQ(1.0f, scale_factor); - EXPECT_EQ(width1x, bitmap1x.width()); - EXPECT_EQ(height1x, bitmap1x.height()); - - const SkBitmap& bitmap2x = image_skia.GetBitmapForScale(2.0f, 2.0f, - &scale_factor); - EXPECT_TRUE(!bitmap2x.isNull()); - EXPECT_EQ(2.0f, scale_factor); - EXPECT_EQ(width2x, bitmap2x.width()); - EXPECT_EQ(height2x, bitmap2x.height()); - - // Check that the image has a single representation. - gfx::Image image(image_skia); +TEST_F(ImageTest, MultiResolutionSkBitmap) { + const int width1 = 10; + const int height1 = 12; + const int width2 = 20; + const int height2 = 24; + + std::vector<const SkBitmap*> bitmaps; + bitmaps.push_back(gt::CreateBitmap(width1, height1)); + bitmaps.push_back(gt::CreateBitmap(width2, height2)); + gfx::Image image(bitmaps); + + EXPECT_EQ(1u, image.RepresentationCount()); + const std::vector<const SkBitmap*>& image_bitmaps = + image.ToImageSkia()->bitmaps(); + EXPECT_EQ(2u, image_bitmaps.size()); + + const SkBitmap* bitmap1 = image_bitmaps[0]; + EXPECT_TRUE(bitmap1); + const SkBitmap* bitmap2 = image_bitmaps[1]; + EXPECT_TRUE(bitmap2); + + if (bitmap1->width() == width1) { + EXPECT_EQ(bitmap1->height(), height1); + EXPECT_EQ(bitmap2->width(), width2); + EXPECT_EQ(bitmap2->height(), height2); + } else { + EXPECT_EQ(bitmap1->width(), width2); + EXPECT_EQ(bitmap1->height(), height2); + EXPECT_EQ(bitmap2->width(), width1); + EXPECT_EQ(bitmap2->height(), height1); + } + + // Sanity check. EXPECT_EQ(1u, image.RepresentationCount()); + EXPECT_EQ(2u, image.ToImageSkia()->bitmaps().size()); } // Integration tests with UI toolkit frameworks require linking against the |