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