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 // Because the unit tests for gfx::Image are spread across multiple 6 // implementation files, this header contains the reusable components. 7 8 #include "ui/gfx/image/image_unittest_util.h" 9 10 #include <cmath> 11 12 #include "base/memory/scoped_ptr.h" 13 #include "testing/gtest/include/gtest/gtest.h" 14 #include "third_party/skia/include/core/SkBitmap.h" 15 #include "ui/gfx/codec/png_codec.h" 16 #include "ui/gfx/image/image_skia.h" 17 18 #if defined(TOOLKIT_GTK) 19 #include <gtk/gtk.h> 20 #include "ui/gfx/gtk_util.h" 21 #elif defined(OS_IOS) 22 #include "base/mac/foundation_util.h" 23 #include "base/mac/scoped_cftyperef.h" 24 #include "skia/ext/skia_utils_ios.h" 25 #elif defined(OS_MACOSX) 26 #include "base/mac/mac_util.h" 27 #include "skia/ext/skia_utils_mac.h" 28 #endif 29 30 namespace gfx { 31 namespace test { 32 33 namespace { 34 35 bool ColorComponentsClose(SkColor component1, SkColor component2) { 36 int c1 = static_cast<int>(component1); 37 int c2 = static_cast<int>(component2); 38 return std::abs(c1 - c2) <= 40; 39 } 40 41 bool ColorsClose(SkColor color1, SkColor color2) { 42 // Be tolerant of floating point rounding and lossy color space conversions. 43 return ColorComponentsClose(SkColorGetR(color1), SkColorGetR(color2)) && 44 ColorComponentsClose(SkColorGetG(color1), SkColorGetG(color2)) && 45 ColorComponentsClose(SkColorGetB(color1), SkColorGetB(color2)) && 46 ColorComponentsClose(SkColorGetA(color1), SkColorGetA(color2)); 47 } 48 49 } // namespace 50 51 std::vector<float> Get1xAnd2xScales() { 52 std::vector<float> scales; 53 scales.push_back(1.0f); 54 scales.push_back(2.0f); 55 return scales; 56 } 57 58 const SkBitmap CreateBitmap(int width, int height) { 59 SkBitmap bitmap; 60 bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); 61 bitmap.allocPixels(); 62 bitmap.eraseRGB(0, 255, 0); 63 return bitmap; 64 } 65 66 gfx::ImageSkia CreateImageSkia(int width, int height) { 67 return gfx::ImageSkia::CreateFrom1xBitmap(CreateBitmap(width, height)); 68 } 69 70 scoped_refptr<base::RefCountedMemory> CreatePNGBytes(int edge_size) { 71 SkBitmap bitmap = CreateBitmap(edge_size, edge_size); 72 scoped_refptr<base::RefCountedBytes> bytes(new base::RefCountedBytes()); 73 PNGCodec::EncodeBGRASkBitmap(bitmap, false, &bytes->data()); 74 return bytes; 75 } 76 77 gfx::Image CreateImage() { 78 return CreateImage(100, 50); 79 } 80 81 gfx::Image CreateImage(int width, int height) { 82 return gfx::Image::CreateFrom1xBitmap(CreateBitmap(width, height)); 83 } 84 85 bool IsEqual(const gfx::Image& img1, const gfx::Image& img2) { 86 std::vector<gfx::ImageSkiaRep> img1_reps = img1.AsImageSkia().image_reps(); 87 gfx::ImageSkia image_skia2 = img2.AsImageSkia(); 88 if (image_skia2.image_reps().size() != img1_reps.size()) 89 return false; 90 91 for (size_t i = 0; i < img1_reps.size(); ++i) { 92 float scale = img1_reps[i].scale(); 93 const gfx::ImageSkiaRep& image_rep2 = image_skia2.GetRepresentation(scale); 94 if (image_rep2.scale() != scale || 95 !IsEqual(img1_reps[i].sk_bitmap(), image_rep2.sk_bitmap())) { 96 return false; 97 } 98 } 99 return true; 100 } 101 102 bool IsEqual(const SkBitmap& bmp1, const SkBitmap& bmp2) { 103 if (bmp1.isNull() && bmp2.isNull()) 104 return true; 105 106 if (bmp1.width() != bmp2.width() || 107 bmp1.height() != bmp2.height() || 108 bmp1.config() != SkBitmap::kARGB_8888_Config || 109 bmp2.config() != SkBitmap::kARGB_8888_Config) { 110 return false; 111 } 112 113 SkAutoLockPixels lock1(bmp1); 114 SkAutoLockPixels lock2(bmp2); 115 if (!bmp1.getPixels() || !bmp2.getPixels()) 116 return false; 117 118 for (int y = 0; y < bmp1.height(); ++y) { 119 for (int x = 0; x < bmp1.width(); ++x) { 120 if (!ColorsClose(bmp1.getColor(x,y), bmp2.getColor(x,y))) 121 return false; 122 } 123 } 124 125 return true; 126 } 127 128 bool IsEqual(const scoped_refptr<base::RefCountedMemory>& bytes, 129 const SkBitmap& bitmap) { 130 SkBitmap decoded; 131 if (!bytes.get() || 132 !PNGCodec::Decode(bytes->front(), bytes->size(), &decoded)) { 133 return bitmap.isNull(); 134 } 135 136 return IsEqual(bitmap, decoded); 137 } 138 139 void CheckImageIndicatesPNGDecodeFailure(const gfx::Image& image) { 140 SkBitmap bitmap = image.AsBitmap(); 141 EXPECT_FALSE(bitmap.isNull()); 142 EXPECT_LE(16, bitmap.width()); 143 EXPECT_LE(16, bitmap.height()); 144 SkAutoLockPixels auto_lock(bitmap); 145 CheckColors(bitmap.getColor(10, 10), SK_ColorRED); 146 } 147 148 bool ImageSkiaStructureMatches( 149 const gfx::ImageSkia& image_skia, 150 int width, 151 int height, 152 const std::vector<float>& scales) { 153 if (image_skia.isNull() || 154 image_skia.width() != width || 155 image_skia.height() != height || 156 image_skia.image_reps().size() != scales.size()) { 157 return false; 158 } 159 160 for (size_t i = 0; i < scales.size(); ++i) { 161 gfx::ImageSkiaRep image_rep = 162 image_skia.GetRepresentation(scales[i]); 163 if (image_rep.is_null() || image_rep.scale() != scales[i]) 164 return false; 165 166 if (image_rep.pixel_width() != static_cast<int>(width * scales[i]) || 167 image_rep.pixel_height() != static_cast<int>(height * scales[i])) { 168 return false; 169 } 170 } 171 return true; 172 } 173 174 bool IsEmpty(const gfx::Image& image) { 175 const SkBitmap& bmp = *image.ToSkBitmap(); 176 return bmp.isNull() || 177 (bmp.width() == 0 && bmp.height() == 0); 178 } 179 180 PlatformImage CreatePlatformImage() { 181 const SkBitmap bitmap(CreateBitmap(25, 25)); 182 #if defined(OS_IOS) 183 float scale = ImageSkia::GetMaxSupportedScale(); 184 185 base::ScopedCFTypeRef<CGColorSpaceRef> color_space( 186 CGColorSpaceCreateDeviceRGB()); 187 UIImage* image = 188 gfx::SkBitmapToUIImageWithColorSpace(bitmap, scale, color_space); 189 base::mac::NSObjectRetain(image); 190 return image; 191 #elif defined(OS_MACOSX) 192 NSImage* image = gfx::SkBitmapToNSImage(bitmap); 193 base::mac::NSObjectRetain(image); 194 return image; 195 #elif defined(TOOLKIT_GTK) 196 return gfx::GdkPixbufFromSkBitmap(bitmap); 197 #else 198 return gfx::ImageSkia::CreateFrom1xBitmap(bitmap); 199 #endif 200 } 201 202 gfx::Image::RepresentationType GetPlatformRepresentationType() { 203 #if defined(OS_IOS) 204 return gfx::Image::kImageRepCocoaTouch; 205 #elif defined(OS_MACOSX) 206 return gfx::Image::kImageRepCocoa; 207 #elif defined(TOOLKIT_GTK) 208 return gfx::Image::kImageRepGdk; 209 #else 210 return gfx::Image::kImageRepSkia; 211 #endif 212 } 213 214 PlatformImage ToPlatformType(const gfx::Image& image) { 215 #if defined(OS_IOS) 216 return image.ToUIImage(); 217 #elif defined(OS_MACOSX) 218 return image.ToNSImage(); 219 #elif defined(TOOLKIT_GTK) 220 return image.ToGdkPixbuf(); 221 #else 222 return image.AsImageSkia(); 223 #endif 224 } 225 226 PlatformImage CopyPlatformType(const gfx::Image& image) { 227 #if defined(OS_IOS) 228 return image.CopyUIImage(); 229 #elif defined(OS_MACOSX) 230 return image.CopyNSImage(); 231 #elif defined(TOOLKIT_GTK) 232 return image.CopyGdkPixbuf(); 233 #else 234 return image.AsImageSkia(); 235 #endif 236 } 237 238 #if defined(OS_MACOSX) 239 // Defined in image_unittest_util_mac.mm. 240 #elif defined(TOOLKIT_GTK) 241 SkColor GetPlatformImageColor(PlatformImage image, int x, int y) { 242 int n_channels = gdk_pixbuf_get_n_channels(image); 243 int rowstride = gdk_pixbuf_get_rowstride(image); 244 guchar* gdk_pixels = gdk_pixbuf_get_pixels(image); 245 246 guchar* pixel = gdk_pixels + (y * rowstride) + (x * n_channels); 247 guchar alpha = gdk_pixbuf_get_has_alpha(image) ? pixel[3] : 255; 248 return SkColorSetARGB(alpha, pixel[0], pixel[1], pixel[2]); 249 } 250 #else 251 SkColor GetPlatformImageColor(PlatformImage image, int x, int y) { 252 SkBitmap bitmap = *image.bitmap(); 253 SkAutoLockPixels auto_lock(bitmap); 254 return bitmap.getColor(x, y); 255 } 256 #endif 257 258 void CheckColors(SkColor color1, SkColor color2) { 259 EXPECT_TRUE(ColorsClose(color1, color2)); 260 } 261 262 void CheckIsTransparent(SkColor color) { 263 EXPECT_LT(SkColorGetA(color) / 255.0, 0.05); 264 } 265 266 bool IsPlatformImageValid(PlatformImage image) { 267 #if defined(OS_MACOSX) || defined(TOOLKIT_GTK) 268 return image != NULL; 269 #else 270 return !image.isNull(); 271 #endif 272 } 273 274 bool PlatformImagesEqual(PlatformImage image1, PlatformImage image2) { 275 #if defined(OS_MACOSX) || defined(TOOLKIT_GTK) 276 return image1 == image2; 277 #else 278 return image1.BackedBySameObjectAs(image2); 279 #endif 280 } 281 282 } // namespace test 283 } // namespace gfx 284