GoogleURLTrackerInfoBarDelegate: Initialize uninitialized member in constructor.
[chromium-blink-merge.git] / ui / gfx / image / image.cc
blob5c81a5519ed6be6637bfbb8da200dfebd4ba061c
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.
5 #include "ui/gfx/image/image.h"
7 #include <algorithm>
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"
17 #if !defined(OS_IOS)
18 #include "ui/gfx/codec/png_codec.h"
19 #endif
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/mac_util.h"
26 #include "ui/gfx/image/image_skia_util_mac.h"
27 #endif
29 namespace gfx {
31 namespace internal {
33 #if defined(OS_IOS)
34 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromUIImage(
35 UIImage* uiimage);
36 // Caller takes ownership of the returned UIImage.
37 UIImage* CreateUIImageFromPNG(
38 const std::vector<gfx::ImagePNGRep>& image_png_reps);
39 gfx::Size UIImageSize(UIImage* image);
40 #elif defined(OS_MACOSX)
41 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromNSImage(
42 NSImage* nsimage);
43 // Caller takes ownership of the returned NSImage.
44 NSImage* NSImageFromPNG(const std::vector<gfx::ImagePNGRep>& image_png_reps,
45 CGColorSpaceRef color_space);
46 gfx::Size NSImageSize(NSImage* image);
47 #endif // defined(OS_MACOSX)
49 #if defined(OS_IOS)
50 ImageSkia* ImageSkiaFromPNG(
51 const std::vector<gfx::ImagePNGRep>& image_png_reps);
52 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
53 const ImageSkia* skia);
54 #else
55 // Returns a 16x16 red image to visually show error in decoding PNG.
56 // Caller takes ownership of returned ImageSkia.
57 ImageSkia* GetErrorImageSkia() {
58 SkBitmap bitmap;
59 bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
60 bitmap.allocPixels();
61 bitmap.eraseARGB(0xff, 0xff, 0, 0);
62 return new gfx::ImageSkia(gfx::ImageSkiaRep(bitmap, 1.0f));
65 ImageSkia* ImageSkiaFromPNG(
66 const std::vector<gfx::ImagePNGRep>& image_png_reps) {
67 if (image_png_reps.empty())
68 return GetErrorImageSkia();
70 scoped_ptr<gfx::ImageSkia> image_skia(new ImageSkia());
71 for (size_t i = 0; i < image_png_reps.size(); ++i) {
72 scoped_refptr<base::RefCountedMemory> raw_data =
73 image_png_reps[i].raw_data;
74 CHECK(raw_data.get());
75 SkBitmap bitmap;
76 if (!gfx::PNGCodec::Decode(raw_data->front(), raw_data->size(),
77 &bitmap)) {
78 LOG(ERROR) << "Unable to decode PNG for "
79 << image_png_reps[i].scale
80 << ".";
81 return GetErrorImageSkia();
83 image_skia->AddRepresentation(gfx::ImageSkiaRep(
84 bitmap, image_png_reps[i].scale));
86 return image_skia.release();
89 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
90 const ImageSkia* image_skia) {
91 ImageSkiaRep image_skia_rep = image_skia->GetRepresentation(1.0f);
93 scoped_refptr<base::RefCountedBytes> png_bytes(new base::RefCountedBytes());
94 if (image_skia_rep.scale() != 1.0f ||
95 !gfx::PNGCodec::EncodeBGRASkBitmap(image_skia_rep.sk_bitmap(), false,
96 &png_bytes->data())) {
97 return NULL;
99 return png_bytes;
101 #endif
103 class ImageRepPNG;
104 class ImageRepSkia;
105 class ImageRepCocoa;
106 class ImageRepCocoaTouch;
108 // An ImageRep is the object that holds the backing memory for an Image. Each
109 // RepresentationType has an ImageRep subclass that is responsible for freeing
110 // the memory that the ImageRep holds. When an ImageRep is created, it expects
111 // to take ownership of the image, without having to retain it or increase its
112 // reference count.
113 class ImageRep {
114 public:
115 explicit ImageRep(Image::RepresentationType rep) : type_(rep) {}
117 // Deletes the associated pixels of an ImageRep.
118 virtual ~ImageRep() {}
120 // Cast helpers ("fake RTTI").
121 ImageRepPNG* AsImageRepPNG() {
122 CHECK_EQ(type_, Image::kImageRepPNG);
123 return reinterpret_cast<ImageRepPNG*>(this);
126 ImageRepSkia* AsImageRepSkia() {
127 CHECK_EQ(type_, Image::kImageRepSkia);
128 return reinterpret_cast<ImageRepSkia*>(this);
131 #if defined(OS_IOS)
132 ImageRepCocoaTouch* AsImageRepCocoaTouch() {
133 CHECK_EQ(type_, Image::kImageRepCocoaTouch);
134 return reinterpret_cast<ImageRepCocoaTouch*>(this);
136 #elif defined(OS_MACOSX)
137 ImageRepCocoa* AsImageRepCocoa() {
138 CHECK_EQ(type_, Image::kImageRepCocoa);
139 return reinterpret_cast<ImageRepCocoa*>(this);
141 #endif
143 Image::RepresentationType type() const { return type_; }
145 virtual int Width() const = 0;
146 virtual int Height() const = 0;
147 virtual gfx::Size Size() const = 0;
149 private:
150 Image::RepresentationType type_;
153 class ImageRepPNG : public ImageRep {
154 public:
155 ImageRepPNG() : ImageRep(Image::kImageRepPNG) {
158 ImageRepPNG(const std::vector<ImagePNGRep>& image_png_reps)
159 : ImageRep(Image::kImageRepPNG),
160 image_png_reps_(image_png_reps) {
163 virtual ~ImageRepPNG() {
166 virtual int Width() const OVERRIDE {
167 return Size().width();
170 virtual int Height() const OVERRIDE {
171 return Size().height();
174 virtual gfx::Size Size() const OVERRIDE {
175 // Read the PNG data to get the image size, caching it.
176 if (!size_cache_) {
177 for (std::vector<ImagePNGRep>::const_iterator it = image_reps().begin();
178 it != image_reps().end(); ++it) {
179 if (it->scale == 1.0f) {
180 size_cache_.reset(new gfx::Size(it->Size()));
181 return *size_cache_;
184 size_cache_.reset(new gfx::Size);
187 return *size_cache_;
190 const std::vector<ImagePNGRep>& image_reps() const { return image_png_reps_; }
192 private:
193 std::vector<ImagePNGRep> image_png_reps_;
195 // Cached to avoid having to parse the raw data multiple times.
196 mutable scoped_ptr<gfx::Size> size_cache_;
198 DISALLOW_COPY_AND_ASSIGN(ImageRepPNG);
201 class ImageRepSkia : public ImageRep {
202 public:
203 // Takes ownership of |image|.
204 explicit ImageRepSkia(ImageSkia* image)
205 : ImageRep(Image::kImageRepSkia),
206 image_(image) {
209 virtual ~ImageRepSkia() {
212 virtual int Width() const OVERRIDE {
213 return image_->width();
216 virtual int Height() const OVERRIDE {
217 return image_->height();
220 virtual gfx::Size Size() const OVERRIDE {
221 return image_->size();
224 ImageSkia* image() { return image_.get(); }
226 private:
227 scoped_ptr<ImageSkia> image_;
229 DISALLOW_COPY_AND_ASSIGN(ImageRepSkia);
232 #if defined(OS_IOS)
233 class ImageRepCocoaTouch : public ImageRep {
234 public:
235 explicit ImageRepCocoaTouch(UIImage* image)
236 : ImageRep(Image::kImageRepCocoaTouch),
237 image_(image) {
238 CHECK(image);
241 virtual ~ImageRepCocoaTouch() {
242 base::mac::NSObjectRelease(image_);
243 image_ = nil;
246 virtual int Width() const OVERRIDE {
247 return Size().width();
250 virtual int Height() const OVERRIDE {
251 return Size().height();
254 virtual gfx::Size Size() const OVERRIDE {
255 return internal::UIImageSize(image_);
258 UIImage* image() const { return image_; }
260 private:
261 UIImage* image_;
263 DISALLOW_COPY_AND_ASSIGN(ImageRepCocoaTouch);
265 #elif defined(OS_MACOSX)
266 class ImageRepCocoa : public ImageRep {
267 public:
268 explicit ImageRepCocoa(NSImage* image)
269 : ImageRep(Image::kImageRepCocoa),
270 image_(image) {
271 CHECK(image);
274 virtual ~ImageRepCocoa() {
275 base::mac::NSObjectRelease(image_);
276 image_ = nil;
279 virtual int Width() const OVERRIDE {
280 return Size().width();
283 virtual int Height() const OVERRIDE {
284 return Size().height();
287 virtual gfx::Size Size() const OVERRIDE {
288 return internal::NSImageSize(image_);
291 NSImage* image() const { return image_; }
293 private:
294 NSImage* image_;
296 DISALLOW_COPY_AND_ASSIGN(ImageRepCocoa);
298 #endif // defined(OS_MACOSX)
300 // The Storage class acts similarly to the pixels in a SkBitmap: the Image
301 // class holds a refptr instance of Storage, which in turn holds all the
302 // ImageReps. This way, the Image can be cheaply copied.
303 class ImageStorage : public base::RefCounted<ImageStorage> {
304 public:
305 ImageStorage(gfx::Image::RepresentationType default_type)
306 : default_representation_type_(default_type),
307 #if defined(OS_MACOSX) && !defined(OS_IOS)
308 default_representation_color_space_(
309 base::mac::GetGenericRGBColorSpace()),
310 #endif // defined(OS_MACOSX) && !defined(OS_IOS)
311 representations_deleter_(&representations_) {
314 gfx::Image::RepresentationType default_representation_type() {
315 return default_representation_type_;
317 gfx::Image::RepresentationMap& representations() { return representations_; }
319 #if defined(OS_MACOSX) && !defined(OS_IOS)
320 void set_default_representation_color_space(CGColorSpaceRef color_space) {
321 default_representation_color_space_ = color_space;
323 CGColorSpaceRef default_representation_color_space() {
324 return default_representation_color_space_;
326 #endif // defined(OS_MACOSX) && !defined(OS_IOS)
328 private:
329 friend class base::RefCounted<ImageStorage>;
331 ~ImageStorage() {}
333 // The type of image that was passed to the constructor. This key will always
334 // exist in the |representations_| map.
335 gfx::Image::RepresentationType default_representation_type_;
337 #if defined(OS_MACOSX) && !defined(OS_IOS)
338 // The default representation's colorspace. This is used for converting to
339 // NSImage. This field exists to compensate for PNGCodec not writing or
340 // reading colorspace ancillary chunks. (sRGB, iCCP).
341 // Not owned.
342 CGColorSpaceRef default_representation_color_space_;
343 #endif // defined(OS_MACOSX) && !defined(OS_IOS)
345 // All the representations of an Image. Size will always be at least one, with
346 // more for any converted representations.
347 gfx::Image::RepresentationMap representations_;
349 STLValueDeleter<Image::RepresentationMap> representations_deleter_;
351 DISALLOW_COPY_AND_ASSIGN(ImageStorage);
354 } // namespace internal
356 Image::Image() {
357 // |storage_| is NULL for empty Images.
360 Image::Image(const std::vector<ImagePNGRep>& image_reps) {
361 // Do not store obviously invalid ImagePNGReps.
362 std::vector<ImagePNGRep> filtered;
363 for (size_t i = 0; i < image_reps.size(); ++i) {
364 if (image_reps[i].raw_data.get() && image_reps[i].raw_data->size())
365 filtered.push_back(image_reps[i]);
368 if (filtered.empty())
369 return;
371 storage_ = new internal::ImageStorage(Image::kImageRepPNG);
372 internal::ImageRepPNG* rep = new internal::ImageRepPNG(filtered);
373 AddRepresentation(rep);
376 Image::Image(const ImageSkia& image) {
377 if (!image.isNull()) {
378 storage_ = new internal::ImageStorage(Image::kImageRepSkia);
379 internal::ImageRepSkia* rep = new internal::ImageRepSkia(
380 new ImageSkia(image));
381 AddRepresentation(rep);
385 #if defined(OS_IOS)
386 Image::Image(UIImage* image)
387 : storage_(new internal::ImageStorage(Image::kImageRepCocoaTouch)) {
388 if (image) {
389 internal::ImageRepCocoaTouch* rep = new internal::ImageRepCocoaTouch(image);
390 AddRepresentation(rep);
393 #elif defined(OS_MACOSX)
394 Image::Image(NSImage* image) {
395 if (image) {
396 storage_ = new internal::ImageStorage(Image::kImageRepCocoa);
397 internal::ImageRepCocoa* rep = new internal::ImageRepCocoa(image);
398 AddRepresentation(rep);
401 #endif
403 Image::Image(const Image& other) : storage_(other.storage_) {
406 Image& Image::operator=(const Image& other) {
407 storage_ = other.storage_;
408 return *this;
411 Image::~Image() {
414 // static
415 Image Image::CreateFrom1xBitmap(const SkBitmap& bitmap) {
416 return gfx::Image(ImageSkia::CreateFrom1xBitmap(bitmap));
419 // static
420 Image Image::CreateFrom1xPNGBytes(const unsigned char* input,
421 size_t input_size) {
422 if (input_size == 0u)
423 return gfx::Image();
425 scoped_refptr<base::RefCountedBytes> raw_data(new base::RefCountedBytes());
426 raw_data->data().assign(input, input + input_size);
428 return CreateFrom1xPNGBytes(raw_data);
431 Image Image::CreateFrom1xPNGBytes(
432 const scoped_refptr<base::RefCountedMemory>& input) {
433 if (!input.get() || input->size() == 0u)
434 return gfx::Image();
436 std::vector<gfx::ImagePNGRep> image_reps;
437 image_reps.push_back(ImagePNGRep(input, 1.0f));
438 return gfx::Image(image_reps);
441 const SkBitmap* Image::ToSkBitmap() const {
442 // Possibly create and cache an intermediate ImageRepSkia.
443 return ToImageSkia()->bitmap();
446 const ImageSkia* Image::ToImageSkia() const {
447 internal::ImageRep* rep = GetRepresentation(kImageRepSkia, false);
448 if (!rep) {
449 switch (DefaultRepresentationType()) {
450 case kImageRepPNG: {
451 internal::ImageRepPNG* png_rep =
452 GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
453 rep = new internal::ImageRepSkia(
454 internal::ImageSkiaFromPNG(png_rep->image_reps()));
455 break;
457 #if defined(OS_IOS)
458 case kImageRepCocoaTouch: {
459 internal::ImageRepCocoaTouch* native_rep =
460 GetRepresentation(kImageRepCocoaTouch, true)
461 ->AsImageRepCocoaTouch();
462 rep = new internal::ImageRepSkia(new ImageSkia(
463 ImageSkiaFromUIImage(native_rep->image())));
464 break;
466 #elif defined(OS_MACOSX)
467 case kImageRepCocoa: {
468 internal::ImageRepCocoa* native_rep =
469 GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
470 rep = new internal::ImageRepSkia(new ImageSkia(
471 ImageSkiaFromNSImage(native_rep->image())));
472 break;
474 #endif
475 default:
476 NOTREACHED();
478 CHECK(rep);
479 AddRepresentation(rep);
481 return rep->AsImageRepSkia()->image();
484 #if defined(OS_IOS)
485 UIImage* Image::ToUIImage() const {
486 internal::ImageRep* rep = GetRepresentation(kImageRepCocoaTouch, false);
487 if (!rep) {
488 switch (DefaultRepresentationType()) {
489 case kImageRepPNG: {
490 internal::ImageRepPNG* png_rep =
491 GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
492 rep = new internal::ImageRepCocoaTouch(internal::CreateUIImageFromPNG(
493 png_rep->image_reps()));
494 break;
496 case kImageRepSkia: {
497 internal::ImageRepSkia* skia_rep =
498 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
499 UIImage* image = UIImageFromImageSkia(*skia_rep->image());
500 base::mac::NSObjectRetain(image);
501 rep = new internal::ImageRepCocoaTouch(image);
502 break;
504 default:
505 NOTREACHED();
507 CHECK(rep);
508 AddRepresentation(rep);
510 return rep->AsImageRepCocoaTouch()->image();
512 #elif defined(OS_MACOSX)
513 NSImage* Image::ToNSImage() const {
514 internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false);
515 if (!rep) {
516 CGColorSpaceRef default_representation_color_space =
517 storage_->default_representation_color_space();
519 switch (DefaultRepresentationType()) {
520 case kImageRepPNG: {
521 internal::ImageRepPNG* png_rep =
522 GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
523 rep = new internal::ImageRepCocoa(internal::NSImageFromPNG(
524 png_rep->image_reps(), default_representation_color_space));
525 break;
527 case kImageRepSkia: {
528 internal::ImageRepSkia* skia_rep =
529 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
530 NSImage* image = NSImageFromImageSkiaWithColorSpace(*skia_rep->image(),
531 default_representation_color_space);
532 base::mac::NSObjectRetain(image);
533 rep = new internal::ImageRepCocoa(image);
534 break;
536 default:
537 NOTREACHED();
539 CHECK(rep);
540 AddRepresentation(rep);
542 return rep->AsImageRepCocoa()->image();
544 #endif
546 scoped_refptr<base::RefCountedMemory> Image::As1xPNGBytes() const {
547 if (IsEmpty())
548 return new base::RefCountedBytes();
550 internal::ImageRep* rep = GetRepresentation(kImageRepPNG, false);
552 if (rep) {
553 const std::vector<gfx::ImagePNGRep>& image_png_reps =
554 rep->AsImageRepPNG()->image_reps();
555 for (size_t i = 0; i < image_png_reps.size(); ++i) {
556 if (image_png_reps[i].scale == 1.0f)
557 return image_png_reps[i].raw_data;
559 return new base::RefCountedBytes();
562 scoped_refptr<base::RefCountedMemory> png_bytes(NULL);
563 switch (DefaultRepresentationType()) {
564 #if defined(OS_IOS)
565 case kImageRepCocoaTouch: {
566 internal::ImageRepCocoaTouch* cocoa_touch_rep =
567 GetRepresentation(kImageRepCocoaTouch, true)
568 ->AsImageRepCocoaTouch();
569 png_bytes = internal::Get1xPNGBytesFromUIImage(
570 cocoa_touch_rep->image());
571 break;
573 #elif defined(OS_MACOSX)
574 case kImageRepCocoa: {
575 internal::ImageRepCocoa* cocoa_rep =
576 GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
577 png_bytes = internal::Get1xPNGBytesFromNSImage(cocoa_rep->image());
578 break;
580 #endif
581 case kImageRepSkia: {
582 internal::ImageRepSkia* skia_rep =
583 GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
584 png_bytes = internal::Get1xPNGBytesFromImageSkia(skia_rep->image());
585 break;
587 default:
588 NOTREACHED();
590 if (!png_bytes.get() || !png_bytes->size()) {
591 // Add an ImageRepPNG with no data such that the conversion is not
592 // attempted each time we want the PNG bytes.
593 AddRepresentation(new internal::ImageRepPNG());
594 return new base::RefCountedBytes();
597 // Do not insert representations for scale factors other than 1x even if
598 // they are available because:
599 // - Only the 1x PNG bytes can be accessed.
600 // - ImageRepPNG is not used as an intermediate type in converting to a
601 // final type eg (converting from ImageRepSkia to ImageRepPNG to get an
602 // ImageRepCocoa).
603 std::vector<ImagePNGRep> image_png_reps;
604 image_png_reps.push_back(gfx::ImagePNGRep(png_bytes, 1.0f));
605 rep = new internal::ImageRepPNG(image_png_reps);
606 AddRepresentation(rep);
607 return png_bytes;
610 SkBitmap Image::AsBitmap() const {
611 return IsEmpty() ? SkBitmap() : *ToSkBitmap();
614 ImageSkia Image::AsImageSkia() const {
615 return IsEmpty() ? ImageSkia() : *ToImageSkia();
618 #if defined(OS_MACOSX) && !defined(OS_IOS)
619 NSImage* Image::AsNSImage() const {
620 return IsEmpty() ? nil : ToNSImage();
622 #endif
624 scoped_refptr<base::RefCountedMemory> Image::Copy1xPNGBytes() const {
625 scoped_refptr<base::RefCountedMemory> original = As1xPNGBytes();
626 scoped_refptr<base::RefCountedBytes> copy(new base::RefCountedBytes());
627 copy->data().assign(original->front(), original->front() + original->size());
628 return copy;
631 ImageSkia* Image::CopyImageSkia() const {
632 return new ImageSkia(*ToImageSkia());
635 SkBitmap* Image::CopySkBitmap() const {
636 return new SkBitmap(*ToSkBitmap());
639 #if defined(OS_IOS)
640 UIImage* Image::CopyUIImage() const {
641 UIImage* image = ToUIImage();
642 base::mac::NSObjectRetain(image);
643 return image;
645 #elif defined(OS_MACOSX)
646 NSImage* Image::CopyNSImage() const {
647 NSImage* image = ToNSImage();
648 base::mac::NSObjectRetain(image);
649 return image;
651 #endif
653 bool Image::HasRepresentation(RepresentationType type) const {
654 return storage_.get() && storage_->representations().count(type) != 0;
657 size_t Image::RepresentationCount() const {
658 if (!storage_.get())
659 return 0;
661 return storage_->representations().size();
664 bool Image::IsEmpty() const {
665 return RepresentationCount() == 0;
668 int Image::Width() const {
669 if (IsEmpty())
670 return 0;
671 return GetRepresentation(DefaultRepresentationType(), true)->Width();
674 int Image::Height() const {
675 if (IsEmpty())
676 return 0;
677 return GetRepresentation(DefaultRepresentationType(), true)->Height();
680 gfx::Size Image::Size() const {
681 if (IsEmpty())
682 return gfx::Size();
683 return GetRepresentation(DefaultRepresentationType(), true)->Size();
686 void Image::SwapRepresentations(gfx::Image* other) {
687 storage_.swap(other->storage_);
690 #if defined(OS_MACOSX) && !defined(OS_IOS)
691 void Image::SetSourceColorSpace(CGColorSpaceRef color_space) {
692 if (storage_.get())
693 storage_->set_default_representation_color_space(color_space);
695 #endif // defined(OS_MACOSX) && !defined(OS_IOS)
697 Image::RepresentationType Image::DefaultRepresentationType() const {
698 CHECK(storage_.get());
699 return storage_->default_representation_type();
702 internal::ImageRep* Image::GetRepresentation(
703 RepresentationType rep_type, bool must_exist) const {
704 CHECK(storage_.get());
705 RepresentationMap::iterator it = storage_->representations().find(rep_type);
706 if (it == storage_->representations().end()) {
707 CHECK(!must_exist);
708 return NULL;
710 return it->second;
713 void Image::AddRepresentation(internal::ImageRep* rep) const {
714 CHECK(storage_.get());
715 storage_->representations().insert(std::make_pair(rep->type(), rep));
718 } // namespace gfx