Don't crash when SimpleCache index is corrupt.
[chromium-blink-merge.git] / ui / gfx / image / image_ios.mm
blob1e21bd83a2e5567b1cfe33f0e5bd15fe2d6dade8
1 // Copyright 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 <cmath>
8 #include <limits>
9 #import <UIKit/UIKit.h>
11 #include "base/logging.h"
12 #include "base/mac/scoped_cftyperef.h"
13 #include "base/memory/scoped_nsobject.h"
14 #include "ui/base/layout.h"
15 #include "ui/gfx/image/image_png_rep.h"
16 #include "ui/gfx/image/image_skia.h"
17 #include "ui/gfx/image/image_skia_util_ios.h"
18 #include "ui/gfx/size.h"
20 namespace gfx {
21 namespace internal {
23 namespace {
25 // Returns a 16x16 red UIImage to visually show when a UIImage cannot be
26 // created from PNG data. Logs error as well.
27 // Caller takes ownership of returned UIImage.
28 UIImage* CreateErrorUIImage(float scale) {
29   LOG(ERROR) << "Unable to decode PNG into UIImage.";
30   base::mac::ScopedCFTypeRef<CGColorSpaceRef> color_space(
31       CGColorSpaceCreateDeviceRGB());
32   base::mac::ScopedCFTypeRef<CGContextRef> context(
33       CGBitmapContextCreate(NULL,  // Allow CG to allocate memory.
34                             16,  // width
35                             16,  // height
36                             8,  // bitsPerComponent
37                             0,  // CG will calculate by default.
38                             color_space,
39                             kCGImageAlphaPremultipliedFirst |
40                                 kCGBitmapByteOrder32Host));
41   CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0);
42   CGContextFillRect(context, CGRectMake(0.0, 0.0, 16, 16));
43   base::mac::ScopedCFTypeRef<CGImageRef> cg_image(
44       CGBitmapContextCreateImage(context));
45   return [[UIImage imageWithCGImage:cg_image.get()
46                               scale:scale
47                         orientation:UIImageOrientationUp] retain];
50 // Converts from ImagePNGRep to UIImage.
51 UIImage* CreateUIImageFromImagePNGRep(const gfx::ImagePNGRep& image_png_rep) {
52   float scale = ui::GetScaleFactorScale(image_png_rep.scale_factor);
53   scoped_refptr<base::RefCountedMemory> png = image_png_rep.raw_data;
54   CHECK(png.get());
55   NSData* data = [NSData dataWithBytes:png->front() length:png->size()];
56   UIImage* image = [[UIImage alloc] initWithData:data scale:scale];
57   return image ? image : CreateErrorUIImage(scale);
60 }  // namespace
62 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromUIImage(
63     UIImage* uiimage) {
64   NSData* data = UIImagePNGRepresentation(uiimage);
66   if ([data length] == 0)
67     return NULL;
69   scoped_refptr<base::RefCountedBytes> png_bytes(
70       new base::RefCountedBytes());
71   png_bytes->data().resize([data length]);
72   [data getBytes:&png_bytes->data().at(0) length:[data length]];
73   return png_bytes;
76 UIImage* CreateUIImageFromPNG(
77     const std::vector<gfx::ImagePNGRep>& image_png_reps) {
78   ui::ScaleFactor ideal_scale_factor = ui::GetMaxScaleFactor();
79   float ideal_scale = ui::GetScaleFactorScale(ideal_scale_factor);
81   if (image_png_reps.empty())
82     return CreateErrorUIImage(ideal_scale);
84   // Find best match for |ideal_scale_factor|.
85   float smallest_diff = std::numeric_limits<float>::max();
86   size_t closest_index = 0u;
87   for (size_t i = 0; i < image_png_reps.size(); ++i) {
88     float scale = ui::GetScaleFactorScale(image_png_reps[i].scale_factor);
89     float diff = std::abs(ideal_scale - scale);
90     if (diff < smallest_diff) {
91       smallest_diff = diff;
92       closest_index = i;
93     }
94   }
96   return CreateUIImageFromImagePNGRep(image_png_reps[closest_index]);
99 scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
100     const ImageSkia* skia) {
101   // iOS does not expose libpng, so conversion from ImageSkia to PNG must go
102   // through UIImage.
103   // TODO(rohitrao): Rewrite the callers of this function to save the UIImage
104   // representation in the gfx::Image.  If we're generating it, we might as well
105   // hold on to it.
106   const gfx::ImageSkiaRep& image_skia_rep = skia->GetRepresentation(
107       ui::SCALE_FACTOR_100P);
108   if (image_skia_rep.scale_factor() != ui::SCALE_FACTOR_100P)
109     return NULL;
111   UIImage* image = UIImageFromImageSkiaRep(image_skia_rep);
112   return Get1xPNGBytesFromUIImage(image);
115 ImageSkia* ImageSkiaFromPNG(
116     const std::vector<gfx::ImagePNGRep>& image_png_reps) {
117   // iOS does not expose libpng, so conversion from PNG to ImageSkia must go
118   // through UIImage.
119   gfx::ImageSkia* image_skia = new gfx::ImageSkia();
120   for (size_t i = 0; i < image_png_reps.size(); ++i) {
121     scoped_nsobject<UIImage> uiimage(CreateUIImageFromImagePNGRep(
122         image_png_reps[i]));
123     gfx::ImageSkiaRep image_skia_rep = ImageSkiaRepOfScaleFactorFromUIImage(
124         uiimage, image_png_reps[i].scale_factor);
125     if (!image_skia_rep.is_null())
126       image_skia->AddRepresentation(image_skia_rep);
127   }
128   return image_skia;
131 gfx::Size UIImageSize(UIImage* image) {
132   int width = static_cast<int>(image.size.width);
133   int height = static_cast<int>(image.size.height);
134   return gfx::Size(width, height);
137 } // namespace internal
138 } // namespace gfx