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#include "skia/ext/skia_utils_mac.mm"
6
7#include "base/mac/mac_util.h"
8#include "base/mac/scoped_nsobject.h"
9#include "testing/gtest/include/gtest/gtest.h"
10
11namespace {
12
13class SkiaUtilsMacTest : public testing::Test {
14 public:
15  // Creates a red or blue bitmap.
16  SkBitmap CreateSkBitmap(int width, int height, bool isred, bool tfbit);
17
18  // Creates a red or blue image.
19  NSImage* CreateNSImage(int width, int height, bool isred);
20
21  // Checks that the given bitmap rep is actually red or blue.
22  void TestImageRep(NSBitmapImageRep* imageRep, bool isred);
23
24  // Checks that the given bitmap is actually red or blue.
25  void TestSkBitmap(const SkBitmap& bitmap, bool isred);
26
27  enum BitLockerTest {
28    TestIdentity = 0,
29    TestTranslate = 1,
30    TestClip = 2,
31    TestXClip = TestTranslate | TestClip,
32    TestNoBits = 4,
33    TestTranslateNoBits = TestTranslate | TestNoBits,
34    TestClipNoBits = TestClip | TestNoBits,
35    TestXClipNoBits = TestXClip | TestNoBits,
36  };
37  void RunBitLockerTest(BitLockerTest test);
38
39  // If not red, is blue.
40  // If not tfbit (twenty-four-bit), is 444.
41  void ShapeHelper(int width, int height, bool isred, bool tfbit);
42};
43
44SkBitmap SkiaUtilsMacTest::CreateSkBitmap(int width, int height,
45                                          bool isred, bool tfbit) {
46  SkColorType ct = tfbit ? kN32_SkColorType : kARGB_4444_SkColorType;
47  SkImageInfo info = SkImageInfo::Make(width, height, ct, kPremul_SkAlphaType);
48
49  SkBitmap bitmap;
50  bitmap.allocPixels(info);
51
52  if (isred)
53    bitmap.eraseARGB(0xff, 0xff, 0, 0);
54  else
55    bitmap.eraseARGB(0xff, 0, 0, 0xff);
56
57  return bitmap;
58}
59
60NSImage* SkiaUtilsMacTest::CreateNSImage(int width, int height, bool isred) {
61  base::scoped_nsobject<NSImage> image(
62      [[NSImage alloc] initWithSize:NSMakeSize(width, height)]);
63  [image lockFocus];
64  if (isred)
65    [[NSColor colorWithDeviceRed:1.0 green:0.0 blue:0.0 alpha:1.0] set];
66  else
67    [[NSColor colorWithDeviceRed:0.0 green:0.0 blue:1.0 alpha:1.0] set];
68  NSRectFill(NSMakeRect(0, 0, width, height));
69  [image unlockFocus];
70  return [image.release() autorelease];
71}
72
73void SkiaUtilsMacTest::TestImageRep(NSBitmapImageRep* imageRep, bool isred) {
74  // Get the color of a pixel and make sure it looks fine
75  int x = [imageRep size].width > 17 ? 17 : 0;
76  int y = [imageRep size].height > 17 ? 17 : 0;
77  NSColor* color = [imageRep colorAtX:x y:y];
78  CGFloat red = 0, green = 0, blue = 0, alpha = 0;
79
80  // SkBitmapToNSImage returns a bitmap in the calibrated color space (sRGB),
81  // while NSReadPixel returns a color in the device color space. Convert back
82  // to the calibrated color space before testing.
83  color = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
84
85  [color getRed:&red green:&green blue:&blue alpha:&alpha];
86
87  // Be tolerant of floating point rounding and lossy color space conversions.
88  if (isred) {
89    EXPECT_GT(red, 0.95);
90    EXPECT_LT(blue, 0.05);
91  } else {
92    EXPECT_LT(red, 0.05);
93    EXPECT_GT(blue, 0.95);
94  }
95  EXPECT_LT(green, 0.05);
96  EXPECT_GT(alpha, 0.95);
97}
98
99void SkiaUtilsMacTest::TestSkBitmap(const SkBitmap& bitmap, bool isred) {
100  int x = bitmap.width() > 17 ? 17 : 0;
101  int y = bitmap.height() > 17 ? 17 : 0;
102  SkColor color = bitmap.getColor(x, y);
103
104  if (isred) {
105    EXPECT_EQ(255u, SkColorGetR(color));
106    EXPECT_EQ(0u, SkColorGetB(color));
107  } else {
108    EXPECT_EQ(0u, SkColorGetR(color));
109    EXPECT_EQ(255u, SkColorGetB(color));
110  }
111  EXPECT_EQ(0u, SkColorGetG(color));
112  EXPECT_EQ(255u, SkColorGetA(color));
113}
114
115// setBitmapDevice has been deprecated/removed. Is this test still useful?
116void SkiaUtilsMacTest::RunBitLockerTest(BitLockerTest test) {
117  const unsigned width = 2;
118  const unsigned height = 2;
119  const unsigned storageSize = width * height;
120  const unsigned original[] = {0xFF333333, 0xFF666666, 0xFF999999, 0xFFCCCCCC};
121  EXPECT_EQ(storageSize, sizeof(original) / sizeof(original[0]));
122  unsigned bits[storageSize];
123  memcpy(bits, original, sizeof(original));
124  SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
125  SkBitmap bitmap;
126  bitmap.installPixels(info, bits, info.minRowBytes());
127
128  SkCanvas canvas(bitmap);
129  if (test & TestTranslate)
130    canvas.translate(width / 2, 0);
131  if (test & TestClip) {
132    SkRect clipRect = {0, height / 2, width, height};
133    canvas.clipRect(clipRect);
134  }
135  {
136    gfx::SkiaBitLocker bitLocker(&canvas);
137    CGContextRef cgContext = bitLocker.cgContext();
138    CGColorRef testColor = CGColorGetConstantColor(kCGColorWhite);
139    CGContextSetFillColorWithColor(cgContext, testColor);
140    CGRect cgRect = {{0, 0}, {width, height}};
141    CGContextFillRect(cgContext, cgRect);
142    if (test & TestNoBits) {
143      if (test & TestClip) {
144        SkRect clipRect = {0, height / 2, width, height};
145        canvas.clipRect(clipRect);
146      }
147    }
148  }
149  const unsigned results[][storageSize] = {
150    {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}, // identity
151    {0xFF333333, 0xFFFFFFFF, 0xFF999999, 0xFFFFFFFF}, // translate
152    {0xFF333333, 0xFF666666, 0xFFFFFFFF, 0xFFFFFFFF}, // clip
153    {0xFF333333, 0xFF666666, 0xFF999999, 0xFFFFFFFF}  // translate | clip
154  };
155  for (unsigned index = 0; index < storageSize; index++)
156    EXPECT_EQ(results[test & ~TestNoBits][index], bits[index]);
157}
158
159void SkiaUtilsMacTest::ShapeHelper(int width, int height,
160                                   bool isred, bool tfbit) {
161  SkBitmap thing(CreateSkBitmap(width, height, isred, tfbit));
162
163  // Confirm size
164  NSImage* image = gfx::SkBitmapToNSImage(thing);
165  EXPECT_DOUBLE_EQ([image size].width, (double)width);
166  EXPECT_DOUBLE_EQ([image size].height, (double)height);
167
168  EXPECT_TRUE([[image representations] count] == 1);
169  EXPECT_TRUE([[[image representations] lastObject]
170      isKindOfClass:[NSBitmapImageRep class]]);
171  TestImageRep([[image representations] lastObject], isred);
172}
173
174TEST_F(SkiaUtilsMacTest, BitmapToNSImage_RedSquare64x64) {
175  ShapeHelper(64, 64, true, true);
176}
177
178TEST_F(SkiaUtilsMacTest, BitmapToNSImage_BlueRectangle199x19) {
179  ShapeHelper(199, 19, false, true);
180}
181
182TEST_F(SkiaUtilsMacTest, BitmapToNSImage_BlueRectangle444) {
183  ShapeHelper(200, 200, false, false);
184}
185
186TEST_F(SkiaUtilsMacTest, BitmapToNSBitmapImageRep_BlueRectangle20x30) {
187  int width = 20;
188  int height = 30;
189
190  SkBitmap bitmap(CreateSkBitmap(width, height, false, true));
191  NSBitmapImageRep* imageRep = gfx::SkBitmapToNSBitmapImageRep(bitmap);
192
193  EXPECT_DOUBLE_EQ(width, [imageRep size].width);
194  EXPECT_DOUBLE_EQ(height, [imageRep size].height);
195  TestImageRep(imageRep, false);
196}
197
198TEST_F(SkiaUtilsMacTest, NSImageRepToSkBitmap) {
199  int width = 10;
200  int height = 15;
201  bool isred = true;
202
203  NSImage* image = CreateNSImage(width, height, isred);
204  EXPECT_EQ(1u, [[image representations] count]);
205  NSBitmapImageRep* imageRep = [[image representations] lastObject];
206  NSColorSpace* colorSpace = [NSColorSpace deviceRGBColorSpace];
207  SkBitmap bitmap(gfx::NSImageRepToSkBitmapWithColorSpace(
208      imageRep, [image size], false, [colorSpace CGColorSpace]));
209  TestSkBitmap(bitmap, isred);
210}
211
212TEST_F(SkiaUtilsMacTest, BitLocker_Identity) {
213  RunBitLockerTest(SkiaUtilsMacTest::TestIdentity);
214}
215
216TEST_F(SkiaUtilsMacTest, BitLocker_Translate) {
217  RunBitLockerTest(SkiaUtilsMacTest::TestTranslate);
218}
219
220TEST_F(SkiaUtilsMacTest, BitLocker_Clip) {
221  RunBitLockerTest(SkiaUtilsMacTest::TestClip);
222}
223
224TEST_F(SkiaUtilsMacTest, BitLocker_XClip) {
225  RunBitLockerTest(SkiaUtilsMacTest::TestXClip);
226}
227
228TEST_F(SkiaUtilsMacTest, BitLocker_NoBits) {
229  RunBitLockerTest(SkiaUtilsMacTest::TestNoBits);
230}
231
232TEST_F(SkiaUtilsMacTest, BitLocker_TranslateNoBits) {
233  RunBitLockerTest(SkiaUtilsMacTest::TestTranslateNoBits);
234}
235
236TEST_F(SkiaUtilsMacTest, BitLocker_ClipNoBits) {
237  RunBitLockerTest(SkiaUtilsMacTest::TestClipNoBits);
238}
239
240TEST_F(SkiaUtilsMacTest, BitLocker_XClipNoBits) {
241  RunBitLockerTest(SkiaUtilsMacTest::TestXClipNoBits);
242}
243
244}  // namespace
245
246