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