blob: a9a26c4680a1aed2c1459bfbe8edac03bf4f6222 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "skia/ext/skia_utils_mac.h"
#import <AppKit/AppKit.h>
#include "base/apple/foundation_util.h"
#include "base/mac/mac_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColorSpace.h"
#include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
namespace {
class SkiaUtilsMacTest : public testing::Test {
public:
enum class TestColor {
kRed,
kBlue,
};
enum class ColorType {
k24Bit, // kN32_SkColorType
k16Bit, // kARGB_4444_SkColorType
};
// Creates a test bitmap of the specified color and color type.
SkBitmap CreateSkBitmap(int width,
int height,
TestColor test_color,
ColorType color_type);
// Creates a red image.
NSImage* CreateNSImage(int width, int height);
// Checks that the given bitmap rep is actually the correct color.
void TestImageRep(NSBitmapImageRep* image_rep, TestColor test_color);
// Checks that the given bitmap is red.
void TestSkBitmap(const SkBitmap& bitmap);
// Tests `SkBitmapToNSImage` for a specific combination of color and color
// type. Creates a bitmap with `CreateSkBitmap`, converts it into an
// `NSImage`, then tests it with `TestImageRep`.
void ShapeHelper(int width,
int height,
TestColor test_color,
ColorType color_type);
};
SkBitmap SkiaUtilsMacTest::CreateSkBitmap(int width,
int height,
TestColor test_color,
ColorType color_type) {
SkColorType sk_color_type = color_type == ColorType::k24Bit
? kN32_SkColorType
: kARGB_4444_SkColorType;
SkImageInfo info =
SkImageInfo::Make(width, height, sk_color_type, kPremul_SkAlphaType,
SkColorSpace::MakeSRGB());
SkBitmap bitmap;
bitmap.allocPixels(info);
if (test_color == TestColor::kRed)
bitmap.eraseARGB(0xff, 0xff, 0, 0);
else
bitmap.eraseARGB(0xff, 0, 0, 0xff);
return bitmap;
}
NSImage* SkiaUtilsMacTest::CreateNSImage(int width, int height) {
// An `NSBitmapImageRep` can only be created with a handful of named color
// spaces, and sRGB isn't one. Do a retagging after creation to switch it.
NSBitmapImageRep* initial_bitmap = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:nil
pixelsWide:width
pixelsHigh:height
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSCalibratedRGBColorSpace
bitmapFormat:0
bytesPerRow:4 * width
bitsPerPixel:32];
NSBitmapImageRep* bitmap = [initial_bitmap
bitmapImageRepByRetaggingWithColorSpace:NSColorSpace.sRGBColorSpace];
{
gfx::ScopedNSGraphicsContextSaveGState scopedGState;
NSGraphicsContext.currentContext =
[NSGraphicsContext graphicsContextWithBitmapImageRep:bitmap];
CGFloat comps[] = {1.0, 0.0, 0.0, 1.0};
NSColor* color = [NSColor colorWithColorSpace:NSColorSpace.sRGBColorSpace
components:comps
count:4];
[color set];
NSRectFill(NSMakeRect(0, 0, width, height));
}
NSImage* image = [[NSImage alloc] initWithSize:NSMakeSize(width, height)];
[image addRepresentation:bitmap];
return image;
}
void SkiaUtilsMacTest::TestImageRep(NSBitmapImageRep* image_rep,
TestColor test_color) {
// Get the color of a pixel and make sure it looks fine.
int x = image_rep.size.width > 17 ? 17 : 0;
int y = image_rep.size.height > 17 ? 17 : 0;
NSColor* color = [image_rep colorAtX:x y:y];
ASSERT_EQ(4, color.numberOfComponents);
CGFloat color_components[4];
[color getComponents:color_components];
const CGFloat& red = color_components[0];
const CGFloat& green = color_components[1];
const CGFloat& blue = color_components[2];
const CGFloat& alpha = color_components[3];
// Be a little tolerant of floating point rounding, maybe, but everything is
// done in SRGB so there should be no color space conversion affecting things.
if (test_color == TestColor::kRed) {
EXPECT_GT(red, 0.9995);
EXPECT_LT(blue, 0.0005);
} else {
EXPECT_LT(red, 0.0005);
EXPECT_GT(blue, 0.9995);
}
EXPECT_LT(green, 0.0005);
EXPECT_GT(alpha, 0.9995);
}
void SkiaUtilsMacTest::TestSkBitmap(const SkBitmap& bitmap) {
int x = bitmap.width() > 17 ? 17 : 0;
int y = bitmap.height() > 17 ? 17 : 0;
SkColor color = bitmap.getColor(x, y);
EXPECT_EQ(255u, SkColorGetR(color));
EXPECT_EQ(0u, SkColorGetB(color));
EXPECT_EQ(0u, SkColorGetG(color));
EXPECT_EQ(255u, SkColorGetA(color));
}
void SkiaUtilsMacTest::ShapeHelper(int width,
int height,
TestColor test_color,
ColorType color_type) {
SkBitmap bitmap(CreateSkBitmap(width, height, test_color, color_type));
// Confirm size
NSImage* image = skia::SkBitmapToNSImage(bitmap);
EXPECT_DOUBLE_EQ(image.size.width, (CGFloat)width);
EXPECT_DOUBLE_EQ(image.size.height, (CGFloat)height);
EXPECT_TRUE(image.representations.count == 1);
EXPECT_TRUE([image.representations.lastObject
isKindOfClass:[NSBitmapImageRep class]]);
TestImageRep(base::apple::ObjCCastStrict<NSBitmapImageRep>(
image.representations.lastObject),
test_color);
}
TEST_F(SkiaUtilsMacTest, BitmapToNSImage_RedSquare64x64) {
ShapeHelper(64, 64, TestColor::kRed, ColorType::k24Bit);
}
TEST_F(SkiaUtilsMacTest, BitmapToNSImage_BlueRectangle199x19) {
ShapeHelper(199, 19, TestColor::kBlue, ColorType::k24Bit);
}
TEST_F(SkiaUtilsMacTest, BitmapToNSImage_BlueRectangle444) {
ShapeHelper(200, 200, TestColor::kBlue, ColorType::k16Bit);
}
TEST_F(SkiaUtilsMacTest, BitmapToNSBitmapImageRep_BlueRectangle20x30) {
int width = 20;
int height = 30;
SkBitmap bitmap(
CreateSkBitmap(width, height, TestColor::kBlue, ColorType::k24Bit));
NSBitmapImageRep* imageRep = skia::SkBitmapToNSBitmapImageRep(bitmap);
EXPECT_DOUBLE_EQ(width, imageRep.size.width);
EXPECT_DOUBLE_EQ(height, imageRep.size.height);
TestImageRep(imageRep, TestColor::kBlue);
}
TEST_F(SkiaUtilsMacTest, NSImageRepToSkBitmap) {
int width = 10;
int height = 15;
NSImage* image = CreateNSImage(width, height);
EXPECT_EQ(1u, image.representations.count);
NSBitmapImageRep* imageRep = base::apple::ObjCCastStrict<NSBitmapImageRep>(
image.representations.lastObject);
SkBitmap bitmap(skia::NSImageRepToSkBitmap(imageRep, image.size, false));
TestSkBitmap(bitmap);
}
} // namespace