Home | History | Annotate | Download | only in image
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "ui/gfx/image/image.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/logging.h"
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/stl_util.h"
     12 #include "third_party/skia/include/core/SkBitmap.h"
     13 #include "ui/gfx/image/image_png_rep.h"
     14 #include "ui/gfx/image/image_skia.h"
     15 #include "ui/gfx/size.h"
     16 
     17 #if !defined(OS_IOS)
     18 #include "ui/gfx/codec/png_codec.h"
     19 #endif
     20 
     21 #if defined(TOOLKIT_GTK)
     22 #include <gdk-pixbuf/gdk-pixbuf.h>
     23 #include <gdk/gdk.h>
     24 #include <glib-object.h>
     25 #include "ui/base/gtk/scoped_gobject.h"
     26 #include "ui/gfx/canvas.h"
     27 #include "ui/gfx/gtk_util.h"
     28 #include "ui/gfx/image/cairo_cached_surface.h"
     29 #elif defined(OS_IOS)
     30 #include "base/mac/foundation_util.h"
     31 #include "ui/gfx/image/image_skia_util_ios.h"
     32 #elif defined(OS_MACOSX)
     33 #include "base/mac/mac_util.h"
     34 #include "ui/gfx/image/image_skia_util_mac.h"
     35 #endif
     36 
     37 namespace gfx {
     38 
     39 namespace internal {
     40 
     41 #if defined(TOOLKIT_GTK)
     42 const ImageSkia ImageSkiaFromGdkPixbuf(GdkPixbuf* pixbuf) {
     43   CHECK(pixbuf);
     44   gfx::Canvas canvas(gfx::Size(gdk_pixbuf_get_width(pixbuf),
     45                                gdk_pixbuf_get_height(pixbuf)),
     46                      ui::SCALE_FACTOR_100P,
     47                      false);
     48   skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas());
     49   cairo_t* cr = scoped_platform_paint.GetPlatformSurface();
     50   gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
     51   cairo_paint(cr);
     52   return ImageSkia(canvas.ExtractImageRep());
     53 }
     54 
     55 // Returns a 16x16 red pixbuf to visually show error in decoding PNG.
     56 // Also logs error to console.
     57 GdkPixbuf* GetErrorPixbuf() {
     58   LOG(ERROR) << "Unable to decode PNG.";
     59   GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 16, 16);
     60   gdk_pixbuf_fill(pixbuf, 0xff0000ff);
     61   return pixbuf;
     62 }
     63 
     64 GdkPixbuf* GdkPixbufFromPNG(
     65     const std::vector<gfx::ImagePNGRep>& image_png_reps) {
     66   scoped_refptr<base::RefCountedMemory> png_bytes(NULL);
     67   for (size_t i = 0; i < image_png_reps.size(); ++i) {
     68     if (image_png_reps[i].scale_factor == ui::SCALE_FACTOR_100P)
     69       png_bytes = image_png_reps[i].raw_data;
     70   }
     71 
     72   if (!png_bytes.get())
     73     return GetErrorPixbuf();
     74 
     75   GdkPixbuf* pixbuf = NULL;
     76   ui::ScopedGObject<GdkPixbufLoader>::Type loader(gdk_pixbuf_loader_new());
     77 
     78   bool ok = gdk_pixbuf_loader_write(loader.get(),
     79       reinterpret_cast<const guint8*>(png_bytes->front()), png_bytes->size(),
     80       NULL);
     81 
     82   // Calling gdk_pixbuf_loader_close forces the data to be parsed by the
     83   // loader. This must be done before calling gdk_pixbuf_loader_get_pixbuf.
     84   if (ok)
     85     ok = gdk_pixbuf_loader_close(loader.get(), NULL);
     86   if (ok)
     87     pixbuf = gdk_pixbuf_loader_get_pixbuf(loader.get());
     88 
     89   if (pixbuf) {
     90     // The pixbuf is owned by the scoped loader which will delete its ref when
     91     // it goes out of scope. Add a ref so that the pixbuf still exists.
     92     g_object_ref(pixbuf);
     93   } else {
     94     return GetErrorPixbuf();
     95   }
     96 
     97   return pixbuf;
     98 }
     99 
    100 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromPixbuf(
    101     GdkPixbuf* pixbuf) {
    102   gchar* image = NULL;
    103   gsize image_size;
    104   GError* error = NULL;
    105   CHECK(gdk_pixbuf_save_to_buffer(
    106       pixbuf, &image, &image_size, "png", &error, NULL));
    107   scoped_refptr<base::RefCountedBytes> png_bytes(
    108       new base::RefCountedBytes());
    109   png_bytes->data().assign(image, image + image_size);
    110   g_free(image);
    111   return png_bytes;
    112 }
    113 
    114 #endif // defined(TOOLKIT_GTK)
    115 
    116 #if defined(OS_IOS)
    117 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromUIImage(
    118     UIImage* uiimage);
    119 // Caller takes ownership of the returned UIImage.
    120 UIImage* CreateUIImageFromPNG(
    121     const std::vector<gfx::ImagePNGRep>& image_png_reps);
    122 gfx::Size UIImageSize(UIImage* image);
    123 #elif defined(OS_MACOSX)
    124 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromNSImage(
    125     NSImage* nsimage);
    126 // Caller takes ownership of the returned NSImage.
    127 NSImage* NSImageFromPNG(const std::vector<gfx::ImagePNGRep>& image_png_reps,
    128                         CGColorSpaceRef color_space);
    129 gfx::Size NSImageSize(NSImage* image);
    130 #endif // defined(OS_MACOSX)
    131 
    132 #if defined(OS_IOS)
    133 ImageSkia* ImageSkiaFromPNG(
    134     const std::vector<gfx::ImagePNGRep>& image_png_reps);
    135 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
    136     const ImageSkia* skia);
    137 #else
    138 // Returns a 16x16 red image to visually show error in decoding PNG.
    139 // Caller takes ownership of returned ImageSkia.
    140 ImageSkia* GetErrorImageSkia() {
    141   SkBitmap bitmap;
    142   bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
    143   bitmap.allocPixels();
    144   bitmap.eraseRGB(0xff, 0, 0);
    145   return new gfx::ImageSkia(gfx::ImageSkiaRep(bitmap, ui::SCALE_FACTOR_100P));
    146 }
    147 
    148 ImageSkia* ImageSkiaFromPNG(
    149     const std::vector<gfx::ImagePNGRep>& image_png_reps) {
    150   if (image_png_reps.empty())
    151     return GetErrorImageSkia();
    152 
    153   scoped_ptr<gfx::ImageSkia> image_skia(new ImageSkia());
    154   for (size_t i = 0; i < image_png_reps.size(); ++i) {
    155     scoped_refptr<base::RefCountedMemory> raw_data =
    156         image_png_reps[i].raw_data;
    157     CHECK(raw_data.get());
    158     SkBitmap bitmap;
    159     if (!gfx::PNGCodec::Decode(raw_data->front(), raw_data->size(),
    160                                &bitmap)) {
    161       LOG(ERROR) << "Unable to decode PNG for "
    162                  << ui::GetScaleFactorScale(image_png_reps[i].scale_factor)
    163                  << ".";
    164       return GetErrorImageSkia();
    165     }
    166     image_skia->AddRepresentation(gfx::ImageSkiaRep(
    167         bitmap, image_png_reps[i].scale_factor));
    168   }
    169   return image_skia.release();
    170 }
    171 
    172 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
    173     const ImageSkia* image_skia) {
    174   ImageSkiaRep image_skia_rep = image_skia->GetRepresentation(
    175       ui::SCALE_FACTOR_100P);
    176 
    177   scoped_refptr<base::RefCountedBytes> png_bytes(new base::RefCountedBytes());
    178   if (image_skia_rep.scale_factor() != ui::SCALE_FACTOR_100P ||
    179       !gfx::PNGCodec::EncodeBGRASkBitmap(image_skia_rep.sk_bitmap(), false,
    180           &png_bytes->data())) {
    181     return NULL;
    182   }
    183   return png_bytes;
    184 }
    185 #endif
    186 
    187 class ImageRepPNG;
    188 class ImageRepSkia;
    189 class ImageRepGdk;
    190 class ImageRepCairo;
    191 class ImageRepCocoa;
    192 class ImageRepCocoaTouch;
    193 
    194 // An ImageRep is the object that holds the backing memory for an Image. Each
    195 // RepresentationType has an ImageRep subclass that is responsible for freeing
    196 // the memory that the ImageRep holds. When an ImageRep is created, it expects
    197 // to take ownership of the image, without having to retain it or increase its
    198 // reference count.
    199 class ImageRep {
    200  public:
    201   explicit ImageRep(Image::RepresentationType rep) : type_(rep) {}
    202 
    203   // Deletes the associated pixels of an ImageRep.
    204   virtual ~ImageRep() {}
    205 
    206   // Cast helpers ("fake RTTI").
    207   ImageRepPNG* AsImageRepPNG() {
    208     CHECK_EQ(type_, Image::kImageRepPNG);
    209     return reinterpret_cast<ImageRepPNG*>(this);
    210   }
    211 
    212   ImageRepSkia* AsImageRepSkia() {
    213     CHECK_EQ(type_, Image::kImageRepSkia);
    214     return reinterpret_cast<ImageRepSkia*>(this);
    215   }
    216 
    217 #if defined(TOOLKIT_GTK)
    218   ImageRepGdk* AsImageRepGdk() {
    219     CHECK_EQ(type_, Image::kImageRepGdk);
    220     return reinterpret_cast<ImageRepGdk*>(this);
    221   }
    222 
    223   ImageRepCairo* AsImageRepCairo() {
    224     CHECK_EQ(type_, Image::kImageRepCairo);
    225     return reinterpret_cast<ImageRepCairo*>(this);
    226   }
    227 #endif
    228 
    229 #if defined(OS_IOS)
    230   ImageRepCocoaTouch* AsImageRepCocoaTouch() {
    231     CHECK_EQ(type_, Image::kImageRepCocoaTouch);
    232     return reinterpret_cast<ImageRepCocoaTouch*>(this);
    233   }
    234 #elif defined(OS_MACOSX)
    235   ImageRepCocoa* AsImageRepCocoa() {
    236     CHECK_EQ(type_, Image::kImageRepCocoa);
    237     return reinterpret_cast<ImageRepCocoa*>(this);
    238   }
    239 #endif
    240 
    241   Image::RepresentationType type() const { return type_; }
    242 
    243   virtual int Width() const = 0;
    244   virtual int Height() const = 0;
    245   virtual gfx::Size Size() const = 0;
    246 
    247  private:
    248   Image::RepresentationType type_;
    249 };
    250 
    251 class ImageRepPNG : public ImageRep {
    252  public:
    253   ImageRepPNG() : ImageRep(Image::kImageRepPNG) {
    254   }
    255 
    256   ImageRepPNG(const std::vector<ImagePNGRep>& image_png_reps)
    257       : ImageRep(Image::kImageRepPNG),
    258         image_png_reps_(image_png_reps) {
    259   }
    260 
    261   virtual ~ImageRepPNG() {
    262   }
    263 
    264   virtual int Width() const OVERRIDE {
    265     return Size().width();
    266   }
    267 
    268   virtual int Height() const OVERRIDE {
    269     return Size().height();
    270   }
    271 
    272   virtual gfx::Size Size() const OVERRIDE {
    273     // Read the PNG data to get the image size, caching it.
    274     if (!size_cache_) {
    275       for (std::vector<ImagePNGRep>::const_iterator it = image_reps().begin();
    276            it != image_reps().end(); ++it) {
    277         if (it->scale_factor == ui::SCALE_FACTOR_100P) {
    278           size_cache_.reset(new gfx::Size(it->Size()));
    279           return *size_cache_;
    280         }
    281       }
    282       size_cache_.reset(new gfx::Size);
    283     }
    284 
    285     return *size_cache_;
    286   }
    287 
    288   const std::vector<ImagePNGRep>& image_reps() const { return image_png_reps_; }
    289 
    290  private:
    291   std::vector<ImagePNGRep> image_png_reps_;
    292 
    293   // Cached to avoid having to parse the raw data multiple times.
    294   mutable scoped_ptr<gfx::Size> size_cache_;
    295 
    296   DISALLOW_COPY_AND_ASSIGN(ImageRepPNG);
    297 };
    298 
    299 class ImageRepSkia : public ImageRep {
    300  public:
    301   // Takes ownership of |image|.
    302   explicit ImageRepSkia(ImageSkia* image)
    303       : ImageRep(Image::kImageRepSkia),
    304         image_(image) {
    305   }
    306 
    307   virtual ~ImageRepSkia() {
    308   }
    309 
    310   virtual int Width() const OVERRIDE {
    311     return image_->width();
    312   }
    313 
    314   virtual int Height() const OVERRIDE {
    315     return image_->height();
    316   }
    317 
    318   virtual gfx::Size Size() const OVERRIDE {
    319     return image_->size();
    320   }
    321 
    322   ImageSkia* image() { return image_.get(); }
    323 
    324  private:
    325   scoped_ptr<ImageSkia> image_;
    326 
    327   DISALLOW_COPY_AND_ASSIGN(ImageRepSkia);
    328 };
    329 
    330 #if defined(TOOLKIT_GTK)
    331 class ImageRepGdk : public ImageRep {
    332  public:
    333   explicit ImageRepGdk(GdkPixbuf* pixbuf)
    334       : ImageRep(Image::kImageRepGdk),
    335         pixbuf_(pixbuf) {
    336     CHECK(pixbuf);
    337   }
    338 
    339   virtual ~ImageRepGdk() {
    340     if (pixbuf_) {
    341       g_object_unref(pixbuf_);
    342       pixbuf_ = NULL;
    343     }
    344   }
    345 
    346   virtual int Width() const OVERRIDE {
    347     return gdk_pixbuf_get_width(pixbuf_);
    348   }
    349 
    350   virtual int Height() const OVERRIDE {
    351     return gdk_pixbuf_get_height(pixbuf_);
    352   }
    353 
    354   virtual gfx::Size Size() const OVERRIDE {
    355     return gfx::Size(Width(), Height());
    356   }
    357 
    358   GdkPixbuf* pixbuf() const { return pixbuf_; }
    359 
    360  private:
    361   GdkPixbuf* pixbuf_;
    362 
    363   DISALLOW_COPY_AND_ASSIGN(ImageRepGdk);
    364 };
    365 
    366 // Represents data that lives on the display server instead of in the client.
    367 class ImageRepCairo : public ImageRep {
    368  public:
    369   explicit ImageRepCairo(GdkPixbuf* pixbuf)
    370       : ImageRep(Image::kImageRepCairo),
    371         cairo_cache_(new CairoCachedSurface) {
    372     CHECK(pixbuf);
    373     cairo_cache_->UsePixbuf(pixbuf);
    374   }
    375 
    376   virtual ~ImageRepCairo() {
    377     delete cairo_cache_;
    378   }
    379 
    380   virtual int Width() const OVERRIDE {
    381     return cairo_cache_->Width();
    382   }
    383 
    384   virtual int Height() const OVERRIDE {
    385     return cairo_cache_->Height();
    386   }
    387 
    388   virtual gfx::Size Size() const OVERRIDE {
    389     return gfx::Size(Width(), Height());
    390   }
    391 
    392   CairoCachedSurface* surface() const { return cairo_cache_; }
    393 
    394  private:
    395   CairoCachedSurface* cairo_cache_;
    396 
    397   DISALLOW_COPY_AND_ASSIGN(ImageRepCairo);
    398 };
    399 #endif  // defined(TOOLKIT_GTK)
    400 
    401 #if defined(OS_IOS)
    402 class ImageRepCocoaTouch : public ImageRep {
    403  public:
    404   explicit ImageRepCocoaTouch(UIImage* image)
    405       : ImageRep(Image::kImageRepCocoaTouch),
    406         image_(image) {
    407     CHECK(image);
    408   }
    409 
    410   virtual ~ImageRepCocoaTouch() {
    411     base::mac::NSObjectRelease(image_);
    412     image_ = nil;
    413   }
    414 
    415   virtual int Width() const OVERRIDE {
    416     return Size().width();
    417   }
    418 
    419   virtual int Height() const OVERRIDE {
    420     return Size().height();
    421   }
    422 
    423   virtual gfx::Size Size() const OVERRIDE {
    424     return internal::UIImageSize(image_);
    425   }
    426 
    427   UIImage* image() const { return image_; }
    428 
    429  private:
    430   UIImage* image_;
    431 
    432   DISALLOW_COPY_AND_ASSIGN(ImageRepCocoaTouch);
    433 };
    434 #elif defined(OS_MACOSX)
    435 class ImageRepCocoa : public ImageRep {
    436  public:
    437   explicit ImageRepCocoa(NSImage* image)
    438       : ImageRep(Image::kImageRepCocoa),
    439         image_(image) {
    440     CHECK(image);
    441   }
    442 
    443   virtual ~ImageRepCocoa() {
    444     base::mac::NSObjectRelease(image_);
    445     image_ = nil;
    446   }
    447 
    448   virtual int Width() const OVERRIDE {
    449     return Size().width();
    450   }
    451 
    452   virtual int Height() const OVERRIDE {
    453     return Size().height();
    454   }
    455 
    456   virtual gfx::Size Size() const OVERRIDE {
    457     return internal::NSImageSize(image_);
    458   }
    459 
    460   NSImage* image() const { return image_; }
    461 
    462  private:
    463   NSImage* image_;
    464 
    465   DISALLOW_COPY_AND_ASSIGN(ImageRepCocoa);
    466 };
    467 #endif  // defined(OS_MACOSX)
    468 
    469 // The Storage class acts similarly to the pixels in a SkBitmap: the Image
    470 // class holds a refptr instance of Storage, which in turn holds all the
    471 // ImageReps. This way, the Image can be cheaply copied.
    472 class ImageStorage : public base::RefCounted<ImageStorage> {
    473  public:
    474   ImageStorage(gfx::Image::RepresentationType default_type)
    475       : default_representation_type_(default_type),
    476 #if defined(OS_MACOSX) && !defined(OS_IOS)
    477         default_representation_color_space_(
    478             base::mac::GetGenericRGBColorSpace()),
    479 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    480         representations_deleter_(&representations_) {
    481   }
    482 
    483   gfx::Image::RepresentationType default_representation_type() {
    484     return default_representation_type_;
    485   }
    486   gfx::Image::RepresentationMap& representations() { return representations_; }
    487 
    488 #if defined(OS_MACOSX) && !defined(OS_IOS)
    489   void set_default_representation_color_space(CGColorSpaceRef color_space) {
    490     default_representation_color_space_ = color_space;
    491   }
    492   CGColorSpaceRef default_representation_color_space() {
    493     return default_representation_color_space_;
    494   }
    495 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    496 
    497  private:
    498   friend class base::RefCounted<ImageStorage>;
    499 
    500   ~ImageStorage() {}
    501 
    502   // The type of image that was passed to the constructor. This key will always
    503   // exist in the |representations_| map.
    504   gfx::Image::RepresentationType default_representation_type_;
    505 
    506 #if defined(OS_MACOSX) && !defined(OS_IOS)
    507   // The default representation's colorspace. This is used for converting to
    508   // NSImage. This field exists to compensate for PNGCodec not writing or
    509   // reading colorspace ancillary chunks. (sRGB, iCCP).
    510   // Not owned.
    511   CGColorSpaceRef default_representation_color_space_;
    512 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    513 
    514   // All the representations of an Image. Size will always be at least one, with
    515   // more for any converted representations.
    516   gfx::Image::RepresentationMap representations_;
    517 
    518   STLValueDeleter<Image::RepresentationMap> representations_deleter_;
    519 
    520   DISALLOW_COPY_AND_ASSIGN(ImageStorage);
    521 };
    522 
    523 }  // namespace internal
    524 
    525 Image::Image() {
    526   // |storage_| is NULL for empty Images.
    527 }
    528 
    529 Image::Image(const std::vector<ImagePNGRep>& image_reps) {
    530   // Do not store obviously invalid ImagePNGReps.
    531   std::vector<ImagePNGRep> filtered;
    532   for (size_t i = 0; i < image_reps.size(); ++i) {
    533     if (image_reps[i].raw_data.get() && image_reps[i].raw_data->size())
    534       filtered.push_back(image_reps[i]);
    535   }
    536 
    537   if (filtered.empty())
    538     return;
    539 
    540   storage_ = new internal::ImageStorage(Image::kImageRepPNG);
    541   internal::ImageRepPNG* rep = new internal::ImageRepPNG(filtered);
    542   AddRepresentation(rep);
    543 }
    544 
    545 Image::Image(const ImageSkia& image) {
    546   if (!image.isNull()) {
    547     storage_ = new internal::ImageStorage(Image::kImageRepSkia);
    548     internal::ImageRepSkia* rep = new internal::ImageRepSkia(
    549         new ImageSkia(image));
    550     AddRepresentation(rep);
    551   }
    552 }
    553 
    554 #if defined(TOOLKIT_GTK)
    555 Image::Image(GdkPixbuf* pixbuf) {
    556   if (pixbuf) {
    557     storage_ = new internal::ImageStorage(Image::kImageRepGdk);
    558     internal::ImageRepGdk* rep = new internal::ImageRepGdk(pixbuf);
    559     AddRepresentation(rep);
    560   }
    561 }
    562 #endif
    563 
    564 #if defined(OS_IOS)
    565 Image::Image(UIImage* image)
    566     : storage_(new internal::ImageStorage(Image::kImageRepCocoaTouch)) {
    567   if (image) {
    568     internal::ImageRepCocoaTouch* rep = new internal::ImageRepCocoaTouch(image);
    569     AddRepresentation(rep);
    570   }
    571 }
    572 #elif defined(OS_MACOSX)
    573 Image::Image(NSImage* image) {
    574   if (image) {
    575     storage_ = new internal::ImageStorage(Image::kImageRepCocoa);
    576     internal::ImageRepCocoa* rep = new internal::ImageRepCocoa(image);
    577     AddRepresentation(rep);
    578   }
    579 }
    580 #endif
    581 
    582 Image::Image(const Image& other) : storage_(other.storage_) {
    583 }
    584 
    585 Image& Image::operator=(const Image& other) {
    586   storage_ = other.storage_;
    587   return *this;
    588 }
    589 
    590 Image::~Image() {
    591 }
    592 
    593 // static
    594 Image Image::CreateFrom1xBitmap(const SkBitmap& bitmap) {
    595   return gfx::Image(ImageSkia::CreateFrom1xBitmap(bitmap));
    596 }
    597 
    598 // static
    599 Image Image::CreateFrom1xPNGBytes(const unsigned char* input,
    600                                   size_t input_size) {
    601   if (input_size == 0u)
    602     return gfx::Image();
    603 
    604   scoped_refptr<base::RefCountedBytes> raw_data(new base::RefCountedBytes());
    605   raw_data->data().assign(input, input + input_size);
    606   std::vector<gfx::ImagePNGRep> image_reps;
    607   image_reps.push_back(ImagePNGRep(raw_data, ui::SCALE_FACTOR_100P));
    608   return gfx::Image(image_reps);
    609 }
    610 
    611 const SkBitmap* Image::ToSkBitmap() const {
    612   // Possibly create and cache an intermediate ImageRepSkia.
    613   return ToImageSkia()->bitmap();
    614 }
    615 
    616 const ImageSkia* Image::ToImageSkia() const {
    617   internal::ImageRep* rep = GetRepresentation(kImageRepSkia, false);
    618   if (!rep) {
    619     switch (DefaultRepresentationType()) {
    620       case kImageRepPNG: {
    621         internal::ImageRepPNG* png_rep =
    622             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
    623         rep = new internal::ImageRepSkia(
    624             internal::ImageSkiaFromPNG(png_rep->image_reps()));
    625         break;
    626       }
    627 #if defined(TOOLKIT_GTK)
    628       case kImageRepGdk: {
    629         internal::ImageRepGdk* native_rep =
    630             GetRepresentation(kImageRepGdk, true)->AsImageRepGdk();
    631         rep = new internal::ImageRepSkia(new ImageSkia(
    632             internal::ImageSkiaFromGdkPixbuf(native_rep->pixbuf())));
    633         break;
    634       }
    635 #elif defined(OS_IOS)
    636       case kImageRepCocoaTouch: {
    637         internal::ImageRepCocoaTouch* native_rep =
    638             GetRepresentation(kImageRepCocoaTouch, true)
    639                 ->AsImageRepCocoaTouch();
    640         rep = new internal::ImageRepSkia(new ImageSkia(
    641             ImageSkiaFromUIImage(native_rep->image())));
    642         break;
    643       }
    644 #elif defined(OS_MACOSX)
    645       case kImageRepCocoa: {
    646         internal::ImageRepCocoa* native_rep =
    647             GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
    648         rep = new internal::ImageRepSkia(new ImageSkia(
    649             ImageSkiaFromNSImage(native_rep->image())));
    650         break;
    651       }
    652 #endif
    653       default:
    654         NOTREACHED();
    655     }
    656     CHECK(rep);
    657     AddRepresentation(rep);
    658   }
    659   return rep->AsImageRepSkia()->image();
    660 }
    661 
    662 #if defined(TOOLKIT_GTK)
    663 GdkPixbuf* Image::ToGdkPixbuf() const {
    664   internal::ImageRep* rep = GetRepresentation(kImageRepGdk, false);
    665   if (!rep) {
    666     switch (DefaultRepresentationType()) {
    667       case kImageRepPNG: {
    668         internal::ImageRepPNG* png_rep =
    669             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
    670         rep = new internal::ImageRepGdk(internal::GdkPixbufFromPNG(
    671             png_rep->image_reps()));
    672         break;
    673       }
    674       case kImageRepSkia: {
    675         internal::ImageRepSkia* skia_rep =
    676             GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
    677         rep = new internal::ImageRepGdk(gfx::GdkPixbufFromSkBitmap(
    678             *skia_rep->image()->bitmap()));
    679         break;
    680       }
    681       default:
    682         NOTREACHED();
    683     }
    684     CHECK(rep);
    685     AddRepresentation(rep);
    686   }
    687   return rep->AsImageRepGdk()->pixbuf();
    688 }
    689 
    690 CairoCachedSurface* const Image::ToCairo() const {
    691   internal::ImageRep* rep = GetRepresentation(kImageRepCairo, false);
    692   if (!rep) {
    693     // Handle any-to-Cairo conversion. This may create and cache an intermediate
    694     // pixbuf before sending the data to the display server.
    695     rep = new internal::ImageRepCairo(ToGdkPixbuf());
    696     CHECK(rep);
    697     AddRepresentation(rep);
    698   }
    699   return rep->AsImageRepCairo()->surface();
    700 }
    701 #endif
    702 
    703 #if defined(OS_IOS)
    704 UIImage* Image::ToUIImage() const {
    705   internal::ImageRep* rep = GetRepresentation(kImageRepCocoaTouch, false);
    706   if (!rep) {
    707     switch (DefaultRepresentationType()) {
    708       case kImageRepPNG: {
    709         internal::ImageRepPNG* png_rep =
    710             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
    711         rep = new internal::ImageRepCocoaTouch(internal::CreateUIImageFromPNG(
    712             png_rep->image_reps()));
    713         break;
    714       }
    715       case kImageRepSkia: {
    716         internal::ImageRepSkia* skia_rep =
    717             GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
    718         UIImage* image = UIImageFromImageSkia(*skia_rep->image());
    719         base::mac::NSObjectRetain(image);
    720         rep = new internal::ImageRepCocoaTouch(image);
    721         break;
    722       }
    723       default:
    724         NOTREACHED();
    725     }
    726     CHECK(rep);
    727     AddRepresentation(rep);
    728   }
    729   return rep->AsImageRepCocoaTouch()->image();
    730 }
    731 #elif defined(OS_MACOSX)
    732 NSImage* Image::ToNSImage() const {
    733   internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false);
    734   if (!rep) {
    735     CGColorSpaceRef default_representation_color_space =
    736         storage_->default_representation_color_space();
    737 
    738     switch (DefaultRepresentationType()) {
    739       case kImageRepPNG: {
    740         internal::ImageRepPNG* png_rep =
    741             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
    742         rep = new internal::ImageRepCocoa(internal::NSImageFromPNG(
    743             png_rep->image_reps(), default_representation_color_space));
    744         break;
    745       }
    746       case kImageRepSkia: {
    747         internal::ImageRepSkia* skia_rep =
    748             GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
    749         NSImage* image = NSImageFromImageSkiaWithColorSpace(*skia_rep->image(),
    750             default_representation_color_space);
    751         base::mac::NSObjectRetain(image);
    752         rep = new internal::ImageRepCocoa(image);
    753         break;
    754       }
    755       default:
    756         NOTREACHED();
    757     }
    758     CHECK(rep);
    759     AddRepresentation(rep);
    760   }
    761   return rep->AsImageRepCocoa()->image();
    762 }
    763 #endif
    764 
    765 scoped_refptr<base::RefCountedMemory> Image::As1xPNGBytes() const {
    766   if (IsEmpty())
    767     return new base::RefCountedBytes();
    768 
    769   internal::ImageRep* rep = GetRepresentation(kImageRepPNG, false);
    770 
    771   if (rep) {
    772     const std::vector<gfx::ImagePNGRep>& image_png_reps =
    773         rep->AsImageRepPNG()->image_reps();
    774     for (size_t i = 0; i < image_png_reps.size(); ++i) {
    775       if (image_png_reps[i].scale_factor == ui::SCALE_FACTOR_100P)
    776         return image_png_reps[i].raw_data;
    777     }
    778     return new base::RefCountedBytes();
    779   }
    780 
    781   scoped_refptr<base::RefCountedMemory> png_bytes(NULL);
    782   switch (DefaultRepresentationType()) {
    783 #if defined(TOOLKIT_GTK)
    784     case kImageRepGdk: {
    785       internal::ImageRepGdk* gdk_rep =
    786           GetRepresentation(kImageRepGdk, true)->AsImageRepGdk();
    787       png_bytes = internal::Get1xPNGBytesFromPixbuf(gdk_rep->pixbuf());
    788       break;
    789     }
    790 #elif defined(OS_IOS)
    791     case kImageRepCocoaTouch: {
    792       internal::ImageRepCocoaTouch* cocoa_touch_rep =
    793           GetRepresentation(kImageRepCocoaTouch, true)
    794               ->AsImageRepCocoaTouch();
    795       png_bytes = internal::Get1xPNGBytesFromUIImage(
    796           cocoa_touch_rep->image());
    797       break;
    798     }
    799 #elif defined(OS_MACOSX)
    800     case kImageRepCocoa: {
    801       internal::ImageRepCocoa* cocoa_rep =
    802           GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
    803       png_bytes = internal::Get1xPNGBytesFromNSImage(cocoa_rep->image());
    804       break;
    805     }
    806 #endif
    807     case kImageRepSkia: {
    808       internal::ImageRepSkia* skia_rep =
    809           GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
    810       png_bytes = internal::Get1xPNGBytesFromImageSkia(skia_rep->image());
    811       break;
    812     }
    813     default:
    814       NOTREACHED();
    815   }
    816   if (!png_bytes.get() || !png_bytes->size()) {
    817     // Add an ImageRepPNG with no data such that the conversion is not
    818     // attempted each time we want the PNG bytes.
    819     AddRepresentation(new internal::ImageRepPNG());
    820     return new base::RefCountedBytes();
    821   }
    822 
    823   // Do not insert representations for scale factors other than 1x even if
    824   // they are available because:
    825   // - Only the 1x PNG bytes can be accessed.
    826   // - ImageRepPNG is not used as an intermediate type in converting to a
    827   //   final type eg (converting from ImageRepSkia to ImageRepPNG to get an
    828   //   ImageRepCocoa).
    829   std::vector<ImagePNGRep> image_png_reps;
    830   image_png_reps.push_back(gfx::ImagePNGRep(png_bytes,
    831                                             ui::SCALE_FACTOR_100P));
    832   rep = new internal::ImageRepPNG(image_png_reps);
    833   AddRepresentation(rep);
    834   return png_bytes;
    835 }
    836 
    837 SkBitmap Image::AsBitmap() const {
    838   return IsEmpty() ? SkBitmap() : *ToSkBitmap();
    839 }
    840 
    841 ImageSkia Image::AsImageSkia() const {
    842   return IsEmpty() ? ImageSkia() : *ToImageSkia();
    843 }
    844 
    845 #if defined(OS_MACOSX) && !defined(OS_IOS)
    846 NSImage* Image::AsNSImage() const {
    847   return IsEmpty() ? nil : ToNSImage();
    848 }
    849 #endif
    850 
    851 scoped_refptr<base::RefCountedMemory> Image::Copy1xPNGBytes() const {
    852   scoped_refptr<base::RefCountedMemory> original = As1xPNGBytes();
    853   scoped_refptr<base::RefCountedBytes> copy(new base::RefCountedBytes());
    854   copy->data().assign(original->front(), original->front() + original->size());
    855   return copy;
    856 }
    857 
    858 ImageSkia* Image::CopyImageSkia() const {
    859   return new ImageSkia(*ToImageSkia());
    860 }
    861 
    862 SkBitmap* Image::CopySkBitmap() const {
    863   return new SkBitmap(*ToSkBitmap());
    864 }
    865 
    866 #if defined(TOOLKIT_GTK)
    867 GdkPixbuf* Image::CopyGdkPixbuf() const {
    868   GdkPixbuf* pixbuf = ToGdkPixbuf();
    869   g_object_ref(pixbuf);
    870   return pixbuf;
    871 }
    872 #endif
    873 
    874 #if defined(OS_IOS)
    875 UIImage* Image::CopyUIImage() const {
    876   UIImage* image = ToUIImage();
    877   base::mac::NSObjectRetain(image);
    878   return image;
    879 }
    880 #elif defined(OS_MACOSX)
    881 NSImage* Image::CopyNSImage() const {
    882   NSImage* image = ToNSImage();
    883   base::mac::NSObjectRetain(image);
    884   return image;
    885 }
    886 #endif
    887 
    888 bool Image::HasRepresentation(RepresentationType type) const {
    889   return storage_.get() && storage_->representations().count(type) != 0;
    890 }
    891 
    892 size_t Image::RepresentationCount() const {
    893   if (!storage_.get())
    894     return 0;
    895 
    896   return storage_->representations().size();
    897 }
    898 
    899 bool Image::IsEmpty() const {
    900   return RepresentationCount() == 0;
    901 }
    902 
    903 int Image::Width() const {
    904   if (IsEmpty())
    905     return 0;
    906   return GetRepresentation(DefaultRepresentationType(), true)->Width();
    907 }
    908 
    909 int Image::Height() const {
    910   if (IsEmpty())
    911     return 0;
    912   return GetRepresentation(DefaultRepresentationType(), true)->Height();
    913 }
    914 
    915 gfx::Size Image::Size() const {
    916   if (IsEmpty())
    917     return gfx::Size();
    918   return GetRepresentation(DefaultRepresentationType(), true)->Size();
    919 }
    920 
    921 void Image::SwapRepresentations(gfx::Image* other) {
    922   storage_.swap(other->storage_);
    923 }
    924 
    925 #if defined(OS_MACOSX)  && !defined(OS_IOS)
    926 void Image::SetSourceColorSpace(CGColorSpaceRef color_space) {
    927   if (storage_.get())
    928     storage_->set_default_representation_color_space(color_space);
    929 }
    930 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    931 
    932 Image::RepresentationType Image::DefaultRepresentationType() const {
    933   CHECK(storage_.get());
    934   RepresentationType default_type = storage_->default_representation_type();
    935   // The conversions above assume that the default representation type is never
    936   // kImageRepCairo.
    937   DCHECK_NE(default_type, kImageRepCairo);
    938   return default_type;
    939 }
    940 
    941 internal::ImageRep* Image::GetRepresentation(
    942     RepresentationType rep_type, bool must_exist) const {
    943   CHECK(storage_.get());
    944   RepresentationMap::iterator it = storage_->representations().find(rep_type);
    945   if (it == storage_->representations().end()) {
    946     CHECK(!must_exist);
    947     return NULL;
    948   }
    949   return it->second;
    950 }
    951 
    952 void Image::AddRepresentation(internal::ImageRep* rep) const {
    953   CHECK(storage_.get());
    954   storage_->representations().insert(std::make_pair(rep->type(), rep));
    955 }
    956 
    957 }  // namespace gfx
    958