summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-22 01:08:51 +0000
committerrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-22 01:08:51 +0000
commit8779d8bd47ddd9893809e73a9a552a0b463e3188 (patch)
treeaf4c18d2146edcb2f55013c472867a5a2d4b7dbf
parent7c719877de70f70a25d0549671603728d8dc8f77 (diff)
downloadchromium_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.cc81
-rw-r--r--ui/gfx/image.h34
-rw-r--r--ui/gfx/image_unittest.cc58
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