• 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 
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/gfx/canvas.h"
26 #include "ui/gfx/gtk_util.h"
27 #include "ui/gfx/image/cairo_cached_surface.h"
28 #include "ui/gfx/scoped_gobject.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)
ImageSkiaFromGdkPixbuf(GdkPixbuf * pixbuf)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                      1.0f,
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.
GetErrorPixbuf()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 
GdkPixbufFromPNG(const std::vector<gfx::ImagePNGRep> & image_png_reps)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 == 1.0f)
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 
Get1xPNGBytesFromPixbuf(GdkPixbuf * pixbuf)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.
GetErrorImageSkia()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, 1.0f));
146 }
147 
ImageSkiaFromPNG(const std::vector<gfx::ImagePNGRep> & image_png_reps)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                  << image_png_reps[i].scale
163                  << ".";
164       return GetErrorImageSkia();
165     }
166     image_skia->AddRepresentation(gfx::ImageSkiaRep(
167         bitmap, image_png_reps[i].scale));
168   }
169   return image_skia.release();
170 }
171 
Get1xPNGBytesFromImageSkia(const ImageSkia * image_skia)172 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
173     const ImageSkia* image_skia) {
174   ImageSkiaRep image_skia_rep = image_skia->GetRepresentation(1.0f);
175 
176   scoped_refptr<base::RefCountedBytes> png_bytes(new base::RefCountedBytes());
177   if (image_skia_rep.scale() != 1.0f ||
178       !gfx::PNGCodec::EncodeBGRASkBitmap(image_skia_rep.sk_bitmap(), false,
179           &png_bytes->data())) {
180     return NULL;
181   }
182   return png_bytes;
183 }
184 #endif
185 
186 class ImageRepPNG;
187 class ImageRepSkia;
188 class ImageRepGdk;
189 class ImageRepCairo;
190 class ImageRepCocoa;
191 class ImageRepCocoaTouch;
192 
193 // An ImageRep is the object that holds the backing memory for an Image. Each
194 // RepresentationType has an ImageRep subclass that is responsible for freeing
195 // the memory that the ImageRep holds. When an ImageRep is created, it expects
196 // to take ownership of the image, without having to retain it or increase its
197 // reference count.
198 class ImageRep {
199  public:
ImageRep(Image::RepresentationType rep)200   explicit ImageRep(Image::RepresentationType rep) : type_(rep) {}
201 
202   // Deletes the associated pixels of an ImageRep.
~ImageRep()203   virtual ~ImageRep() {}
204 
205   // Cast helpers ("fake RTTI").
AsImageRepPNG()206   ImageRepPNG* AsImageRepPNG() {
207     CHECK_EQ(type_, Image::kImageRepPNG);
208     return reinterpret_cast<ImageRepPNG*>(this);
209   }
210 
AsImageRepSkia()211   ImageRepSkia* AsImageRepSkia() {
212     CHECK_EQ(type_, Image::kImageRepSkia);
213     return reinterpret_cast<ImageRepSkia*>(this);
214   }
215 
216 #if defined(TOOLKIT_GTK)
AsImageRepGdk()217   ImageRepGdk* AsImageRepGdk() {
218     CHECK_EQ(type_, Image::kImageRepGdk);
219     return reinterpret_cast<ImageRepGdk*>(this);
220   }
221 
AsImageRepCairo()222   ImageRepCairo* AsImageRepCairo() {
223     CHECK_EQ(type_, Image::kImageRepCairo);
224     return reinterpret_cast<ImageRepCairo*>(this);
225   }
226 #endif
227 
228 #if defined(OS_IOS)
AsImageRepCocoaTouch()229   ImageRepCocoaTouch* AsImageRepCocoaTouch() {
230     CHECK_EQ(type_, Image::kImageRepCocoaTouch);
231     return reinterpret_cast<ImageRepCocoaTouch*>(this);
232   }
233 #elif defined(OS_MACOSX)
AsImageRepCocoa()234   ImageRepCocoa* AsImageRepCocoa() {
235     CHECK_EQ(type_, Image::kImageRepCocoa);
236     return reinterpret_cast<ImageRepCocoa*>(this);
237   }
238 #endif
239 
type() const240   Image::RepresentationType type() const { return type_; }
241 
242   virtual int Width() const = 0;
243   virtual int Height() const = 0;
244   virtual gfx::Size Size() const = 0;
245 
246  private:
247   Image::RepresentationType type_;
248 };
249 
250 class ImageRepPNG : public ImageRep {
251  public:
ImageRepPNG()252   ImageRepPNG() : ImageRep(Image::kImageRepPNG) {
253   }
254 
ImageRepPNG(const std::vector<ImagePNGRep> & image_png_reps)255   ImageRepPNG(const std::vector<ImagePNGRep>& image_png_reps)
256       : ImageRep(Image::kImageRepPNG),
257         image_png_reps_(image_png_reps) {
258   }
259 
~ImageRepPNG()260   virtual ~ImageRepPNG() {
261   }
262 
Width() const263   virtual int Width() const OVERRIDE {
264     return Size().width();
265   }
266 
Height() const267   virtual int Height() const OVERRIDE {
268     return Size().height();
269   }
270 
Size() const271   virtual gfx::Size Size() const OVERRIDE {
272     // Read the PNG data to get the image size, caching it.
273     if (!size_cache_) {
274       for (std::vector<ImagePNGRep>::const_iterator it = image_reps().begin();
275            it != image_reps().end(); ++it) {
276         if (it->scale == 1.0f) {
277           size_cache_.reset(new gfx::Size(it->Size()));
278           return *size_cache_;
279         }
280       }
281       size_cache_.reset(new gfx::Size);
282     }
283 
284     return *size_cache_;
285   }
286 
image_reps() const287   const std::vector<ImagePNGRep>& image_reps() const { return image_png_reps_; }
288 
289  private:
290   std::vector<ImagePNGRep> image_png_reps_;
291 
292   // Cached to avoid having to parse the raw data multiple times.
293   mutable scoped_ptr<gfx::Size> size_cache_;
294 
295   DISALLOW_COPY_AND_ASSIGN(ImageRepPNG);
296 };
297 
298 class ImageRepSkia : public ImageRep {
299  public:
300   // Takes ownership of |image|.
ImageRepSkia(ImageSkia * image)301   explicit ImageRepSkia(ImageSkia* image)
302       : ImageRep(Image::kImageRepSkia),
303         image_(image) {
304   }
305 
~ImageRepSkia()306   virtual ~ImageRepSkia() {
307   }
308 
Width() const309   virtual int Width() const OVERRIDE {
310     return image_->width();
311   }
312 
Height() const313   virtual int Height() const OVERRIDE {
314     return image_->height();
315   }
316 
Size() const317   virtual gfx::Size Size() const OVERRIDE {
318     return image_->size();
319   }
320 
image()321   ImageSkia* image() { return image_.get(); }
322 
323  private:
324   scoped_ptr<ImageSkia> image_;
325 
326   DISALLOW_COPY_AND_ASSIGN(ImageRepSkia);
327 };
328 
329 #if defined(TOOLKIT_GTK)
330 class ImageRepGdk : public ImageRep {
331  public:
ImageRepGdk(GdkPixbuf * pixbuf)332   explicit ImageRepGdk(GdkPixbuf* pixbuf)
333       : ImageRep(Image::kImageRepGdk),
334         pixbuf_(pixbuf) {
335     CHECK(pixbuf);
336   }
337 
~ImageRepGdk()338   virtual ~ImageRepGdk() {
339     if (pixbuf_) {
340       g_object_unref(pixbuf_);
341       pixbuf_ = NULL;
342     }
343   }
344 
Width() const345   virtual int Width() const OVERRIDE {
346     return gdk_pixbuf_get_width(pixbuf_);
347   }
348 
Height() const349   virtual int Height() const OVERRIDE {
350     return gdk_pixbuf_get_height(pixbuf_);
351   }
352 
Size() const353   virtual gfx::Size Size() const OVERRIDE {
354     return gfx::Size(Width(), Height());
355   }
356 
pixbuf() const357   GdkPixbuf* pixbuf() const { return pixbuf_; }
358 
359  private:
360   GdkPixbuf* pixbuf_;
361 
362   DISALLOW_COPY_AND_ASSIGN(ImageRepGdk);
363 };
364 
365 // Represents data that lives on the display server instead of in the client.
366 class ImageRepCairo : public ImageRep {
367  public:
ImageRepCairo(GdkPixbuf * pixbuf)368   explicit ImageRepCairo(GdkPixbuf* pixbuf)
369       : ImageRep(Image::kImageRepCairo),
370         cairo_cache_(new CairoCachedSurface) {
371     CHECK(pixbuf);
372     cairo_cache_->UsePixbuf(pixbuf);
373   }
374 
~ImageRepCairo()375   virtual ~ImageRepCairo() {
376     delete cairo_cache_;
377   }
378 
Width() const379   virtual int Width() const OVERRIDE {
380     return cairo_cache_->Width();
381   }
382 
Height() const383   virtual int Height() const OVERRIDE {
384     return cairo_cache_->Height();
385   }
386 
Size() const387   virtual gfx::Size Size() const OVERRIDE {
388     return gfx::Size(Width(), Height());
389   }
390 
surface() const391   CairoCachedSurface* surface() const { return cairo_cache_; }
392 
393  private:
394   CairoCachedSurface* cairo_cache_;
395 
396   DISALLOW_COPY_AND_ASSIGN(ImageRepCairo);
397 };
398 #endif  // defined(TOOLKIT_GTK)
399 
400 #if defined(OS_IOS)
401 class ImageRepCocoaTouch : public ImageRep {
402  public:
ImageRepCocoaTouch(UIImage * image)403   explicit ImageRepCocoaTouch(UIImage* image)
404       : ImageRep(Image::kImageRepCocoaTouch),
405         image_(image) {
406     CHECK(image);
407   }
408 
~ImageRepCocoaTouch()409   virtual ~ImageRepCocoaTouch() {
410     base::mac::NSObjectRelease(image_);
411     image_ = nil;
412   }
413 
Width() const414   virtual int Width() const OVERRIDE {
415     return Size().width();
416   }
417 
Height() const418   virtual int Height() const OVERRIDE {
419     return Size().height();
420   }
421 
Size() const422   virtual gfx::Size Size() const OVERRIDE {
423     return internal::UIImageSize(image_);
424   }
425 
image() const426   UIImage* image() const { return image_; }
427 
428  private:
429   UIImage* image_;
430 
431   DISALLOW_COPY_AND_ASSIGN(ImageRepCocoaTouch);
432 };
433 #elif defined(OS_MACOSX)
434 class ImageRepCocoa : public ImageRep {
435  public:
ImageRepCocoa(NSImage * image)436   explicit ImageRepCocoa(NSImage* image)
437       : ImageRep(Image::kImageRepCocoa),
438         image_(image) {
439     CHECK(image);
440   }
441 
~ImageRepCocoa()442   virtual ~ImageRepCocoa() {
443     base::mac::NSObjectRelease(image_);
444     image_ = nil;
445   }
446 
Width() const447   virtual int Width() const OVERRIDE {
448     return Size().width();
449   }
450 
Height() const451   virtual int Height() const OVERRIDE {
452     return Size().height();
453   }
454 
Size() const455   virtual gfx::Size Size() const OVERRIDE {
456     return internal::NSImageSize(image_);
457   }
458 
image() const459   NSImage* image() const { return image_; }
460 
461  private:
462   NSImage* image_;
463 
464   DISALLOW_COPY_AND_ASSIGN(ImageRepCocoa);
465 };
466 #endif  // defined(OS_MACOSX)
467 
468 // The Storage class acts similarly to the pixels in a SkBitmap: the Image
469 // class holds a refptr instance of Storage, which in turn holds all the
470 // ImageReps. This way, the Image can be cheaply copied.
471 class ImageStorage : public base::RefCounted<ImageStorage> {
472  public:
ImageStorage(gfx::Image::RepresentationType default_type)473   ImageStorage(gfx::Image::RepresentationType default_type)
474       : default_representation_type_(default_type),
475 #if defined(OS_MACOSX) && !defined(OS_IOS)
476         default_representation_color_space_(
477             base::mac::GetGenericRGBColorSpace()),
478 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
479         representations_deleter_(&representations_) {
480   }
481 
default_representation_type()482   gfx::Image::RepresentationType default_representation_type() {
483     return default_representation_type_;
484   }
representations()485   gfx::Image::RepresentationMap& representations() { return representations_; }
486 
487 #if defined(OS_MACOSX) && !defined(OS_IOS)
set_default_representation_color_space(CGColorSpaceRef color_space)488   void set_default_representation_color_space(CGColorSpaceRef color_space) {
489     default_representation_color_space_ = color_space;
490   }
default_representation_color_space()491   CGColorSpaceRef default_representation_color_space() {
492     return default_representation_color_space_;
493   }
494 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
495 
496  private:
497   friend class base::RefCounted<ImageStorage>;
498 
~ImageStorage()499   ~ImageStorage() {}
500 
501   // The type of image that was passed to the constructor. This key will always
502   // exist in the |representations_| map.
503   gfx::Image::RepresentationType default_representation_type_;
504 
505 #if defined(OS_MACOSX) && !defined(OS_IOS)
506   // The default representation's colorspace. This is used for converting to
507   // NSImage. This field exists to compensate for PNGCodec not writing or
508   // reading colorspace ancillary chunks. (sRGB, iCCP).
509   // Not owned.
510   CGColorSpaceRef default_representation_color_space_;
511 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
512 
513   // All the representations of an Image. Size will always be at least one, with
514   // more for any converted representations.
515   gfx::Image::RepresentationMap representations_;
516 
517   STLValueDeleter<Image::RepresentationMap> representations_deleter_;
518 
519   DISALLOW_COPY_AND_ASSIGN(ImageStorage);
520 };
521 
522 }  // namespace internal
523 
Image()524 Image::Image() {
525   // |storage_| is NULL for empty Images.
526 }
527 
Image(const std::vector<ImagePNGRep> & image_reps)528 Image::Image(const std::vector<ImagePNGRep>& image_reps) {
529   // Do not store obviously invalid ImagePNGReps.
530   std::vector<ImagePNGRep> filtered;
531   for (size_t i = 0; i < image_reps.size(); ++i) {
532     if (image_reps[i].raw_data.get() && image_reps[i].raw_data->size())
533       filtered.push_back(image_reps[i]);
534   }
535 
536   if (filtered.empty())
537     return;
538 
539   storage_ = new internal::ImageStorage(Image::kImageRepPNG);
540   internal::ImageRepPNG* rep = new internal::ImageRepPNG(filtered);
541   AddRepresentation(rep);
542 }
543 
Image(const ImageSkia & image)544 Image::Image(const ImageSkia& image) {
545   if (!image.isNull()) {
546     storage_ = new internal::ImageStorage(Image::kImageRepSkia);
547     internal::ImageRepSkia* rep = new internal::ImageRepSkia(
548         new ImageSkia(image));
549     AddRepresentation(rep);
550   }
551 }
552 
553 #if defined(TOOLKIT_GTK)
Image(GdkPixbuf * pixbuf)554 Image::Image(GdkPixbuf* pixbuf) {
555   if (pixbuf) {
556     storage_ = new internal::ImageStorage(Image::kImageRepGdk);
557     internal::ImageRepGdk* rep = new internal::ImageRepGdk(pixbuf);
558     AddRepresentation(rep);
559   }
560 }
561 #endif
562 
563 #if defined(OS_IOS)
Image(UIImage * image)564 Image::Image(UIImage* image)
565     : storage_(new internal::ImageStorage(Image::kImageRepCocoaTouch)) {
566   if (image) {
567     internal::ImageRepCocoaTouch* rep = new internal::ImageRepCocoaTouch(image);
568     AddRepresentation(rep);
569   }
570 }
571 #elif defined(OS_MACOSX)
Image(NSImage * image)572 Image::Image(NSImage* image) {
573   if (image) {
574     storage_ = new internal::ImageStorage(Image::kImageRepCocoa);
575     internal::ImageRepCocoa* rep = new internal::ImageRepCocoa(image);
576     AddRepresentation(rep);
577   }
578 }
579 #endif
580 
Image(const Image & other)581 Image::Image(const Image& other) : storage_(other.storage_) {
582 }
583 
operator =(const Image & other)584 Image& Image::operator=(const Image& other) {
585   storage_ = other.storage_;
586   return *this;
587 }
588 
~Image()589 Image::~Image() {
590 }
591 
592 // static
CreateFrom1xBitmap(const SkBitmap & bitmap)593 Image Image::CreateFrom1xBitmap(const SkBitmap& bitmap) {
594   return gfx::Image(ImageSkia::CreateFrom1xBitmap(bitmap));
595 }
596 
597 // static
CreateFrom1xPNGBytes(const unsigned char * input,size_t input_size)598 Image Image::CreateFrom1xPNGBytes(const unsigned char* input,
599                                   size_t input_size) {
600   if (input_size == 0u)
601     return gfx::Image();
602 
603   scoped_refptr<base::RefCountedBytes> raw_data(new base::RefCountedBytes());
604   raw_data->data().assign(input, input + input_size);
605   std::vector<gfx::ImagePNGRep> image_reps;
606   image_reps.push_back(ImagePNGRep(raw_data, 1.0f));
607   return gfx::Image(image_reps);
608 }
609 
ToSkBitmap() const610 const SkBitmap* Image::ToSkBitmap() const {
611   // Possibly create and cache an intermediate ImageRepSkia.
612   return ToImageSkia()->bitmap();
613 }
614 
ToImageSkia() const615 const ImageSkia* Image::ToImageSkia() const {
616   internal::ImageRep* rep = GetRepresentation(kImageRepSkia, false);
617   if (!rep) {
618     switch (DefaultRepresentationType()) {
619       case kImageRepPNG: {
620         internal::ImageRepPNG* png_rep =
621             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
622         rep = new internal::ImageRepSkia(
623             internal::ImageSkiaFromPNG(png_rep->image_reps()));
624         break;
625       }
626 #if defined(TOOLKIT_GTK)
627       case kImageRepGdk: {
628         internal::ImageRepGdk* native_rep =
629             GetRepresentation(kImageRepGdk, true)->AsImageRepGdk();
630         rep = new internal::ImageRepSkia(new ImageSkia(
631             internal::ImageSkiaFromGdkPixbuf(native_rep->pixbuf())));
632         break;
633       }
634 #elif defined(OS_IOS)
635       case kImageRepCocoaTouch: {
636         internal::ImageRepCocoaTouch* native_rep =
637             GetRepresentation(kImageRepCocoaTouch, true)
638                 ->AsImageRepCocoaTouch();
639         rep = new internal::ImageRepSkia(new ImageSkia(
640             ImageSkiaFromUIImage(native_rep->image())));
641         break;
642       }
643 #elif defined(OS_MACOSX)
644       case kImageRepCocoa: {
645         internal::ImageRepCocoa* native_rep =
646             GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
647         rep = new internal::ImageRepSkia(new ImageSkia(
648             ImageSkiaFromNSImage(native_rep->image())));
649         break;
650       }
651 #endif
652       default:
653         NOTREACHED();
654     }
655     CHECK(rep);
656     AddRepresentation(rep);
657   }
658   return rep->AsImageRepSkia()->image();
659 }
660 
661 #if defined(TOOLKIT_GTK)
ToGdkPixbuf() const662 GdkPixbuf* Image::ToGdkPixbuf() const {
663   internal::ImageRep* rep = GetRepresentation(kImageRepGdk, false);
664   if (!rep) {
665     switch (DefaultRepresentationType()) {
666       case kImageRepPNG: {
667         internal::ImageRepPNG* png_rep =
668             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
669         rep = new internal::ImageRepGdk(internal::GdkPixbufFromPNG(
670             png_rep->image_reps()));
671         break;
672       }
673       case kImageRepSkia: {
674         internal::ImageRepSkia* skia_rep =
675             GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
676         rep = new internal::ImageRepGdk(gfx::GdkPixbufFromSkBitmap(
677             *skia_rep->image()->bitmap()));
678         break;
679       }
680       default:
681         NOTREACHED();
682     }
683     CHECK(rep);
684     AddRepresentation(rep);
685   }
686   return rep->AsImageRepGdk()->pixbuf();
687 }
688 
ToCairo() const689 CairoCachedSurface* const Image::ToCairo() const {
690   internal::ImageRep* rep = GetRepresentation(kImageRepCairo, false);
691   if (!rep) {
692     // Handle any-to-Cairo conversion. This may create and cache an intermediate
693     // pixbuf before sending the data to the display server.
694     rep = new internal::ImageRepCairo(ToGdkPixbuf());
695     CHECK(rep);
696     AddRepresentation(rep);
697   }
698   return rep->AsImageRepCairo()->surface();
699 }
700 #endif
701 
702 #if defined(OS_IOS)
ToUIImage() const703 UIImage* Image::ToUIImage() const {
704   internal::ImageRep* rep = GetRepresentation(kImageRepCocoaTouch, false);
705   if (!rep) {
706     switch (DefaultRepresentationType()) {
707       case kImageRepPNG: {
708         internal::ImageRepPNG* png_rep =
709             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
710         rep = new internal::ImageRepCocoaTouch(internal::CreateUIImageFromPNG(
711             png_rep->image_reps()));
712         break;
713       }
714       case kImageRepSkia: {
715         internal::ImageRepSkia* skia_rep =
716             GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
717         UIImage* image = UIImageFromImageSkia(*skia_rep->image());
718         base::mac::NSObjectRetain(image);
719         rep = new internal::ImageRepCocoaTouch(image);
720         break;
721       }
722       default:
723         NOTREACHED();
724     }
725     CHECK(rep);
726     AddRepresentation(rep);
727   }
728   return rep->AsImageRepCocoaTouch()->image();
729 }
730 #elif defined(OS_MACOSX)
ToNSImage() const731 NSImage* Image::ToNSImage() const {
732   internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false);
733   if (!rep) {
734     CGColorSpaceRef default_representation_color_space =
735         storage_->default_representation_color_space();
736 
737     switch (DefaultRepresentationType()) {
738       case kImageRepPNG: {
739         internal::ImageRepPNG* png_rep =
740             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
741         rep = new internal::ImageRepCocoa(internal::NSImageFromPNG(
742             png_rep->image_reps(), default_representation_color_space));
743         break;
744       }
745       case kImageRepSkia: {
746         internal::ImageRepSkia* skia_rep =
747             GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
748         NSImage* image = NSImageFromImageSkiaWithColorSpace(*skia_rep->image(),
749             default_representation_color_space);
750         base::mac::NSObjectRetain(image);
751         rep = new internal::ImageRepCocoa(image);
752         break;
753       }
754       default:
755         NOTREACHED();
756     }
757     CHECK(rep);
758     AddRepresentation(rep);
759   }
760   return rep->AsImageRepCocoa()->image();
761 }
762 #endif
763 
As1xPNGBytes() const764 scoped_refptr<base::RefCountedMemory> Image::As1xPNGBytes() const {
765   if (IsEmpty())
766     return new base::RefCountedBytes();
767 
768   internal::ImageRep* rep = GetRepresentation(kImageRepPNG, false);
769 
770   if (rep) {
771     const std::vector<gfx::ImagePNGRep>& image_png_reps =
772         rep->AsImageRepPNG()->image_reps();
773     for (size_t i = 0; i < image_png_reps.size(); ++i) {
774       if (image_png_reps[i].scale == 1.0f)
775         return image_png_reps[i].raw_data;
776     }
777     return new base::RefCountedBytes();
778   }
779 
780   scoped_refptr<base::RefCountedMemory> png_bytes(NULL);
781   switch (DefaultRepresentationType()) {
782 #if defined(TOOLKIT_GTK)
783     case kImageRepGdk: {
784       internal::ImageRepGdk* gdk_rep =
785           GetRepresentation(kImageRepGdk, true)->AsImageRepGdk();
786       png_bytes = internal::Get1xPNGBytesFromPixbuf(gdk_rep->pixbuf());
787       break;
788     }
789 #elif defined(OS_IOS)
790     case kImageRepCocoaTouch: {
791       internal::ImageRepCocoaTouch* cocoa_touch_rep =
792           GetRepresentation(kImageRepCocoaTouch, true)
793               ->AsImageRepCocoaTouch();
794       png_bytes = internal::Get1xPNGBytesFromUIImage(
795           cocoa_touch_rep->image());
796       break;
797     }
798 #elif defined(OS_MACOSX)
799     case kImageRepCocoa: {
800       internal::ImageRepCocoa* cocoa_rep =
801           GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
802       png_bytes = internal::Get1xPNGBytesFromNSImage(cocoa_rep->image());
803       break;
804     }
805 #endif
806     case kImageRepSkia: {
807       internal::ImageRepSkia* skia_rep =
808           GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
809       png_bytes = internal::Get1xPNGBytesFromImageSkia(skia_rep->image());
810       break;
811     }
812     default:
813       NOTREACHED();
814   }
815   if (!png_bytes.get() || !png_bytes->size()) {
816     // Add an ImageRepPNG with no data such that the conversion is not
817     // attempted each time we want the PNG bytes.
818     AddRepresentation(new internal::ImageRepPNG());
819     return new base::RefCountedBytes();
820   }
821 
822   // Do not insert representations for scale factors other than 1x even if
823   // they are available because:
824   // - Only the 1x PNG bytes can be accessed.
825   // - ImageRepPNG is not used as an intermediate type in converting to a
826   //   final type eg (converting from ImageRepSkia to ImageRepPNG to get an
827   //   ImageRepCocoa).
828   std::vector<ImagePNGRep> image_png_reps;
829   image_png_reps.push_back(gfx::ImagePNGRep(png_bytes, 1.0f));
830   rep = new internal::ImageRepPNG(image_png_reps);
831   AddRepresentation(rep);
832   return png_bytes;
833 }
834 
AsBitmap() const835 SkBitmap Image::AsBitmap() const {
836   return IsEmpty() ? SkBitmap() : *ToSkBitmap();
837 }
838 
AsImageSkia() const839 ImageSkia Image::AsImageSkia() const {
840   return IsEmpty() ? ImageSkia() : *ToImageSkia();
841 }
842 
843 #if defined(OS_MACOSX) && !defined(OS_IOS)
AsNSImage() const844 NSImage* Image::AsNSImage() const {
845   return IsEmpty() ? nil : ToNSImage();
846 }
847 #endif
848 
Copy1xPNGBytes() const849 scoped_refptr<base::RefCountedMemory> Image::Copy1xPNGBytes() const {
850   scoped_refptr<base::RefCountedMemory> original = As1xPNGBytes();
851   scoped_refptr<base::RefCountedBytes> copy(new base::RefCountedBytes());
852   copy->data().assign(original->front(), original->front() + original->size());
853   return copy;
854 }
855 
CopyImageSkia() const856 ImageSkia* Image::CopyImageSkia() const {
857   return new ImageSkia(*ToImageSkia());
858 }
859 
CopySkBitmap() const860 SkBitmap* Image::CopySkBitmap() const {
861   return new SkBitmap(*ToSkBitmap());
862 }
863 
864 #if defined(TOOLKIT_GTK)
CopyGdkPixbuf() const865 GdkPixbuf* Image::CopyGdkPixbuf() const {
866   GdkPixbuf* pixbuf = ToGdkPixbuf();
867   g_object_ref(pixbuf);
868   return pixbuf;
869 }
870 #endif
871 
872 #if defined(OS_IOS)
CopyUIImage() const873 UIImage* Image::CopyUIImage() const {
874   UIImage* image = ToUIImage();
875   base::mac::NSObjectRetain(image);
876   return image;
877 }
878 #elif defined(OS_MACOSX)
CopyNSImage() const879 NSImage* Image::CopyNSImage() const {
880   NSImage* image = ToNSImage();
881   base::mac::NSObjectRetain(image);
882   return image;
883 }
884 #endif
885 
HasRepresentation(RepresentationType type) const886 bool Image::HasRepresentation(RepresentationType type) const {
887   return storage_.get() && storage_->representations().count(type) != 0;
888 }
889 
RepresentationCount() const890 size_t Image::RepresentationCount() const {
891   if (!storage_.get())
892     return 0;
893 
894   return storage_->representations().size();
895 }
896 
IsEmpty() const897 bool Image::IsEmpty() const {
898   return RepresentationCount() == 0;
899 }
900 
Width() const901 int Image::Width() const {
902   if (IsEmpty())
903     return 0;
904   return GetRepresentation(DefaultRepresentationType(), true)->Width();
905 }
906 
Height() const907 int Image::Height() const {
908   if (IsEmpty())
909     return 0;
910   return GetRepresentation(DefaultRepresentationType(), true)->Height();
911 }
912 
Size() const913 gfx::Size Image::Size() const {
914   if (IsEmpty())
915     return gfx::Size();
916   return GetRepresentation(DefaultRepresentationType(), true)->Size();
917 }
918 
SwapRepresentations(gfx::Image * other)919 void Image::SwapRepresentations(gfx::Image* other) {
920   storage_.swap(other->storage_);
921 }
922 
923 #if defined(OS_MACOSX)  && !defined(OS_IOS)
SetSourceColorSpace(CGColorSpaceRef color_space)924 void Image::SetSourceColorSpace(CGColorSpaceRef color_space) {
925   if (storage_.get())
926     storage_->set_default_representation_color_space(color_space);
927 }
928 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
929 
DefaultRepresentationType() const930 Image::RepresentationType Image::DefaultRepresentationType() const {
931   CHECK(storage_.get());
932   RepresentationType default_type = storage_->default_representation_type();
933   // The conversions above assume that the default representation type is never
934   // kImageRepCairo.
935   DCHECK_NE(default_type, kImageRepCairo);
936   return default_type;
937 }
938 
GetRepresentation(RepresentationType rep_type,bool must_exist) const939 internal::ImageRep* Image::GetRepresentation(
940     RepresentationType rep_type, bool must_exist) const {
941   CHECK(storage_.get());
942   RepresentationMap::iterator it = storage_->representations().find(rep_type);
943   if (it == storage_->representations().end()) {
944     CHECK(!must_exist);
945     return NULL;
946   }
947   return it->second;
948 }
949 
AddRepresentation(internal::ImageRep * rep) const950 void Image::AddRepresentation(internal::ImageRep* rep) const {
951   CHECK(storage_.get());
952   storage_->representations().insert(std::make_pair(rep->type(), rep));
953 }
954 
955 }  // namespace gfx
956