diff options
author | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-22 01:08:51 +0000 |
---|---|---|
committer | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-22 01:08:51 +0000 |
commit | 8779d8bd47ddd9893809e73a9a552a0b463e3188 (patch) | |
tree | af4c18d2146edcb2f55013c472867a5a2d4b7dbf | |
parent | 7c719877de70f70a25d0549671603728d8dc8f77 (diff) | |
download | chromium_src-8779d8bd47ddd9893809e73a9a552a0b463e3188.zip chromium_src-8779d8bd47ddd9893809e73a9a552a0b463e3188.tar.gz chromium_src-8779d8bd47ddd9893809e73a9a552a0b463e3188.tar.bz2 |
Move the internals of gfx::Image into a ref-counted storage class.
This will allow gfx::Image to be cheaply copied like an SkBitmap.
BUG=none
TEST=ui_unittests
Review URL: http://codereview.chromium.org/6880121
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@82599 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ui/gfx/image.cc | 81 | ||||
-rw-r--r-- | ui/gfx/image.h | 34 | ||||
-rw-r--r-- | ui/gfx/image_unittest.cc | 58 |
3 files changed, 124 insertions, 49 deletions
diff --git a/ui/gfx/image.cc b/ui/gfx/image.cc index b42e215..9395279 100644 --- a/ui/gfx/image.cc +++ b/ui/gfx/image.cc @@ -150,35 +150,74 @@ class NSImageRep : public ImageRep { }; #endif +// The Storage class acts similarly to the pixels in a SkBitmap: the Image +// class holds a refptr instance of Storage, which in turn holds all the +// ImageReps. This way, the Image can be cheaply copied. +class ImageStorage : public base::RefCounted<ImageStorage> { + public: + ImageStorage(gfx::Image::RepresentationType default_type) + : default_representation_type_(default_type) { + } + + gfx::Image::RepresentationType default_representation_type() { + return default_representation_type_; + } + gfx::Image::RepresentationMap& representations() { return representations_; } + + private: + ~ImageStorage() { + for (gfx::Image::RepresentationMap::iterator it = representations_.begin(); + it != representations_.end(); + ++it) { + delete it->second; + } + representations_.clear(); + } + + // 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_; + + // All the representations of an Image. Size will always be at least one, with + // more for any converted representations. + gfx::Image::RepresentationMap representations_; + + friend class base::RefCounted<ImageStorage>; +}; + } // namespace internal Image::Image(const SkBitmap* bitmap) - : default_representation_(Image::kSkBitmapRep) { + : storage_(new internal::ImageStorage(Image::kSkBitmapRep)) { internal::SkBitmapRep* rep = new internal::SkBitmapRep(bitmap); AddRepresentation(rep); } #if defined(OS_LINUX) Image::Image(GdkPixbuf* pixbuf) - : default_representation_(Image::kGdkPixbufRep) { + : storage_(new internal::ImageStorage(Image::kGdkPixbufRep)) { internal::GdkPixbufRep* rep = new internal::GdkPixbufRep(pixbuf); AddRepresentation(rep); } #endif #if defined(OS_MACOSX) -Image::Image(NSImage* image) : default_representation_(Image::kNSImageRep) { +Image::Image(NSImage* image) + : storage_(new internal::ImageStorage(Image::kNSImageRep)) { internal::NSImageRep* rep = new internal::NSImageRep(image); AddRepresentation(rep); } #endif +Image::Image(const Image& other) : storage_(other.storage_) { +} + +Image& Image::operator=(const Image& other) { + storage_ = other.storage_; + return *this; +} + Image::~Image() { - for (RepresentationMap::iterator it = representations_.begin(); - it != representations_.end(); ++it) { - delete it->second; - } - representations_.clear(); } Image::operator const SkBitmap*() { @@ -205,30 +244,34 @@ Image::operator NSImage*() { #endif bool Image::HasRepresentation(RepresentationType type) { - return representations_.count(type) != 0; + return storage_->representations().count(type) != 0; +} + +size_t Image::RepresentationCount() { + return storage_->representations().size(); } void Image::SwapRepresentations(gfx::Image* other) { - representations_.swap(other->representations_); - std::swap(default_representation_, other->default_representation_); + storage_.swap(other->storage_); } internal::ImageRep* Image::DefaultRepresentation() { + RepresentationMap& representations = storage_->representations(); RepresentationMap::iterator it = - representations_.find(default_representation_); - DCHECK(it != representations_.end()); + representations.find(storage_->default_representation_type()); + DCHECK(it != representations.end()); return it->second; } internal::ImageRep* Image::GetRepresentation(RepresentationType rep_type) { // If the requested rep is the default, return it. internal::ImageRep* default_rep = DefaultRepresentation(); - if (rep_type == default_representation_) + if (rep_type == storage_->default_representation_type()) return default_rep; // Check to see if the representation already exists. - RepresentationMap::iterator it = representations_.find(rep_type); - if (it != representations_.end()) + RepresentationMap::iterator it = storage_->representations().find(rep_type); + if (it != storage_->representations().end()) return it->second; // At this point, the requested rep does not exist, so it must be converted @@ -238,13 +281,13 @@ internal::ImageRep* Image::GetRepresentation(RepresentationType rep_type) { if (rep_type == Image::kSkBitmapRep) { internal::SkBitmapRep* rep = NULL; #if defined(OS_LINUX) - if (default_representation_ == Image::kGdkPixbufRep) { + if (storage_->default_representation_type() == Image::kGdkPixbufRep) { internal::GdkPixbufRep* pixbuf_rep = default_rep->AsGdkPixbufRep(); rep = new internal::SkBitmapRep( internal::GdkPixbufToSkBitmap(pixbuf_rep->pixbuf())); } #elif defined(OS_MACOSX) - if (default_representation_ == Image::kNSImageRep) { + if (storage_->default_representation_type() == Image::kNSImageRep) { internal::NSImageRep* nsimage_rep = default_rep->AsNSImageRep(); rep = new internal::SkBitmapRep( internal::NSImageToSkBitmap(nsimage_rep->image())); @@ -281,7 +324,7 @@ internal::ImageRep* Image::GetRepresentation(RepresentationType rep_type) { } void Image::AddRepresentation(internal::ImageRep* rep) { - representations_.insert(std::make_pair(rep->type(), rep)); + storage_->representations().insert(std::make_pair(rep->type(), rep)); } } // namespace gfx diff --git a/ui/gfx/image.h b/ui/gfx/image.h index fddf4da..518d8ac4 100644 --- a/ui/gfx/image.h +++ b/ui/gfx/image.h @@ -8,7 +8,10 @@ // internally to prevent double-conversion. // // The lifetime of both the initial representation and any converted ones are -// tied to the lifetime of the Image object itself. +// tied to the lifetime of the Image's internal storage. To allow Images to be +// cheaply passed around by value, the actual image data is stored in a ref- +// counted member. When all Images referencing this storage are deleted, the +// actual representations are deleted, too. #ifndef UI_GFX_IMAGE_H_ #define UI_GFX_IMAGE_H_ @@ -18,6 +21,7 @@ #include "base/basictypes.h" #include "base/gtest_prod_util.h" +#include "base/memory/ref_counted.h" #include "build/build_config.h" #include "ui/gfx/native_widget_types.h" // Forward-declares GdkPixbuf and NSImage. @@ -31,6 +35,7 @@ namespace gfx { namespace internal { class ImageRep; +class ImageStorage; } class Image { @@ -41,6 +46,8 @@ class Image { kSkBitmapRep, }; + typedef std::map<RepresentationType, internal::ImageRep*> RepresentationMap; + // Creates a new image with the default representation. The object will take // ownership of the image. explicit Image(const SkBitmap* bitmap); @@ -52,7 +59,14 @@ class Image { explicit Image(NSImage* image); #endif - // Deletes the image and all of its cached representations. + // Initializes a new Image by AddRef()ing |other|'s internal storage. + Image(const Image& other); + + // Copies a reference to |other|'s storage. + Image& operator=(const Image& other); + + // Deletes the image and, if the only owner of the storage, all of its cached + // representations. ~Image(); // Conversion handlers. @@ -67,12 +81,13 @@ class Image { // Inspects the representations map to see if the given type exists. bool HasRepresentation(RepresentationType type); + // Returns the number of representations. + size_t RepresentationCount(); + // Swaps this image's internal representations with |other|. void SwapRepresentations(gfx::Image* other); private: - typedef std::map<RepresentationType, internal::ImageRep*> RepresentationMap; - // Returns the ImageRep for the default representation. internal::ImageRep* DefaultRepresentation(); @@ -83,16 +98,11 @@ class Image { // Stores a representation into the map. void AddRepresentation(internal::ImageRep* rep); - // The type of image that was passed to the constructor. This key will always - // exist in the |representations_| map. - RepresentationType default_representation_; - - // All the representations of an Image. Size will always be at least one, with - // more for any converted representations. - RepresentationMap representations_; + // Internal class that holds all the representations. This allows the Image to + // be cheaply copied. + scoped_refptr<internal::ImageStorage> storage_; friend class ::ImageTest; - DISALLOW_COPY_AND_ASSIGN(Image); }; } // namespace gfx diff --git a/ui/gfx/image_unittest.cc b/ui/gfx/image_unittest.cc index 6f41bfe..ce2a1f8 100644 --- a/ui/gfx/image_unittest.cc +++ b/ui/gfx/image_unittest.cc @@ -25,10 +25,6 @@ const bool kUsesSkiaNatively = false; #endif class ImageTest : public testing::Test { - public: - size_t GetRepCount(const gfx::Image& image) { - return image.representations_.size(); - } }; namespace gt = gfx::test; @@ -38,13 +34,13 @@ TEST_F(ImageTest, SkiaToSkia) { const SkBitmap* bitmap = static_cast<const SkBitmap*>(image); EXPECT_TRUE(bitmap); EXPECT_FALSE(bitmap->isNull()); - EXPECT_EQ(1U, GetRepCount(image)); + EXPECT_EQ(1U, image.RepresentationCount()); // Make sure double conversion doesn't happen. bitmap = static_cast<const SkBitmap*>(image); EXPECT_TRUE(bitmap); EXPECT_FALSE(bitmap->isNull()); - EXPECT_EQ(1U, GetRepCount(image)); + EXPECT_EQ(1U, image.RepresentationCount()); EXPECT_TRUE(image.HasRepresentation(gfx::Image::kSkBitmapRep)); if (!kUsesSkiaNatively) @@ -56,11 +52,11 @@ TEST_F(ImageTest, SkiaToSkiaRef) { const SkBitmap& bitmap = static_cast<const SkBitmap&>(image); EXPECT_FALSE(bitmap.isNull()); - EXPECT_EQ(1U, GetRepCount(image)); + EXPECT_EQ(1U, image.RepresentationCount()); const SkBitmap* bitmap1 = static_cast<const SkBitmap*>(image); EXPECT_FALSE(bitmap1->isNull()); - EXPECT_EQ(1U, GetRepCount(image)); + EXPECT_EQ(1U, image.RepresentationCount()); EXPECT_TRUE(image.HasRepresentation(gfx::Image::kSkBitmapRep)); if (!kUsesSkiaNatively) @@ -76,11 +72,11 @@ TEST_F(ImageTest, SkiaToPlatform) { EXPECT_FALSE(image.HasRepresentation(gt::GetPlatformRepresentationType())); EXPECT_TRUE(static_cast<gt::PlatformImage>(image)); - EXPECT_EQ(kRepCount, GetRepCount(image)); + EXPECT_EQ(kRepCount, image.RepresentationCount()); const SkBitmap& bitmap = static_cast<const SkBitmap&>(image); EXPECT_FALSE(bitmap.isNull()); - EXPECT_EQ(kRepCount, GetRepCount(image)); + EXPECT_EQ(kRepCount, image.RepresentationCount()); EXPECT_TRUE(image.HasRepresentation(gfx::Image::kSkBitmapRep)); EXPECT_TRUE(image.HasRepresentation(gt::GetPlatformRepresentationType())); @@ -97,10 +93,10 @@ TEST_F(ImageTest, PlatformToSkia) { const SkBitmap* bitmap = static_cast<const SkBitmap*>(image); EXPECT_TRUE(bitmap); EXPECT_FALSE(bitmap->isNull()); - EXPECT_EQ(kRepCount, GetRepCount(image)); + EXPECT_EQ(kRepCount, image.RepresentationCount()); EXPECT_TRUE(static_cast<gt::PlatformImage>(image)); - EXPECT_EQ(kRepCount, GetRepCount(image)); + EXPECT_EQ(kRepCount, image.RepresentationCount()); EXPECT_TRUE(image.HasRepresentation(gfx::Image::kSkBitmapRep)); } @@ -108,11 +104,11 @@ TEST_F(ImageTest, PlatformToSkia) { TEST_F(ImageTest, PlatformToPlatform) { gfx::Image image(gt::CreatePlatformImage()); EXPECT_TRUE(static_cast<gt::PlatformImage>(image)); - EXPECT_EQ(1U, GetRepCount(image)); + EXPECT_EQ(1U, image.RepresentationCount()); // Make sure double conversion doesn't happen. EXPECT_TRUE(static_cast<gt::PlatformImage>(image)); - EXPECT_EQ(1U, GetRepCount(image)); + EXPECT_EQ(1U, image.RepresentationCount()); EXPECT_TRUE(image.HasRepresentation(gt::GetPlatformRepresentationType())); if (!kUsesSkiaNatively) @@ -133,20 +129,46 @@ TEST_F(ImageTest, SwapRepresentations) { gfx::Image image1(gt::CreateBitmap()); const SkBitmap* bitmap1 = image1; - EXPECT_EQ(1U, GetRepCount(image1)); + EXPECT_EQ(1U, image1.RepresentationCount()); gfx::Image image2(gt::CreatePlatformImage()); const SkBitmap* bitmap2 = image2; gt::PlatformImage platform_image = static_cast<gt::PlatformImage>(image2); - EXPECT_EQ(kRepCount, GetRepCount(image2)); + EXPECT_EQ(kRepCount, image2.RepresentationCount()); image1.SwapRepresentations(&image2); EXPECT_EQ(bitmap2, static_cast<const SkBitmap*>(image1)); EXPECT_EQ(platform_image, static_cast<gt::PlatformImage>(image1)); EXPECT_EQ(bitmap1, static_cast<const SkBitmap*>(image2)); - EXPECT_EQ(kRepCount, GetRepCount(image1)); - EXPECT_EQ(1U, GetRepCount(image2)); + EXPECT_EQ(kRepCount, image1.RepresentationCount()); + EXPECT_EQ(1U, image2.RepresentationCount()); +} + +TEST_F(ImageTest, Copy) { + const size_t kRepCount = kUsesSkiaNatively ? 1U : 2U; + + gfx::Image image1(gt::CreateBitmap()); + gfx::Image image2(image1); + + EXPECT_EQ(1U, image1.RepresentationCount()); + EXPECT_EQ(1U, image2.RepresentationCount()); + EXPECT_EQ(static_cast<const SkBitmap*>(image1), + static_cast<const SkBitmap*>(image2)); + + EXPECT_TRUE(static_cast<gt::PlatformImage>(image2)); + EXPECT_EQ(kRepCount, image2.RepresentationCount()); + EXPECT_EQ(kRepCount, image1.RepresentationCount()); +} + +TEST_F(ImageTest, Assign) { + gfx::Image image1(gt::CreatePlatformImage()); + gfx::Image image2 = image1; + + EXPECT_EQ(1U, image1.RepresentationCount()); + EXPECT_EQ(1U, image2.RepresentationCount()); + EXPECT_EQ(static_cast<const SkBitmap*>(image1), + static_cast<const SkBitmap*>(image2)); } // Integration tests with UI toolkit frameworks require linking against the |