diff options
author | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-11 17:42:28 +0000 |
---|---|---|
committer | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-02-11 17:42:28 +0000 |
commit | 40a080e65b4205fc5f75dbbe43ca033a5a9664bd (patch) | |
tree | 188eb7f12d1dcd17238507d307539d18f52c6448 /ui/gfx/image.cc | |
parent | d98dfa02191fbe47c1104b1129293b29f6600e87 (diff) | |
download | chromium_src-40a080e65b4205fc5f75dbbe43ca033a5a9664bd.zip chromium_src-40a080e65b4205fc5f75dbbe43ca033a5a9664bd.tar.gz chromium_src-40a080e65b4205fc5f75dbbe43ca033a5a9664bd.tar.bz2 |
Add ui::gfx::Image to eventually replace gfx::ScopedImage.
This achieves the same goal as ScopedImage, namely encapsulating the memory
management of any image type. But ui::gfx::Image goes further by providing
conversion helpers between different image types.
BUG=carnitas
TEST=gfx_unittests and unit_tests
Review URL: http://codereview.chromium.org/6312159
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@74624 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui/gfx/image.cc')
-rw-r--r-- | ui/gfx/image.cc | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/ui/gfx/image.cc b/ui/gfx/image.cc new file mode 100644 index 0000000..6eac4c0 --- /dev/null +++ b/ui/gfx/image.cc @@ -0,0 +1,281 @@ +// 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.h" + +#include "base/logging.h" + +#if defined(OS_LINUX) +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <glib-object.h> +#include "ui/gfx/canvas_skia.h" +#include "ui/gfx/gtk_util.h" +#elif defined(OS_MACOSX) +#include "base/mac/mac_util.h" +#include "skia/ext/skia_utils_mac.h" +#endif + +namespace ui { +namespace gfx { + +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. +const SkBitmap* NSImageToSkBitmap(NSImage* image); +#endif + +#if defined(OS_LINUX) +const SkBitmap* GdkPixbufToSkBitmap(GdkPixbuf* pixbuf) { + ::gfx::CanvasSkia canvas(gdk_pixbuf_get_width(pixbuf), + gdk_pixbuf_get_height(pixbuf), + false); + canvas.DrawGdkPixbuf(pixbuf, 0, 0); + return new SkBitmap(canvas.ExtractBitmap()); +} +#endif + +class SkBitmapRep; +class GdkPixbufRep; +class NSImageRep; + +// An ImageRep is the object that holds the backing memory for an Image. Each +// RepresentationType has an ImageRep subclass that is responsible for freeing +// the memory that the ImageRep holds. When an ImageRep is created, it expects +// to take ownership of the image, without having to retain it or increase its +// reference count. +class ImageRep { + public: + explicit ImageRep(Image::RepresentationType rep) : type_(rep) {} + + // Deletes the associated pixels of an ImageRep. + virtual ~ImageRep() {} + + // Cast helpers ("fake RTTI"). + SkBitmapRep* AsSkBitmapRep() { + CHECK_EQ(type_, Image::kSkBitmapRep); + return reinterpret_cast<SkBitmapRep*>(this); + } + +#if defined(OS_LINUX) + GdkPixbufRep* AsGdkPixbufRep() { + CHECK_EQ(type_, Image::kGdkPixbufRep); + return reinterpret_cast<GdkPixbufRep*>(this); + } +#endif + +#if defined(OS_MACOSX) + NSImageRep* AsNSImageRep() { + CHECK_EQ(type_, Image::kNSImageRep); + return reinterpret_cast<NSImageRep*>(this); + } +#endif + + Image::RepresentationType type() const { return type_; } + + private: + Image::RepresentationType type_; +}; + +class SkBitmapRep : public ImageRep { + public: + explicit SkBitmapRep(const SkBitmap* bitmap) + : ImageRep(Image::kSkBitmapRep), + bitmap_(bitmap) { + CHECK(bitmap); + } + + virtual ~SkBitmapRep() { + delete bitmap_; + bitmap_ = NULL; + } + + const SkBitmap* bitmap() const { return bitmap_; } + + private: + const SkBitmap* bitmap_; + + DISALLOW_COPY_AND_ASSIGN(SkBitmapRep); +}; + +#if defined(OS_LINUX) +class GdkPixbufRep : public ImageRep { + public: + explicit GdkPixbufRep(GdkPixbuf* pixbuf) + : ImageRep(Image::kGdkPixbufRep), + pixbuf_(pixbuf) { + CHECK(pixbuf); + } + + virtual ~GdkPixbufRep() { + if (pixbuf_) { + g_object_unref(pixbuf_); + pixbuf_ = NULL; + } + } + + GdkPixbuf* pixbuf() const { return pixbuf_; } + + private: + GdkPixbuf* pixbuf_; + + DISALLOW_COPY_AND_ASSIGN(GdkPixbufRep); +}; +#endif + +#if defined(OS_MACOSX) +class NSImageRep : public ImageRep { + public: + explicit NSImageRep(NSImage* image) + : ImageRep(Image::kNSImageRep), + image_(image) { + CHECK(image); + } + + virtual ~NSImageRep() { + base::mac::NSObjectRelease(image_); + image_ = nil; + } + + NSImage* image() const { return image_; } + + private: + NSImage* image_; + + DISALLOW_COPY_AND_ASSIGN(NSImageRep); +}; +#endif + +} // namespace internal + +Image::Image(const SkBitmap* bitmap) + : default_representation_(Image::kSkBitmapRep) { + internal::SkBitmapRep* rep = new internal::SkBitmapRep(bitmap); + AddRepresentation(rep); +} + +#if defined(OS_LINUX) +Image::Image(GdkPixbuf* pixbuf) + : default_representation_(Image::kGdkPixbufRep) { + internal::GdkPixbufRep* rep = new internal::GdkPixbufRep(pixbuf); + AddRepresentation(rep); +} +#endif + +#if defined(OS_MACOSX) +Image::Image(NSImage* image) : default_representation_(Image::kNSImageRep) { + internal::NSImageRep* rep = new internal::NSImageRep(image); + AddRepresentation(rep); +} +#endif + +Image::~Image() { + for (RepresentationMap::iterator it = representations_.begin(); + it != representations_.end(); ++it) { + delete it->second; + } + representations_.clear(); +} + +Image::operator const SkBitmap*() { + internal::ImageRep* rep = GetRepresentation(Image::kSkBitmapRep); + return rep->AsSkBitmapRep()->bitmap(); +} + +Image::operator const SkBitmap&() { + return *(this->operator const SkBitmap*()); +} + +#if defined(OS_LINUX) +Image::operator GdkPixbuf*() { + internal::ImageRep* rep = GetRepresentation(Image::kGdkPixbufRep); + return rep->AsGdkPixbufRep()->pixbuf(); +} +#endif + +#if defined(OS_MACOSX) +Image::operator NSImage*() { + internal::ImageRep* rep = GetRepresentation(Image::kNSImageRep); + return rep->AsNSImageRep()->image(); +} +#endif + +internal::ImageRep* Image::DefaultRepresentation() { + RepresentationMap::iterator it = + representations_.find(default_representation_); + 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_) + return default_rep; + + // Check to see if the representation already exists. + RepresentationMap::iterator it = representations_.find(rep_type); + if (it != representations_.end()) + return it->second; + + // At this point, the requested rep does not exist, so it must be converted + // from the default rep. + + // Handle native-to-Skia conversion. + if (rep_type == Image::kSkBitmapRep) { + internal::SkBitmapRep* rep = NULL; +#if defined(OS_LINUX) + if (default_representation_ == 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) { + internal::NSImageRep* nsimage_rep = default_rep->AsNSImageRep(); + rep = new internal::SkBitmapRep( + internal::NSImageToSkBitmap(nsimage_rep->image())); + } +#endif + if (rep) { + AddRepresentation(rep); + return rep; + } + NOTREACHED(); + } + + // Handle Skia-to-native conversions. + if (default_rep->type() == Image::kSkBitmapRep) { + internal::SkBitmapRep* skia_rep = default_rep->AsSkBitmapRep(); + internal::ImageRep* native_rep = NULL; +#if defined(OS_LINUX) + if (rep_type == Image::kGdkPixbufRep) { + GdkPixbuf* pixbuf = ::gfx::GdkPixbufFromSkBitmap(skia_rep->bitmap()); + native_rep = new internal::GdkPixbufRep(pixbuf); + } +#elif defined(OS_MACOSX) + if (rep_type == Image::kNSImageRep) { + NSImage* image = ::gfx::SkBitmapToNSImage(*(skia_rep->bitmap())); + base::mac::NSObjectRetain(image); + native_rep = new internal::NSImageRep(image); + } +#endif + if (native_rep) { + AddRepresentation(native_rep); + return native_rep; + } + NOTREACHED(); + } + + // Something went seriously wrong... + return NULL; +} + +void Image::AddRepresentation(internal::ImageRep* rep) { + representations_.insert(std::make_pair(rep->type(), rep)); +} + +} // namespace gfx +} // namespace ui |