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