• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
GetErrorImageSkia()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:
PNGImageSource()68   PNGImageSource() {}
~PNGImageSource()69   virtual ~PNGImageSource() {}
70 
GetImageForScale(float scale)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 
size() const93   const gfx::Size size() const {
94     return size_;
95   }
96 
AddPNGData(const ImagePNGRep & png_rep)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 
ToImageSkiaRep(const ImagePNGRep & png_rep)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 {
operator ()gfx::internal::PNGImageSource::Compare121     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 
ImageSkiaFromPNG(const std::vector<ImagePNGRep> & image_png_reps)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 
Get1xPNGBytesFromImageSkia(const ImageSkia * image_skia)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:
ImageRep(Image::RepresentationType rep)176   explicit ImageRep(Image::RepresentationType rep) : type_(rep) {}
177 
178   // Deletes the associated pixels of an ImageRep.
~ImageRep()179   virtual ~ImageRep() {}
180 
181   // Cast helpers ("fake RTTI").
AsImageRepPNG()182   ImageRepPNG* AsImageRepPNG() {
183     CHECK_EQ(type_, Image::kImageRepPNG);
184     return reinterpret_cast<ImageRepPNG*>(this);
185   }
186 
AsImageRepSkia()187   ImageRepSkia* AsImageRepSkia() {
188     CHECK_EQ(type_, Image::kImageRepSkia);
189     return reinterpret_cast<ImageRepSkia*>(this);
190   }
191 
192 #if defined(OS_IOS)
AsImageRepCocoaTouch()193   ImageRepCocoaTouch* AsImageRepCocoaTouch() {
194     CHECK_EQ(type_, Image::kImageRepCocoaTouch);
195     return reinterpret_cast<ImageRepCocoaTouch*>(this);
196   }
197 #elif defined(OS_MACOSX)
AsImageRepCocoa()198   ImageRepCocoa* AsImageRepCocoa() {
199     CHECK_EQ(type_, Image::kImageRepCocoa);
200     return reinterpret_cast<ImageRepCocoa*>(this);
201   }
202 #endif
203 
type() const204   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:
ImageRepPNG()216   ImageRepPNG() : ImageRep(Image::kImageRepPNG) {
217   }
218 
ImageRepPNG(const std::vector<ImagePNGRep> & image_png_reps)219   ImageRepPNG(const std::vector<ImagePNGRep>& image_png_reps)
220       : ImageRep(Image::kImageRepPNG),
221         image_png_reps_(image_png_reps) {
222   }
223 
~ImageRepPNG()224   virtual ~ImageRepPNG() {
225   }
226 
Width() const227   virtual int Width() const OVERRIDE {
228     return Size().width();
229   }
230 
Height() const231   virtual int Height() const OVERRIDE {
232     return Size().height();
233   }
234 
Size() const235   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 
image_reps() const251   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|.
ImageRepSkia(ImageSkia * image)265   explicit ImageRepSkia(ImageSkia* image)
266       : ImageRep(Image::kImageRepSkia),
267         image_(image) {
268   }
269 
~ImageRepSkia()270   virtual ~ImageRepSkia() {
271   }
272 
Width() const273   virtual int Width() const OVERRIDE {
274     return image_->width();
275   }
276 
Height() const277   virtual int Height() const OVERRIDE {
278     return image_->height();
279   }
280 
Size() const281   virtual gfx::Size Size() const OVERRIDE {
282     return image_->size();
283   }
284 
image()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:
ImageRepCocoaTouch(UIImage * image)296   explicit ImageRepCocoaTouch(UIImage* image)
297       : ImageRep(Image::kImageRepCocoaTouch),
298         image_(image) {
299     CHECK(image);
300   }
301 
~ImageRepCocoaTouch()302   virtual ~ImageRepCocoaTouch() {
303     base::mac::NSObjectRelease(image_);
304     image_ = nil;
305   }
306 
Width() const307   virtual int Width() const OVERRIDE {
308     return Size().width();
309   }
310 
Height() const311   virtual int Height() const OVERRIDE {
312     return Size().height();
313   }
314 
Size() const315   virtual gfx::Size Size() const OVERRIDE {
316     return internal::UIImageSize(image_);
317   }
318 
image() const319   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:
ImageRepCocoa(NSImage * image)329   explicit ImageRepCocoa(NSImage* image)
330       : ImageRep(Image::kImageRepCocoa),
331         image_(image) {
332     CHECK(image);
333   }
334 
~ImageRepCocoa()335   virtual ~ImageRepCocoa() {
336     base::mac::NSObjectRelease(image_);
337     image_ = nil;
338   }
339 
Width() const340   virtual int Width() const OVERRIDE {
341     return Size().width();
342   }
343 
Height() const344   virtual int Height() const OVERRIDE {
345     return Size().height();
346   }
347 
Size() const348   virtual gfx::Size Size() const OVERRIDE {
349     return internal::NSImageSize(image_);
350   }
351 
image() const352   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:
ImageStorage(Image::RepresentationType default_type)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 
default_representation_type()375   Image::RepresentationType default_representation_type() {
376     return default_representation_type_;
377   }
representations()378   Image::RepresentationMap& representations() { return representations_; }
379 
380 #if defined(OS_MACOSX) && !defined(OS_IOS)
set_default_representation_color_space(CGColorSpaceRef color_space)381   void set_default_representation_color_space(CGColorSpaceRef color_space) {
382     default_representation_color_space_ = color_space;
383   }
default_representation_color_space()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 
~ImageStorage()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 
Image()417 Image::Image() {
418   // |storage_| is NULL for empty Images.
419 }
420 
Image(const std::vector<ImagePNGRep> & image_reps)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 
Image(const ImageSkia & image)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)
Image(UIImage * image)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)
Image(NSImage * image)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 
Image(const Image & other)464 Image::Image(const Image& other) : storage_(other.storage_) {
465 }
466 
operator =(const Image & other)467 Image& Image::operator=(const Image& other) {
468   storage_ = other.storage_;
469   return *this;
470 }
471 
~Image()472 Image::~Image() {
473 }
474 
475 // static
CreateFrom1xBitmap(const SkBitmap & bitmap)476 Image Image::CreateFrom1xBitmap(const SkBitmap& bitmap) {
477   return Image(ImageSkia::CreateFrom1xBitmap(bitmap));
478 }
479 
480 // static
CreateFrom1xPNGBytes(const unsigned char * input,size_t input_size)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 
CreateFrom1xPNGBytes(const scoped_refptr<base::RefCountedMemory> & input)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 
ToSkBitmap() const502 const SkBitmap* Image::ToSkBitmap() const {
503   // Possibly create and cache an intermediate ImageRepSkia.
504   return ToImageSkia()->bitmap();
505 }
506 
ToImageSkia() const507 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)
ToUIImage() const546 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)
ToNSImage() const574 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 
As1xPNGBytes() const607 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 
AsBitmap() const671 SkBitmap Image::AsBitmap() const {
672   return IsEmpty() ? SkBitmap() : *ToSkBitmap();
673 }
674 
AsImageSkia() const675 ImageSkia Image::AsImageSkia() const {
676   return IsEmpty() ? ImageSkia() : *ToImageSkia();
677 }
678 
679 #if defined(OS_MACOSX) && !defined(OS_IOS)
AsNSImage() const680 NSImage* Image::AsNSImage() const {
681   return IsEmpty() ? nil : ToNSImage();
682 }
683 #endif
684 
Copy1xPNGBytes() const685 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 
CopyImageSkia() const692 ImageSkia* Image::CopyImageSkia() const {
693   return new ImageSkia(*ToImageSkia());
694 }
695 
CopySkBitmap() const696 SkBitmap* Image::CopySkBitmap() const {
697   return new SkBitmap(*ToSkBitmap());
698 }
699 
700 #if defined(OS_IOS)
CopyUIImage() const701 UIImage* Image::CopyUIImage() const {
702   UIImage* image = ToUIImage();
703   base::mac::NSObjectRetain(image);
704   return image;
705 }
706 #elif defined(OS_MACOSX)
CopyNSImage() const707 NSImage* Image::CopyNSImage() const {
708   NSImage* image = ToNSImage();
709   base::mac::NSObjectRetain(image);
710   return image;
711 }
712 #endif
713 
HasRepresentation(RepresentationType type) const714 bool Image::HasRepresentation(RepresentationType type) const {
715   return storage_.get() && storage_->representations().count(type) != 0;
716 }
717 
RepresentationCount() const718 size_t Image::RepresentationCount() const {
719   if (!storage_.get())
720     return 0;
721 
722   return storage_->representations().size();
723 }
724 
IsEmpty() const725 bool Image::IsEmpty() const {
726   return RepresentationCount() == 0;
727 }
728 
Width() const729 int Image::Width() const {
730   if (IsEmpty())
731     return 0;
732   return GetRepresentation(DefaultRepresentationType(), true)->Width();
733 }
734 
Height() const735 int Image::Height() const {
736   if (IsEmpty())
737     return 0;
738   return GetRepresentation(DefaultRepresentationType(), true)->Height();
739 }
740 
Size() const741 gfx::Size Image::Size() const {
742   if (IsEmpty())
743     return gfx::Size();
744   return GetRepresentation(DefaultRepresentationType(), true)->Size();
745 }
746 
SwapRepresentations(Image * other)747 void Image::SwapRepresentations(Image* other) {
748   storage_.swap(other->storage_);
749 }
750 
751 #if defined(OS_MACOSX)  && !defined(OS_IOS)
SetSourceColorSpace(CGColorSpaceRef color_space)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 
DefaultRepresentationType() const758 Image::RepresentationType Image::DefaultRepresentationType() const {
759   CHECK(storage_.get());
760   return storage_->default_representation_type();
761 }
762 
GetRepresentation(RepresentationType rep_type,bool must_exist) const763 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 
AddRepresentation(internal::ImageRep * rep) const774 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