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 #include <set>
      9 
     10 #include "base/logging.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/stl_util.h"
     13 #include "third_party/skia/include/core/SkBitmap.h"
     14 #include "ui/gfx/image/image_png_rep.h"
     15 #include "ui/gfx/image/image_skia.h"
     16 #include "ui/gfx/image/image_skia_source.h"
     17 #include "ui/gfx/size.h"
     18 
     19 #if !defined(OS_IOS)
     20 #include "ui/gfx/codec/png_codec.h"
     21 #endif
     22 
     23 #if defined(OS_IOS)
     24 #include "base/mac/foundation_util.h"
     25 #include "ui/gfx/image/image_skia_util_ios.h"
     26 #elif defined(OS_MACOSX)
     27 #include "base/mac/mac_util.h"
     28 #include "ui/gfx/image/image_skia_util_mac.h"
     29 #endif
     30 
     31 namespace gfx {
     32 
     33 namespace internal {
     34 
     35 #if defined(OS_IOS)
     36 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromUIImage(
     37     UIImage* uiimage);
     38 // Caller takes ownership of the returned UIImage.
     39 UIImage* CreateUIImageFromPNG(
     40     const std::vector<ImagePNGRep>& image_png_reps);
     41 gfx::Size UIImageSize(UIImage* image);
     42 #elif defined(OS_MACOSX)
     43 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromNSImage(
     44     NSImage* nsimage);
     45 // Caller takes ownership of the returned NSImage.
     46 NSImage* NSImageFromPNG(const std::vector<ImagePNGRep>& image_png_reps,
     47                         CGColorSpaceRef color_space);
     48 gfx::Size NSImageSize(NSImage* image);
     49 #endif // defined(OS_MACOSX)
     50 
     51 #if defined(OS_IOS)
     52 ImageSkia* ImageSkiaFromPNG(
     53     const std::vector<ImagePNGRep>& image_png_reps);
     54 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
     55     const ImageSkia* skia);
     56 #else
     57 // Returns a 16x16 red image to visually show error in decoding PNG.
     58 // Caller takes ownership of returned ImageSkia.
     59 ImageSkia* GetErrorImageSkia() {
     60   SkBitmap bitmap;
     61   bitmap.allocN32Pixels(16, 16);
     62   bitmap.eraseARGB(0xff, 0xff, 0, 0);
     63   return new ImageSkia(ImageSkiaRep(bitmap, 1.0f));
     64 }
     65 
     66 class PNGImageSource : public ImageSkiaSource {
     67  public:
     68   PNGImageSource() {}
     69   virtual ~PNGImageSource() {}
     70 
     71   virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
     72     if (image_skia_reps_.empty())
     73       return ImageSkiaRep();
     74 
     75     const ImageSkiaRep* rep = NULL;
     76     // gfx::ImageSkia passes one of the resource scale factors. The source
     77     // should return:
     78     // 1) The ImageSkiaRep with the highest scale if all available
     79     // scales are smaller than |scale|.
     80     // 2) The ImageSkiaRep with the smallest one that is larger than |scale|.
     81     for (ImageSkiaRepSet::const_iterator iter = image_skia_reps_.begin();
     82          iter != image_skia_reps_.end(); ++iter) {
     83       if ((*iter).scale() == scale)
     84         return (*iter);
     85       if (!rep || rep->scale() < (*iter).scale())
     86         rep = &(*iter);
     87       if (rep->scale() >= scale)
     88         break;
     89     }
     90     return rep ? *rep : ImageSkiaRep();
     91   }
     92 
     93   const gfx::Size size() const {
     94     return size_;
     95   }
     96 
     97   bool AddPNGData(const ImagePNGRep& png_rep) {
     98     const gfx::ImageSkiaRep rep = ToImageSkiaRep(png_rep);
     99     if (rep.is_null())
    100       return false;
    101     if (size_.IsEmpty())
    102       size_ = gfx::Size(rep.GetWidth(), rep.GetHeight());
    103     image_skia_reps_.insert(rep);
    104     return true;
    105   }
    106 
    107   static ImageSkiaRep ToImageSkiaRep(const ImagePNGRep& png_rep) {
    108     scoped_refptr<base::RefCountedMemory> raw_data = png_rep.raw_data;
    109     CHECK(raw_data.get());
    110     SkBitmap bitmap;
    111     if (!PNGCodec::Decode(raw_data->front(), raw_data->size(),
    112                                &bitmap)) {
    113       LOG(ERROR) << "Unable to decode PNG for " << png_rep.scale << ".";
    114       return ImageSkiaRep();
    115     }
    116     return ImageSkiaRep(bitmap, png_rep.scale);
    117   }
    118 
    119  private:
    120   struct Compare {
    121     bool operator()(const ImageSkiaRep& rep1, const ImageSkiaRep& rep2) {
    122       return rep1.scale() < rep2.scale();
    123     }
    124   };
    125 
    126   typedef std::set<ImageSkiaRep, Compare> ImageSkiaRepSet;
    127   ImageSkiaRepSet image_skia_reps_;
    128   gfx::Size size_;
    129 
    130   DISALLOW_COPY_AND_ASSIGN(PNGImageSource);
    131 };
    132 
    133 ImageSkia* ImageSkiaFromPNG(
    134     const std::vector<ImagePNGRep>& image_png_reps) {
    135   if (image_png_reps.empty())
    136     return GetErrorImageSkia();
    137   scoped_ptr<PNGImageSource> image_source(new PNGImageSource);
    138 
    139   for (size_t i = 0; i < image_png_reps.size(); ++i) {
    140     if (!image_source->AddPNGData(image_png_reps[i]))
    141       return GetErrorImageSkia();
    142   }
    143   const gfx::Size& size = image_source->size();
    144   DCHECK(!size.IsEmpty());
    145   if (size.IsEmpty())
    146     return GetErrorImageSkia();
    147   return new ImageSkia(image_source.release(), size);
    148 }
    149 
    150 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
    151     const ImageSkia* image_skia) {
    152   ImageSkiaRep image_skia_rep = image_skia->GetRepresentation(1.0f);
    153 
    154   scoped_refptr<base::RefCountedBytes> png_bytes(new base::RefCountedBytes());
    155   if (image_skia_rep.scale() != 1.0f ||
    156       !PNGCodec::EncodeBGRASkBitmap(image_skia_rep.sk_bitmap(), false,
    157           &png_bytes->data())) {
    158     return NULL;
    159   }
    160   return png_bytes;
    161 }
    162 #endif
    163 
    164 class ImageRepPNG;
    165 class ImageRepSkia;
    166 class ImageRepCocoa;
    167 class ImageRepCocoaTouch;
    168 
    169 // An ImageRep is the object that holds the backing memory for an Image. Each
    170 // RepresentationType has an ImageRep subclass that is responsible for freeing
    171 // the memory that the ImageRep holds. When an ImageRep is created, it expects
    172 // to take ownership of the image, without having to retain it or increase its
    173 // reference count.
    174 class ImageRep {
    175  public:
    176   explicit ImageRep(Image::RepresentationType rep) : type_(rep) {}
    177 
    178   // Deletes the associated pixels of an ImageRep.
    179   virtual ~ImageRep() {}
    180 
    181   // Cast helpers ("fake RTTI").
    182   ImageRepPNG* AsImageRepPNG() {
    183     CHECK_EQ(type_, Image::kImageRepPNG);
    184     return reinterpret_cast<ImageRepPNG*>(this);
    185   }
    186 
    187   ImageRepSkia* AsImageRepSkia() {
    188     CHECK_EQ(type_, Image::kImageRepSkia);
    189     return reinterpret_cast<ImageRepSkia*>(this);
    190   }
    191 
    192 #if defined(OS_IOS)
    193   ImageRepCocoaTouch* AsImageRepCocoaTouch() {
    194     CHECK_EQ(type_, Image::kImageRepCocoaTouch);
    195     return reinterpret_cast<ImageRepCocoaTouch*>(this);
    196   }
    197 #elif defined(OS_MACOSX)
    198   ImageRepCocoa* AsImageRepCocoa() {
    199     CHECK_EQ(type_, Image::kImageRepCocoa);
    200     return reinterpret_cast<ImageRepCocoa*>(this);
    201   }
    202 #endif
    203 
    204   Image::RepresentationType type() const { return type_; }
    205 
    206   virtual int Width() const = 0;
    207   virtual int Height() const = 0;
    208   virtual gfx::Size Size() const = 0;
    209 
    210  private:
    211   Image::RepresentationType type_;
    212 };
    213 
    214 class ImageRepPNG : public ImageRep {
    215  public:
    216   ImageRepPNG() : ImageRep(Image::kImageRepPNG) {
    217   }
    218 
    219   ImageRepPNG(const std::vector<ImagePNGRep>& image_png_reps)
    220       : ImageRep(Image::kImageRepPNG),
    221         image_png_reps_(image_png_reps) {
    222   }
    223 
    224   virtual ~ImageRepPNG() {
    225   }
    226 
    227   virtual int Width() const OVERRIDE {
    228     return Size().width();
    229   }
    230 
    231   virtual int Height() const OVERRIDE {
    232     return Size().height();
    233   }
    234 
    235   virtual gfx::Size Size() const OVERRIDE {
    236     // Read the PNG data to get the image size, caching it.
    237     if (!size_cache_) {
    238       for (std::vector<ImagePNGRep>::const_iterator it = image_reps().begin();
    239            it != image_reps().end(); ++it) {
    240         if (it->scale == 1.0f) {
    241           size_cache_.reset(new gfx::Size(it->Size()));
    242           return *size_cache_;
    243         }
    244       }
    245       size_cache_.reset(new gfx::Size);
    246     }
    247 
    248     return *size_cache_;
    249   }
    250 
    251   const std::vector<ImagePNGRep>& image_reps() const { return image_png_reps_; }
    252 
    253  private:
    254   std::vector<ImagePNGRep> image_png_reps_;
    255 
    256   // Cached to avoid having to parse the raw data multiple times.
    257   mutable scoped_ptr<gfx::Size> size_cache_;
    258 
    259   DISALLOW_COPY_AND_ASSIGN(ImageRepPNG);
    260 };
    261 
    262 class ImageRepSkia : public ImageRep {
    263  public:
    264   // Takes ownership of |image|.
    265   explicit ImageRepSkia(ImageSkia* image)
    266       : ImageRep(Image::kImageRepSkia),
    267         image_(image) {
    268   }
    269 
    270   virtual ~ImageRepSkia() {
    271   }
    272 
    273   virtual int Width() const OVERRIDE {
    274     return image_->width();
    275   }
    276 
    277   virtual int Height() const OVERRIDE {
    278     return image_->height();
    279   }
    280 
    281   virtual gfx::Size Size() const OVERRIDE {
    282     return image_->size();
    283   }
    284 
    285   ImageSkia* image() { return image_.get(); }
    286 
    287  private:
    288   scoped_ptr<ImageSkia> image_;
    289 
    290   DISALLOW_COPY_AND_ASSIGN(ImageRepSkia);
    291 };
    292 
    293 #if defined(OS_IOS)
    294 class ImageRepCocoaTouch : public ImageRep {
    295  public:
    296   explicit ImageRepCocoaTouch(UIImage* image)
    297       : ImageRep(Image::kImageRepCocoaTouch),
    298         image_(image) {
    299     CHECK(image);
    300   }
    301 
    302   virtual ~ImageRepCocoaTouch() {
    303     base::mac::NSObjectRelease(image_);
    304     image_ = nil;
    305   }
    306 
    307   virtual int Width() const OVERRIDE {
    308     return Size().width();
    309   }
    310 
    311   virtual int Height() const OVERRIDE {
    312     return Size().height();
    313   }
    314 
    315   virtual gfx::Size Size() const OVERRIDE {
    316     return internal::UIImageSize(image_);
    317   }
    318 
    319   UIImage* image() const { return image_; }
    320 
    321  private:
    322   UIImage* image_;
    323 
    324   DISALLOW_COPY_AND_ASSIGN(ImageRepCocoaTouch);
    325 };
    326 #elif defined(OS_MACOSX)
    327 class ImageRepCocoa : public ImageRep {
    328  public:
    329   explicit ImageRepCocoa(NSImage* image)
    330       : ImageRep(Image::kImageRepCocoa),
    331         image_(image) {
    332     CHECK(image);
    333   }
    334 
    335   virtual ~ImageRepCocoa() {
    336     base::mac::NSObjectRelease(image_);
    337     image_ = nil;
    338   }
    339 
    340   virtual int Width() const OVERRIDE {
    341     return Size().width();
    342   }
    343 
    344   virtual int Height() const OVERRIDE {
    345     return Size().height();
    346   }
    347 
    348   virtual gfx::Size Size() const OVERRIDE {
    349     return internal::NSImageSize(image_);
    350   }
    351 
    352   NSImage* image() const { return image_; }
    353 
    354  private:
    355   NSImage* image_;
    356 
    357   DISALLOW_COPY_AND_ASSIGN(ImageRepCocoa);
    358 };
    359 #endif  // defined(OS_MACOSX)
    360 
    361 // The Storage class acts similarly to the pixels in a SkBitmap: the Image
    362 // class holds a refptr instance of Storage, which in turn holds all the
    363 // ImageReps. This way, the Image can be cheaply copied.
    364 class ImageStorage : public base::RefCounted<ImageStorage> {
    365  public:
    366   ImageStorage(Image::RepresentationType default_type)
    367       : default_representation_type_(default_type),
    368 #if defined(OS_MACOSX) && !defined(OS_IOS)
    369         default_representation_color_space_(
    370             base::mac::GetGenericRGBColorSpace()),
    371 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    372         representations_deleter_(&representations_) {
    373   }
    374 
    375   Image::RepresentationType default_representation_type() {
    376     return default_representation_type_;
    377   }
    378   Image::RepresentationMap& representations() { return representations_; }
    379 
    380 #if defined(OS_MACOSX) && !defined(OS_IOS)
    381   void set_default_representation_color_space(CGColorSpaceRef color_space) {
    382     default_representation_color_space_ = color_space;
    383   }
    384   CGColorSpaceRef default_representation_color_space() {
    385     return default_representation_color_space_;
    386   }
    387 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    388 
    389  private:
    390   friend class base::RefCounted<ImageStorage>;
    391 
    392   ~ImageStorage() {}
    393 
    394   // The type of image that was passed to the constructor. This key will always
    395   // exist in the |representations_| map.
    396   Image::RepresentationType default_representation_type_;
    397 
    398 #if defined(OS_MACOSX) && !defined(OS_IOS)
    399   // The default representation's colorspace. This is used for converting to
    400   // NSImage. This field exists to compensate for PNGCodec not writing or
    401   // reading colorspace ancillary chunks. (sRGB, iCCP).
    402   // Not owned.
    403   CGColorSpaceRef default_representation_color_space_;
    404 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    405 
    406   // All the representations of an Image. Size will always be at least one, with
    407   // more for any converted representations.
    408   Image::RepresentationMap representations_;
    409 
    410   STLValueDeleter<Image::RepresentationMap> representations_deleter_;
    411 
    412   DISALLOW_COPY_AND_ASSIGN(ImageStorage);
    413 };
    414 
    415 }  // namespace internal
    416 
    417 Image::Image() {
    418   // |storage_| is NULL for empty Images.
    419 }
    420 
    421 Image::Image(const std::vector<ImagePNGRep>& image_reps) {
    422   // Do not store obviously invalid ImagePNGReps.
    423   std::vector<ImagePNGRep> filtered;
    424   for (size_t i = 0; i < image_reps.size(); ++i) {
    425     if (image_reps[i].raw_data.get() && image_reps[i].raw_data->size())
    426       filtered.push_back(image_reps[i]);
    427   }
    428 
    429   if (filtered.empty())
    430     return;
    431 
    432   storage_ = new internal::ImageStorage(Image::kImageRepPNG);
    433   internal::ImageRepPNG* rep = new internal::ImageRepPNG(filtered);
    434   AddRepresentation(rep);
    435 }
    436 
    437 Image::Image(const ImageSkia& image) {
    438   if (!image.isNull()) {
    439     storage_ = new internal::ImageStorage(Image::kImageRepSkia);
    440     internal::ImageRepSkia* rep = new internal::ImageRepSkia(
    441         new ImageSkia(image));
    442     AddRepresentation(rep);
    443   }
    444 }
    445 
    446 #if defined(OS_IOS)
    447 Image::Image(UIImage* image)
    448     : storage_(new internal::ImageStorage(Image::kImageRepCocoaTouch)) {
    449   if (image) {
    450     internal::ImageRepCocoaTouch* rep = new internal::ImageRepCocoaTouch(image);
    451     AddRepresentation(rep);
    452   }
    453 }
    454 #elif defined(OS_MACOSX)
    455 Image::Image(NSImage* image) {
    456   if (image) {
    457     storage_ = new internal::ImageStorage(Image::kImageRepCocoa);
    458     internal::ImageRepCocoa* rep = new internal::ImageRepCocoa(image);
    459     AddRepresentation(rep);
    460   }
    461 }
    462 #endif
    463 
    464 Image::Image(const Image& other) : storage_(other.storage_) {
    465 }
    466 
    467 Image& Image::operator=(const Image& other) {
    468   storage_ = other.storage_;
    469   return *this;
    470 }
    471 
    472 Image::~Image() {
    473 }
    474 
    475 // static
    476 Image Image::CreateFrom1xBitmap(const SkBitmap& bitmap) {
    477   return Image(ImageSkia::CreateFrom1xBitmap(bitmap));
    478 }
    479 
    480 // static
    481 Image Image::CreateFrom1xPNGBytes(const unsigned char* input,
    482                                   size_t input_size) {
    483   if (input_size == 0u)
    484     return Image();
    485 
    486   scoped_refptr<base::RefCountedBytes> raw_data(new base::RefCountedBytes());
    487   raw_data->data().assign(input, input + input_size);
    488 
    489   return CreateFrom1xPNGBytes(raw_data);
    490 }
    491 
    492 Image Image::CreateFrom1xPNGBytes(
    493     const scoped_refptr<base::RefCountedMemory>& input) {
    494   if (!input.get() || input->size() == 0u)
    495     return Image();
    496 
    497   std::vector<ImagePNGRep> image_reps;
    498   image_reps.push_back(ImagePNGRep(input, 1.0f));
    499   return Image(image_reps);
    500 }
    501 
    502 const SkBitmap* Image::ToSkBitmap() const {
    503   // Possibly create and cache an intermediate ImageRepSkia.
    504   return ToImageSkia()->bitmap();
    505 }
    506 
    507 const ImageSkia* Image::ToImageSkia() const {
    508   internal::ImageRep* rep = GetRepresentation(kImageRepSkia, false);
    509   if (!rep) {
    510     switch (DefaultRepresentationType()) {
    511       case kImageRepPNG: {
    512         internal::ImageRepPNG* png_rep =
    513             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
    514         rep = new internal::ImageRepSkia(
    515             internal::ImageSkiaFromPNG(png_rep->image_reps()));
    516         break;
    517       }
    518 #if defined(OS_IOS)
    519       case kImageRepCocoaTouch: {
    520         internal::ImageRepCocoaTouch* native_rep =
    521             GetRepresentation(kImageRepCocoaTouch, true)
    522                 ->AsImageRepCocoaTouch();
    523         rep = new internal::ImageRepSkia(new ImageSkia(
    524             ImageSkiaFromUIImage(native_rep->image())));
    525         break;
    526       }
    527 #elif defined(OS_MACOSX)
    528       case kImageRepCocoa: {
    529         internal::ImageRepCocoa* native_rep =
    530             GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
    531         rep = new internal::ImageRepSkia(new ImageSkia(
    532             ImageSkiaFromNSImage(native_rep->image())));
    533         break;
    534       }
    535 #endif
    536       default:
    537         NOTREACHED();
    538     }
    539     CHECK(rep);
    540     AddRepresentation(rep);
    541   }
    542   return rep->AsImageRepSkia()->image();
    543 }
    544 
    545 #if defined(OS_IOS)
    546 UIImage* Image::ToUIImage() const {
    547   internal::ImageRep* rep = GetRepresentation(kImageRepCocoaTouch, false);
    548   if (!rep) {
    549     switch (DefaultRepresentationType()) {
    550       case kImageRepPNG: {
    551         internal::ImageRepPNG* png_rep =
    552             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
    553         rep = new internal::ImageRepCocoaTouch(internal::CreateUIImageFromPNG(
    554             png_rep->image_reps()));
    555         break;
    556       }
    557       case kImageRepSkia: {
    558         internal::ImageRepSkia* skia_rep =
    559             GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
    560         UIImage* image = UIImageFromImageSkia(*skia_rep->image());
    561         base::mac::NSObjectRetain(image);
    562         rep = new internal::ImageRepCocoaTouch(image);
    563         break;
    564       }
    565       default:
    566         NOTREACHED();
    567     }
    568     CHECK(rep);
    569     AddRepresentation(rep);
    570   }
    571   return rep->AsImageRepCocoaTouch()->image();
    572 }
    573 #elif defined(OS_MACOSX)
    574 NSImage* Image::ToNSImage() const {
    575   internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false);
    576   if (!rep) {
    577     CGColorSpaceRef default_representation_color_space =
    578         storage_->default_representation_color_space();
    579 
    580     switch (DefaultRepresentationType()) {
    581       case kImageRepPNG: {
    582         internal::ImageRepPNG* png_rep =
    583             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
    584         rep = new internal::ImageRepCocoa(internal::NSImageFromPNG(
    585             png_rep->image_reps(), default_representation_color_space));
    586         break;
    587       }
    588       case kImageRepSkia: {
    589         internal::ImageRepSkia* skia_rep =
    590             GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
    591         NSImage* image = NSImageFromImageSkiaWithColorSpace(*skia_rep->image(),
    592             default_representation_color_space);
    593         base::mac::NSObjectRetain(image);
    594         rep = new internal::ImageRepCocoa(image);
    595         break;
    596       }
    597       default:
    598         NOTREACHED();
    599     }
    600     CHECK(rep);
    601     AddRepresentation(rep);
    602   }
    603   return rep->AsImageRepCocoa()->image();
    604 }
    605 #endif
    606 
    607 scoped_refptr<base::RefCountedMemory> Image::As1xPNGBytes() const {
    608   if (IsEmpty())
    609     return new base::RefCountedBytes();
    610 
    611   internal::ImageRep* rep = GetRepresentation(kImageRepPNG, false);
    612 
    613   if (rep) {
    614     const std::vector<ImagePNGRep>& image_png_reps =
    615         rep->AsImageRepPNG()->image_reps();
    616     for (size_t i = 0; i < image_png_reps.size(); ++i) {
    617       if (image_png_reps[i].scale == 1.0f)
    618         return image_png_reps[i].raw_data;
    619     }
    620     return new base::RefCountedBytes();
    621   }
    622 
    623   scoped_refptr<base::RefCountedMemory> png_bytes(NULL);
    624   switch (DefaultRepresentationType()) {
    625 #if defined(OS_IOS)
    626     case kImageRepCocoaTouch: {
    627       internal::ImageRepCocoaTouch* cocoa_touch_rep =
    628           GetRepresentation(kImageRepCocoaTouch, true)
    629               ->AsImageRepCocoaTouch();
    630       png_bytes = internal::Get1xPNGBytesFromUIImage(
    631           cocoa_touch_rep->image());
    632       break;
    633     }
    634 #elif defined(OS_MACOSX)
    635     case kImageRepCocoa: {
    636       internal::ImageRepCocoa* cocoa_rep =
    637           GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
    638       png_bytes = internal::Get1xPNGBytesFromNSImage(cocoa_rep->image());
    639       break;
    640     }
    641 #endif
    642     case kImageRepSkia: {
    643       internal::ImageRepSkia* skia_rep =
    644           GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
    645       png_bytes = internal::Get1xPNGBytesFromImageSkia(skia_rep->image());
    646       break;
    647     }
    648     default:
    649       NOTREACHED();
    650   }
    651   if (!png_bytes.get() || !png_bytes->size()) {
    652     // Add an ImageRepPNG with no data such that the conversion is not
    653     // attempted each time we want the PNG bytes.
    654     AddRepresentation(new internal::ImageRepPNG());
    655     return new base::RefCountedBytes();
    656   }
    657 
    658   // Do not insert representations for scale factors other than 1x even if
    659   // they are available because:
    660   // - Only the 1x PNG bytes can be accessed.
    661   // - ImageRepPNG is not used as an intermediate type in converting to a
    662   //   final type eg (converting from ImageRepSkia to ImageRepPNG to get an
    663   //   ImageRepCocoa).
    664   std::vector<ImagePNGRep> image_png_reps;
    665   image_png_reps.push_back(ImagePNGRep(png_bytes, 1.0f));
    666   rep = new internal::ImageRepPNG(image_png_reps);
    667   AddRepresentation(rep);
    668   return png_bytes;
    669 }
    670 
    671 SkBitmap Image::AsBitmap() const {
    672   return IsEmpty() ? SkBitmap() : *ToSkBitmap();
    673 }
    674 
    675 ImageSkia Image::AsImageSkia() const {
    676   return IsEmpty() ? ImageSkia() : *ToImageSkia();
    677 }
    678 
    679 #if defined(OS_MACOSX) && !defined(OS_IOS)
    680 NSImage* Image::AsNSImage() const {
    681   return IsEmpty() ? nil : ToNSImage();
    682 }
    683 #endif
    684 
    685 scoped_refptr<base::RefCountedMemory> Image::Copy1xPNGBytes() const {
    686   scoped_refptr<base::RefCountedMemory> original = As1xPNGBytes();
    687   scoped_refptr<base::RefCountedBytes> copy(new base::RefCountedBytes());
    688   copy->data().assign(original->front(), original->front() + original->size());
    689   return copy;
    690 }
    691 
    692 ImageSkia* Image::CopyImageSkia() const {
    693   return new ImageSkia(*ToImageSkia());
    694 }
    695 
    696 SkBitmap* Image::CopySkBitmap() const {
    697   return new SkBitmap(*ToSkBitmap());
    698 }
    699 
    700 #if defined(OS_IOS)
    701 UIImage* Image::CopyUIImage() const {
    702   UIImage* image = ToUIImage();
    703   base::mac::NSObjectRetain(image);
    704   return image;
    705 }
    706 #elif defined(OS_MACOSX)
    707 NSImage* Image::CopyNSImage() const {
    708   NSImage* image = ToNSImage();
    709   base::mac::NSObjectRetain(image);
    710   return image;
    711 }
    712 #endif
    713 
    714 bool Image::HasRepresentation(RepresentationType type) const {
    715   return storage_.get() && storage_->representations().count(type) != 0;
    716 }
    717 
    718 size_t Image::RepresentationCount() const {
    719   if (!storage_.get())
    720     return 0;
    721 
    722   return storage_->representations().size();
    723 }
    724 
    725 bool Image::IsEmpty() const {
    726   return RepresentationCount() == 0;
    727 }
    728 
    729 int Image::Width() const {
    730   if (IsEmpty())
    731     return 0;
    732   return GetRepresentation(DefaultRepresentationType(), true)->Width();
    733 }
    734 
    735 int Image::Height() const {
    736   if (IsEmpty())
    737     return 0;
    738   return GetRepresentation(DefaultRepresentationType(), true)->Height();
    739 }
    740 
    741 gfx::Size Image::Size() const {
    742   if (IsEmpty())
    743     return gfx::Size();
    744   return GetRepresentation(DefaultRepresentationType(), true)->Size();
    745 }
    746 
    747 void Image::SwapRepresentations(Image* other) {
    748   storage_.swap(other->storage_);
    749 }
    750 
    751 #if defined(OS_MACOSX)  && !defined(OS_IOS)
    752 void Image::SetSourceColorSpace(CGColorSpaceRef color_space) {
    753   if (storage_.get())
    754     storage_->set_default_representation_color_space(color_space);
    755 }
    756 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
    757 
    758 Image::RepresentationType Image::DefaultRepresentationType() const {
    759   CHECK(storage_.get());
    760   return storage_->default_representation_type();
    761 }
    762 
    763 internal::ImageRep* Image::GetRepresentation(
    764     RepresentationType rep_type, bool must_exist) const {
    765   CHECK(storage_.get());
    766   RepresentationMap::iterator it = storage_->representations().find(rep_type);
    767   if (it == storage_->representations().end()) {
    768     CHECK(!must_exist);
    769     return NULL;
    770   }
    771   return it->second;
    772 }
    773 
    774 void Image::AddRepresentation(internal::ImageRep* rep) const {
    775   CHECK(storage_.get());
    776   storage_->representations().insert(std::make_pair(rep->type(), rep));
    777 }
    778 
    779 }  // namespace gfx
    780