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 <utility>
9 #include <vector>
10 
11 #include "base/logging.h"
12 #include "base/macros.h"
13 #include "base/memory/ptr_util.h"
14 #include "build/build_config.h"
15 #include "third_party/skia/include/core/SkBitmap.h"
16 #include "ui/gfx/geometry/size.h"
17 #include "ui/gfx/image/image_platform.h"
18 #include "ui/gfx/image/image_png_rep.h"
19 #include "ui/gfx/image/image_skia.h"
20 
21 #if defined(OS_IOS)
22 #include "base/mac/foundation_util.h"
23 #include "ui/gfx/image/image_skia_util_ios.h"
24 #elif defined(OS_MACOSX)
25 #include "base/mac/foundation_util.h"
26 #include "base/mac/mac_util.h"
27 #include "ui/gfx/image/image_skia_util_mac.h"
28 #endif
29 
30 namespace gfx {
31 
32 namespace {
33 
34 using RepresentationMap =
35     std::map<Image::RepresentationType, std::unique_ptr<internal::ImageRep>>;
36 
37 }  // namespace
38 
39 namespace internal {
40 
41 class ImageRepPNG;
42 class ImageRepSkia;
43 class ImageRepCocoa;
44 class ImageRepCocoaTouch;
45 
46 // An ImageRep is the object that holds the backing memory for an Image. Each
47 // RepresentationType has an ImageRep subclass that is responsible for freeing
48 // the memory that the ImageRep holds. When an ImageRep is created, it expects
49 // to take ownership of the image, without having to retain it or increase its
50 // reference count.
51 class ImageRep {
52  public:
ImageRep(Image::RepresentationType rep)53   explicit ImageRep(Image::RepresentationType rep) : type_(rep) {}
54 
55   // Deletes the associated pixels of an ImageRep.
~ImageRep()56   virtual ~ImageRep() {}
57 
58   // Cast helpers ("fake RTTI").
AsImageRepPNG() const59   const ImageRepPNG* AsImageRepPNG() const {
60     CHECK_EQ(type_, Image::kImageRepPNG);
61     return reinterpret_cast<const ImageRepPNG*>(this);
62   }
AsImageRepPNG()63   ImageRepPNG* AsImageRepPNG() {
64     return const_cast<ImageRepPNG*>(
65         static_cast<const ImageRep*>(this)->AsImageRepPNG());
66   }
67 
AsImageRepSkia() const68   const ImageRepSkia* AsImageRepSkia() const {
69     CHECK_EQ(type_, Image::kImageRepSkia);
70     return reinterpret_cast<const ImageRepSkia*>(this);
71   }
AsImageRepSkia()72   ImageRepSkia* AsImageRepSkia() {
73     return const_cast<ImageRepSkia*>(
74         static_cast<const ImageRep*>(this)->AsImageRepSkia());
75   }
76 
77 #if defined(OS_IOS)
AsImageRepCocoaTouch() const78   const ImageRepCocoaTouch* AsImageRepCocoaTouch() const {
79     CHECK_EQ(type_, Image::kImageRepCocoaTouch);
80     return reinterpret_cast<const ImageRepCocoaTouch*>(this);
81   }
AsImageRepCocoaTouch()82   ImageRepCocoaTouch* AsImageRepCocoaTouch() {
83     return const_cast<ImageRepCocoaTouch*>(
84         static_cast<const ImageRep*>(this)->AsImageRepCocoaTouch());
85   }
86 #elif defined(OS_MACOSX)
AsImageRepCocoa() const87   const ImageRepCocoa* AsImageRepCocoa() const {
88     CHECK_EQ(type_, Image::kImageRepCocoa);
89     return reinterpret_cast<const ImageRepCocoa*>(this);
90   }
AsImageRepCocoa()91   ImageRepCocoa* AsImageRepCocoa() {
92     return const_cast<ImageRepCocoa*>(
93         static_cast<const ImageRep*>(this)->AsImageRepCocoa());
94   }
95 #endif
96 
type() const97   Image::RepresentationType type() const { return type_; }
98 
99   virtual int Width() const = 0;
100   virtual int Height() const = 0;
101   virtual gfx::Size Size() const = 0;
102 
103  private:
104   Image::RepresentationType type_;
105 };
106 
107 class ImageRepPNG : public ImageRep {
108  public:
ImageRepPNG()109   ImageRepPNG() : ImageRep(Image::kImageRepPNG) {
110   }
111 
ImageRepPNG(const std::vector<ImagePNGRep> & image_png_reps)112   explicit ImageRepPNG(const std::vector<ImagePNGRep>& image_png_reps)
113       : ImageRep(Image::kImageRepPNG), image_png_reps_(image_png_reps) {}
114 
~ImageRepPNG()115   ~ImageRepPNG() override {}
116 
Width() const117   int Width() const override { return Size().width(); }
118 
Height() const119   int Height() const override { return Size().height(); }
120 
Size() const121   gfx::Size Size() const override {
122     // Read the PNG data to get the image size, caching it.
123     if (!size_cache_) {
124       for (auto it = image_reps().begin(); it != image_reps().end(); ++it) {
125         if (it->scale == 1.0f) {
126           size_cache_ = it->Size();
127           return *size_cache_;
128         }
129       }
130       size_cache_ = gfx::Size();
131     }
132 
133     return *size_cache_;
134   }
135 
image_reps() const136   const std::vector<ImagePNGRep>& image_reps() const { return image_png_reps_; }
137 
138  private:
139   std::vector<ImagePNGRep> image_png_reps_;
140 
141   // Cached to avoid having to parse the raw data multiple times.
142   mutable base::Optional<gfx::Size> size_cache_;
143 
144   DISALLOW_COPY_AND_ASSIGN(ImageRepPNG);
145 };
146 
147 class ImageRepSkia : public ImageRep {
148  public:
ImageRepSkia(ImageSkia image)149   explicit ImageRepSkia(ImageSkia image)
150       : ImageRep(Image::kImageRepSkia), image_(image) {}
151 
~ImageRepSkia()152   ~ImageRepSkia() override {}
153 
Width() const154   int Width() const override { return image_.width(); }
155 
Height() const156   int Height() const override { return image_.height(); }
157 
Size() const158   gfx::Size Size() const override { return image_.size(); }
159 
image() const160   const ImageSkia* image() const { return &image_; }
image()161   ImageSkia* image() { return &image_; }
162 
163  private:
164   ImageSkia image_;
165 
166   DISALLOW_COPY_AND_ASSIGN(ImageRepSkia);
167 };
168 
169 #if defined(OS_IOS)
170 class ImageRepCocoaTouch : public ImageRep {
171  public:
ImageRepCocoaTouch(UIImage * image)172   explicit ImageRepCocoaTouch(UIImage* image)
173       : ImageRep(Image::kImageRepCocoaTouch),
174         image_(image) {
175     CHECK(image_);
176     base::mac::NSObjectRetain(image_);
177   }
178 
~ImageRepCocoaTouch()179   ~ImageRepCocoaTouch() override {
180     base::mac::NSObjectRelease(image_);
181     image_ = nil;
182   }
183 
Width() const184   int Width() const override { return Size().width(); }
185 
Height() const186   int Height() const override { return Size().height(); }
187 
Size() const188   gfx::Size Size() const override { return internal::UIImageSize(image_); }
189 
image() const190   UIImage* image() const { return image_; }
191 
192  private:
193   UIImage* image_;
194 
195   DISALLOW_COPY_AND_ASSIGN(ImageRepCocoaTouch);
196 };
197 #elif defined(OS_MACOSX)
198 class ImageRepCocoa : public ImageRep {
199  public:
ImageRepCocoa(NSImage * image)200   explicit ImageRepCocoa(NSImage* image)
201       : ImageRep(Image::kImageRepCocoa),
202         image_(image) {
203     CHECK(image_);
204     base::mac::NSObjectRetain(image_);
205   }
206 
~ImageRepCocoa()207   ~ImageRepCocoa() override {
208     base::mac::NSObjectRelease(image_);
209     image_ = nil;
210   }
211 
Width() const212   int Width() const override { return Size().width(); }
213 
Height() const214   int Height() const override { return Size().height(); }
215 
Size() const216   gfx::Size Size() const override { return internal::NSImageSize(image_); }
217 
image() const218   NSImage* image() const { return image_; }
219 
220  private:
221   NSImage* image_;
222 
223   DISALLOW_COPY_AND_ASSIGN(ImageRepCocoa);
224 };
225 #endif  // defined(OS_MACOSX)
226 
227 // The Storage class acts similarly to the pixels in a SkBitmap: the Image
228 // class holds a refptr instance of Storage, which in turn holds all the
229 // ImageReps. This way, the Image can be cheaply copied.
230 //
231 // This class is deliberately not RefCountedThreadSafe. Making it so does not
232 // solve threading issues, as gfx::Image and its internal classes are
233 // themselves not threadsafe.
234 class ImageStorage : public base::RefCounted<ImageStorage> {
235  public:
ImageStorage(Image::RepresentationType default_type)236   explicit ImageStorage(Image::RepresentationType default_type)
237       : default_representation_type_(default_type)
238 #if defined(OS_MACOSX) && !defined(OS_IOS)
239         ,
240         default_representation_color_space_(
241             base::mac::GetGenericRGBColorSpace())
242 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
243   {
244   }
245 
default_representation_type() const246   Image::RepresentationType default_representation_type() const {
247     DCHECK(IsOnValidSequence());
248     return default_representation_type_;
249   }
250 
HasRepresentation(Image::RepresentationType type) const251   bool HasRepresentation(Image::RepresentationType type) const {
252     DCHECK(IsOnValidSequence());
253     return representations_.count(type) != 0;
254   }
255 
RepresentationCount() const256   size_t RepresentationCount() const {
257     DCHECK(IsOnValidSequence());
258     return representations_.size();
259   }
260 
GetRepresentation(Image::RepresentationType rep_type,bool must_exist) const261   const ImageRep* GetRepresentation(Image::RepresentationType rep_type,
262                                     bool must_exist) const {
263     DCHECK(IsOnValidSequence());
264     RepresentationMap::const_iterator it = representations_.find(rep_type);
265     if (it == representations_.end()) {
266       CHECK(!must_exist);
267       return nullptr;
268     }
269     return it->second.get();
270   }
271 
AddRepresentation(std::unique_ptr<ImageRep> rep) const272   const ImageRep* AddRepresentation(std::unique_ptr<ImageRep> rep) const {
273     DCHECK(IsOnValidSequence());
274     Image::RepresentationType type = rep->type();
275     auto result = representations_.emplace(type, std::move(rep));
276 
277     // insert should not fail (implies that there was already a representation
278     // of that type in the map).
279     CHECK(result.second) << "type was already in map.";
280 
281     return result.first->second.get();
282   }
283 
284 #if defined(OS_MACOSX) && !defined(OS_IOS)
set_default_representation_color_space(CGColorSpaceRef color_space)285   void set_default_representation_color_space(CGColorSpaceRef color_space) {
286     DCHECK(IsOnValidSequence());
287     default_representation_color_space_ = color_space;
288   }
default_representation_color_space() const289   CGColorSpaceRef default_representation_color_space() const {
290     DCHECK(IsOnValidSequence());
291     return default_representation_color_space_;
292   }
293 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
294 
295  private:
296   friend class base::RefCounted<ImageStorage>;
297 
~ImageStorage()298   ~ImageStorage() {}
299 
300   // The type of image that was passed to the constructor. This key will always
301   // exist in the |representations_| map.
302   Image::RepresentationType default_representation_type_;
303 
304 #if defined(OS_MACOSX) && !defined(OS_IOS)
305   // The default representation's colorspace. This is used for converting to
306   // NSImage. This field exists to compensate for PNGCodec not writing or
307   // reading colorspace ancillary chunks. (sRGB, iCCP).
308   // Not owned.
309   CGColorSpaceRef default_representation_color_space_;
310 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
311 
312   // All the representations of an Image. Size will always be at least one, with
313   // more for any converted representations.
314   mutable RepresentationMap representations_;
315 
316   DISALLOW_COPY_AND_ASSIGN(ImageStorage);
317 };
318 
319 }  // namespace internal
320 
Image()321 Image::Image() {
322   // |storage_| is null for empty Images.
323 }
324 
Image(const std::vector<ImagePNGRep> & image_reps)325 Image::Image(const std::vector<ImagePNGRep>& image_reps) {
326   // Do not store obviously invalid ImagePNGReps.
327   std::vector<ImagePNGRep> filtered;
328   for (size_t i = 0; i < image_reps.size(); ++i) {
329     if (image_reps[i].raw_data.get() && image_reps[i].raw_data->size())
330       filtered.push_back(image_reps[i]);
331   }
332 
333   if (filtered.empty())
334     return;
335 
336   storage_ = new internal::ImageStorage(Image::kImageRepPNG);
337   AddRepresentation(std::make_unique<internal::ImageRepPNG>(filtered));
338 }
339 
Image(const ImageSkia & image)340 Image::Image(const ImageSkia& image) {
341   if (!image.isNull()) {
342     storage_ = new internal::ImageStorage(Image::kImageRepSkia);
343     AddRepresentation(std::make_unique<internal::ImageRepSkia>(image));
344   }
345 }
346 
347 #if defined(OS_IOS)
Image(UIImage * image)348 Image::Image(UIImage* image) {
349   if (image) {
350     storage_ = new internal::ImageStorage(Image::kImageRepCocoaTouch);
351     AddRepresentation(std::make_unique<internal::ImageRepCocoaTouch>(image));
352   }
353 }
354 #elif defined(OS_MACOSX)
Image(NSImage * image)355 Image::Image(NSImage* image) {
356   if (image) {
357     storage_ = new internal::ImageStorage(Image::kImageRepCocoa);
358     AddRepresentation(std::make_unique<internal::ImageRepCocoa>(image));
359   }
360 }
361 #endif
362 
363 Image::Image(const Image& other) = default;
364 
365 Image::Image(Image&& other) noexcept = default;
366 
367 Image& Image::operator=(const Image& other) = default;
368 
369 Image& Image::operator=(Image&& other) noexcept = default;
370 
~Image()371 Image::~Image() {}
372 
373 // static
CreateFrom1xBitmap(const SkBitmap & bitmap)374 Image Image::CreateFrom1xBitmap(const SkBitmap& bitmap) {
375   return Image(ImageSkia::CreateFrom1xBitmap(bitmap));
376 }
377 
378 // static
CreateFrom1xPNGBytes(const unsigned char * input,size_t input_size)379 Image Image::CreateFrom1xPNGBytes(const unsigned char* input,
380                                   size_t input_size) {
381   if (input_size == 0u)
382     return Image();
383 
384   scoped_refptr<base::RefCountedBytes> raw_data(new base::RefCountedBytes());
385   raw_data->data().assign(input, input + input_size);
386 
387   return CreateFrom1xPNGBytes(raw_data);
388 }
389 
CreateFrom1xPNGBytes(const scoped_refptr<base::RefCountedMemory> & input)390 Image Image::CreateFrom1xPNGBytes(
391     const scoped_refptr<base::RefCountedMemory>& input) {
392   if (!input.get() || input->size() == 0u)
393     return Image();
394 
395   std::vector<ImagePNGRep> image_reps;
396   image_reps.push_back(ImagePNGRep(input, 1.0f));
397   return Image(image_reps);
398 }
399 
ToSkBitmap() const400 const SkBitmap* Image::ToSkBitmap() const {
401   // Possibly create and cache an intermediate ImageRepSkia.
402   return ToImageSkia()->bitmap();
403 }
404 
ToImageSkia() const405 const ImageSkia* Image::ToImageSkia() const {
406   const internal::ImageRep* rep = GetRepresentation(kImageRepSkia, false);
407   if (!rep) {
408     std::unique_ptr<internal::ImageRep> scoped_rep;
409     switch (DefaultRepresentationType()) {
410       case kImageRepPNG: {
411         const internal::ImageRepPNG* png_rep =
412             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
413         scoped_rep = std::make_unique<internal::ImageRepSkia>(
414             internal::ImageSkiaFromPNG(png_rep->image_reps()));
415         break;
416       }
417 #if defined(OS_IOS)
418       case kImageRepCocoaTouch: {
419         const internal::ImageRepCocoaTouch* native_rep =
420             GetRepresentation(kImageRepCocoaTouch, true)
421                 ->AsImageRepCocoaTouch();
422         scoped_rep = std::make_unique<internal::ImageRepSkia>(
423             ImageSkia(ImageSkiaFromUIImage(native_rep->image())));
424         break;
425       }
426 #elif defined(OS_MACOSX)
427       case kImageRepCocoa: {
428         const internal::ImageRepCocoa* native_rep =
429             GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
430         scoped_rep = std::make_unique<internal::ImageRepSkia>(
431             ImageSkia(ImageSkiaFromNSImage(native_rep->image())));
432         break;
433       }
434 #endif
435       default:
436         NOTREACHED();
437     }
438     CHECK(scoped_rep);
439     rep = AddRepresentation(std::move(scoped_rep));
440   }
441   return rep->AsImageRepSkia()->image();
442 }
443 
444 #if defined(OS_IOS)
ToUIImage() const445 UIImage* Image::ToUIImage() const {
446   const internal::ImageRep* rep = GetRepresentation(kImageRepCocoaTouch, false);
447   if (!rep) {
448     std::unique_ptr<internal::ImageRep> scoped_rep;
449     switch (DefaultRepresentationType()) {
450       case kImageRepPNG: {
451         const internal::ImageRepPNG* png_rep =
452             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
453         scoped_rep = std::make_unique<internal::ImageRepCocoaTouch>(
454             internal::UIImageFromPNG(png_rep->image_reps()));
455         break;
456       }
457       case kImageRepSkia: {
458         const internal::ImageRepSkia* skia_rep =
459             GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
460         UIImage* image = UIImageFromImageSkia(*skia_rep->image());
461         scoped_rep = std::make_unique<internal::ImageRepCocoaTouch>(image);
462         break;
463       }
464       default:
465         NOTREACHED();
466     }
467     CHECK(scoped_rep);
468     rep = AddRepresentation(std::move(scoped_rep));
469   }
470   return rep->AsImageRepCocoaTouch()->image();
471 }
472 #elif defined(OS_MACOSX)
ToNSImage() const473 NSImage* Image::ToNSImage() const {
474   const internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false);
475   if (!rep) {
476     std::unique_ptr<internal::ImageRep> scoped_rep;
477     CGColorSpaceRef default_representation_color_space =
478         storage()->default_representation_color_space();
479 
480     switch (DefaultRepresentationType()) {
481       case kImageRepPNG: {
482         const internal::ImageRepPNG* png_rep =
483             GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
484         scoped_rep =
485             std::make_unique<internal::ImageRepCocoa>(internal::NSImageFromPNG(
486                 png_rep->image_reps(), default_representation_color_space));
487         break;
488       }
489       case kImageRepSkia: {
490         const internal::ImageRepSkia* skia_rep =
491             GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
492         NSImage* image = NSImageFromImageSkiaWithColorSpace(*skia_rep->image(),
493             default_representation_color_space);
494         scoped_rep = std::make_unique<internal::ImageRepCocoa>(image);
495         break;
496       }
497       default:
498         NOTREACHED();
499     }
500     CHECK(scoped_rep);
501     rep = AddRepresentation(std::move(scoped_rep));
502   }
503   return rep->AsImageRepCocoa()->image();
504 }
505 #endif
506 
As1xPNGBytes() const507 scoped_refptr<base::RefCountedMemory> Image::As1xPNGBytes() const {
508   if (IsEmpty())
509     return new base::RefCountedBytes();
510 
511   const internal::ImageRep* rep = GetRepresentation(kImageRepPNG, false);
512 
513   if (rep) {
514     const std::vector<ImagePNGRep>& image_png_reps =
515         rep->AsImageRepPNG()->image_reps();
516     for (size_t i = 0; i < image_png_reps.size(); ++i) {
517       if (image_png_reps[i].scale == 1.0f)
518         return image_png_reps[i].raw_data;
519     }
520     return new base::RefCountedBytes();
521   }
522 
523   scoped_refptr<base::RefCountedMemory> png_bytes;
524   switch (DefaultRepresentationType()) {
525 #if defined(OS_IOS)
526     case kImageRepCocoaTouch: {
527       const internal::ImageRepCocoaTouch* cocoa_touch_rep =
528           GetRepresentation(kImageRepCocoaTouch, true)->AsImageRepCocoaTouch();
529       png_bytes = internal::Get1xPNGBytesFromUIImage(
530           cocoa_touch_rep->image());
531       break;
532     }
533 #elif defined(OS_MACOSX)
534     case kImageRepCocoa: {
535       const internal::ImageRepCocoa* cocoa_rep =
536           GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
537       png_bytes = internal::Get1xPNGBytesFromNSImage(cocoa_rep->image());
538       break;
539     }
540 #endif
541     case kImageRepSkia: {
542       const internal::ImageRepSkia* skia_rep =
543           GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
544       png_bytes = internal::Get1xPNGBytesFromImageSkia(skia_rep->image());
545       break;
546     }
547     default:
548       NOTREACHED();
549   }
550   if (!png_bytes.get() || !png_bytes->size()) {
551     // Add an ImageRepPNG with no data such that the conversion is not
552     // attempted each time we want the PNG bytes.
553     AddRepresentation(base::WrapUnique(new internal::ImageRepPNG()));
554     return new base::RefCountedBytes();
555   }
556 
557   // Do not insert representations for scale factors other than 1x even if
558   // they are available because:
559   // - Only the 1x PNG bytes can be accessed.
560   // - ImageRepPNG is not used as an intermediate type in converting to a
561   //   final type eg (converting from ImageRepSkia to ImageRepPNG to get an
562   //   ImageRepCocoa).
563   std::vector<ImagePNGRep> image_png_reps;
564   image_png_reps.push_back(ImagePNGRep(png_bytes, 1.0f));
565   AddRepresentation(
566       base::WrapUnique(new internal::ImageRepPNG(image_png_reps)));
567   return png_bytes;
568 }
569 
AsBitmap() const570 SkBitmap Image::AsBitmap() const {
571   return IsEmpty() ? SkBitmap() : *ToSkBitmap();
572 }
573 
AsImageSkia() const574 ImageSkia Image::AsImageSkia() const {
575   return IsEmpty() ? ImageSkia() : *ToImageSkia();
576 }
577 
578 #if defined(OS_MACOSX) && !defined(OS_IOS)
AsNSImage() const579 NSImage* Image::AsNSImage() const {
580   return IsEmpty() ? nil : ToNSImage();
581 }
582 #endif
583 
HasRepresentation(RepresentationType type) const584 bool Image::HasRepresentation(RepresentationType type) const {
585   return storage() && storage()->HasRepresentation(type);
586 }
587 
RepresentationCount() const588 size_t Image::RepresentationCount() const {
589   return storage() ? storage()->RepresentationCount() : 0;
590 }
591 
IsEmpty() const592 bool Image::IsEmpty() const {
593   return RepresentationCount() == 0;
594 }
595 
Width() const596 int Image::Width() const {
597   if (IsEmpty())
598     return 0;
599   return GetRepresentation(DefaultRepresentationType(), true)->Width();
600 }
601 
Height() const602 int Image::Height() const {
603   if (IsEmpty())
604     return 0;
605   return GetRepresentation(DefaultRepresentationType(), true)->Height();
606 }
607 
Size() const608 gfx::Size Image::Size() const {
609   if (IsEmpty())
610     return gfx::Size();
611   return GetRepresentation(DefaultRepresentationType(), true)->Size();
612 }
613 
614 #if defined(OS_MACOSX)  && !defined(OS_IOS)
SetSourceColorSpace(CGColorSpaceRef color_space)615 void Image::SetSourceColorSpace(CGColorSpaceRef color_space) {
616   if (storage())
617     storage()->set_default_representation_color_space(color_space);
618 }
619 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
620 
DefaultRepresentationType() const621 Image::RepresentationType Image::DefaultRepresentationType() const {
622   CHECK(storage());
623   return storage()->default_representation_type();
624 }
625 
GetRepresentation(RepresentationType rep_type,bool must_exist) const626 const internal::ImageRep* Image::GetRepresentation(RepresentationType rep_type,
627                                                    bool must_exist) const {
628   CHECK(storage());
629   return storage()->GetRepresentation(rep_type, must_exist);
630 }
631 
AddRepresentation(std::unique_ptr<internal::ImageRep> rep) const632 const internal::ImageRep* Image::AddRepresentation(
633     std::unique_ptr<internal::ImageRep> rep) const {
634   CHECK(storage());
635   return storage()->AddRepresentation(std::move(rep));
636 }
637 
638 }  // namespace gfx
639