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