blob: 97920ad328c04fe714c771555be961f30a342d33 [file]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/safe_browsing/password_protection/visual_utils.h"
#include "base/test/test_discardable_memory_allocator.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace safe_browsing {
namespace visual_utils {
namespace {
// Pixel value constants, all in BGR order.
const unsigned int kWhite = 0xffffffff;
const unsigned int kBlack = 0xff000000;
const unsigned int kRed = 0xff0000ff;
const unsigned int kGreen = 0xff00ff00;
const unsigned int kBlue = 0xffff0000;
} // namespace
using ::testing::FloatEq;
class VisualUtilsTest : public testing::Test {
protected:
void SetUp() override {
base::DiscardableMemoryAllocator::SetInstance(&test_allocator_);
sk_sp<SkColorSpace> rec2020 = SkColorSpace::MakeRGB(
{2.22222f, 0.909672f, 0.0903276f, 0.222222f, 0.0812429f, 0, 0},
SkNamedGamut::kRec2020);
SkImageInfo bitmap_info =
SkImageInfo::Make(1000, 1000, SkColorType::kRGBA_8888_SkColorType,
SkAlphaType::kUnpremul_SkAlphaType, rec2020);
ASSERT_TRUE(bitmap_.tryAllocPixels(bitmap_info));
}
void TearDown() override {
base::DiscardableMemoryAllocator::SetInstance(nullptr);
}
// A test bitmap to work with. Initialized to be 1000x1000 in the Rec 2020
// color space.
SkBitmap bitmap_;
private:
// A DiscardableMemoryAllocator is needed for certain Skia operations.
base::TestDiscardableMemoryAllocator test_allocator_;
};
TEST_F(VisualUtilsTest, TestSkColorToQuantizedColor) {
// Test quantization
EXPECT_EQ(SkColorToQuantizedColor(SkColorSetRGB(0, 0, 31)), 0u);
EXPECT_EQ(SkColorToQuantizedColor(SkColorSetRGB(0, 0, 32)), 1u);
EXPECT_EQ(SkColorToQuantizedColor(SkColorSetRGB(0, 31, 0)), 0u);
EXPECT_EQ(SkColorToQuantizedColor(SkColorSetRGB(0, 32, 0)), 8u);
EXPECT_EQ(SkColorToQuantizedColor(SkColorSetRGB(31, 0, 0)), 0u);
EXPECT_EQ(SkColorToQuantizedColor(SkColorSetRGB(32, 0, 0)), 64u);
// Test composition of RGB quantized values
EXPECT_EQ(SkColorToQuantizedColor(SkColorSetRGB(0, 0, 0)), 0u);
EXPECT_EQ(SkColorToQuantizedColor(SkColorSetRGB(0, 0, 255)), 7u);
EXPECT_EQ(SkColorToQuantizedColor(SkColorSetRGB(0, 255, 255)), 63u);
EXPECT_EQ(SkColorToQuantizedColor(SkColorSetRGB(255, 255, 255)), 511u);
}
TEST_F(VisualUtilsTest, GetQuantizedR) {
EXPECT_EQ(GetQuantizedR(0), 0);
EXPECT_EQ(GetQuantizedR(64), 1);
EXPECT_EQ(GetQuantizedR(448), 7);
}
TEST_F(VisualUtilsTest, GetQuantizedG) {
EXPECT_EQ(GetQuantizedG(0), 0);
EXPECT_EQ(GetQuantizedG(8), 1);
EXPECT_EQ(GetQuantizedG(56), 7);
}
TEST_F(VisualUtilsTest, GetQuantizedB) {
EXPECT_EQ(GetQuantizedB(0), 0);
EXPECT_EQ(GetQuantizedB(1), 1);
EXPECT_EQ(GetQuantizedB(7), 7);
}
TEST_F(VisualUtilsTest, GetHistogramForImageWhite) {
VisualFeatures::ColorHistogram histogram;
SkBitmap bitmap;
// Draw white over half the image
for (int x = 0; x < 1000; x++)
for (int y = 0; y < 1000; y++)
*bitmap_.getAddr32(x, y) = kWhite;
ASSERT_TRUE(GetHistogramForImage(bitmap_, &histogram));
ASSERT_EQ(histogram.bins_size(), 1);
EXPECT_THAT(histogram.bins(0).centroid_x(),
FloatEq(0.4995)); // All pixels are the same color, so centroid_x
// is (0+1+...+999)/1000/1000 = 0.4995
EXPECT_THAT(histogram.bins(0).centroid_y(), FloatEq(0.4995));
EXPECT_EQ(histogram.bins(0).quantized_r(), 7);
EXPECT_EQ(histogram.bins(0).quantized_g(), 7);
EXPECT_EQ(histogram.bins(0).quantized_b(), 7);
EXPECT_THAT(histogram.bins(0).weight(), FloatEq(1.0));
}
TEST_F(VisualUtilsTest, GetHistogramForImageHalfWhiteHalfBlack) {
VisualFeatures::ColorHistogram histogram;
// Draw white over half the image
for (int x = 0; x < 1000; x++)
for (int y = 0; y < 500; y++)
*bitmap_.getAddr32(x, y) = kWhite;
// Draw black over half the image.
for (int x = 0; x < 1000; x++)
for (int y = 500; y < 1000; y++)
*bitmap_.getAddr32(x, y) = kBlack;
ASSERT_TRUE(GetHistogramForImage(bitmap_, &histogram));
ASSERT_EQ(histogram.bins_size(), 2);
EXPECT_THAT(histogram.bins(0).centroid_x(), FloatEq(0.4995));
EXPECT_THAT(histogram.bins(0).centroid_y(), FloatEq(0.7495));
EXPECT_EQ(histogram.bins(0).quantized_r(), 0);
EXPECT_EQ(histogram.bins(0).quantized_g(), 0);
EXPECT_EQ(histogram.bins(0).quantized_b(), 0);
EXPECT_THAT(histogram.bins(0).weight(), FloatEq(0.5));
EXPECT_THAT(histogram.bins(1).centroid_x(), FloatEq(0.4995));
EXPECT_THAT(histogram.bins(1).centroid_y(), FloatEq(0.2495));
EXPECT_EQ(histogram.bins(1).quantized_r(), 7);
EXPECT_EQ(histogram.bins(1).quantized_g(), 7);
EXPECT_EQ(histogram.bins(1).quantized_b(), 7);
EXPECT_THAT(histogram.bins(1).weight(), FloatEq(0.5));
}
TEST_F(VisualUtilsTest, BlurImageWhite) {
VisualFeatures::BlurredImage blurred;
// Draw white over the image
for (int x = 0; x < 1000; x++)
for (int y = 0; y < 1000; y++)
*bitmap_.getAddr32(x, y) = kWhite;
ASSERT_TRUE(GetBlurredImage(bitmap_, &blurred));
ASSERT_EQ(48, blurred.width());
ASSERT_EQ(48, blurred.height());
ASSERT_EQ(3u * 48u * 48u, blurred.data().size());
for (size_t i = 0; i < 48u * 48u; i++) {
EXPECT_EQ('\xff', blurred.data()[3 * i]);
EXPECT_EQ('\xff', blurred.data()[3 * i + 1]);
EXPECT_EQ('\xff', blurred.data()[3 * i + 2]);
}
}
TEST_F(VisualUtilsTest, BlurImageRed) {
VisualFeatures::BlurredImage blurred;
// Draw red over the image.
for (int x = 0; x < 1000; x++)
for (int y = 0; y < 1000; y++)
*bitmap_.getAddr32(x, y) = kRed;
ASSERT_TRUE(GetBlurredImage(bitmap_, &blurred));
ASSERT_EQ(48, blurred.width());
ASSERT_EQ(48, blurred.height());
ASSERT_EQ(3u * 48u * 48u, blurred.data().size());
for (size_t i = 0; i < 48u * 48u; i++) {
EXPECT_EQ('\xff', blurred.data()[3 * i]);
EXPECT_EQ('\x00', blurred.data()[3 * i + 1]);
EXPECT_EQ('\x00', blurred.data()[3 * i + 2]);
}
}
TEST_F(VisualUtilsTest, BlurImageHalfWhiteHalfBlack) {
VisualFeatures::BlurredImage blurred;
// Draw black over half the image.
for (int x = 0; x < 1000; x++)
for (int y = 0; y < 500; y++)
*bitmap_.getAddr32(x, y) = kBlack;
// Draw white over half the image
for (int x = 0; x < 1000; x++)
for (int y = 500; y < 1000; y++)
*bitmap_.getAddr32(x, y) = kWhite;
ASSERT_TRUE(GetBlurredImage(bitmap_, &blurred));
ASSERT_EQ(48, blurred.width());
ASSERT_EQ(48, blurred.height());
ASSERT_EQ(3u * 48u * 48u, blurred.data().size());
// The middle blocks may have been blurred to something between white and
// black, so only verify the first 22 and last 22 rows.
for (size_t i = 0; i < 22u * 48u; i++) {
EXPECT_EQ('\x00', blurred.data()[3 * i]);
EXPECT_EQ('\x00', blurred.data()[3 * i + 1]);
EXPECT_EQ('\x00', blurred.data()[3 * i + 2]);
}
for (size_t i = 26u * 48u; i < 48u * 48u; i++) {
EXPECT_EQ('\xff', blurred.data()[3 * i]);
EXPECT_EQ('\xff', blurred.data()[3 * i + 1]);
EXPECT_EQ('\xff', blurred.data()[3 * i + 2]);
}
}
TEST_F(VisualUtilsTest, BlockMeanAverageOneBlock) {
// Draw black over half the image.
for (int x = 0; x < 1000; x++)
for (int y = 0; y < 500; y++)
*bitmap_.getAddr32(x, y) = kBlack;
// Draw white over half the image
for (int x = 0; x < 1000; x++)
for (int y = 500; y < 1000; y++)
*bitmap_.getAddr32(x, y) = kWhite;
std::unique_ptr<SkBitmap> blocks = BlockMeanAverage(bitmap_, 1000);
ASSERT_EQ(1, blocks->width());
ASSERT_EQ(1, blocks->height());
EXPECT_EQ(blocks->getColor(0, 0), SkColorSetRGB(127, 127, 127));
}
TEST_F(VisualUtilsTest, BlockMeanAveragePartialBlocks) {
// Draw a white, red, green, and blue box with the expected block sizes.
for (int x = 0; x < 600; x++)
for (int y = 0; y < 600; y++)
*bitmap_.getAddr32(x, y) = kWhite;
for (int x = 600; x < 1000; x++)
for (int y = 0; y < 600; y++)
*bitmap_.getAddr32(x, y) = kRed;
for (int x = 0; x < 600; x++)
for (int y = 600; y < 1000; y++)
*bitmap_.getAddr32(x, y) = kGreen;
for (int x = 600; x < 1000; x++)
for (int y = 600; y < 1000; y++)
*bitmap_.getAddr32(x, y) = kBlue;
std::unique_ptr<SkBitmap> blocks = BlockMeanAverage(bitmap_, 600);
ASSERT_EQ(2, blocks->width());
ASSERT_EQ(2, blocks->height());
EXPECT_EQ(*blocks->getAddr32(0, 0), kWhite);
EXPECT_EQ(*blocks->getAddr32(1, 0), kRed);
EXPECT_EQ(*blocks->getAddr32(0, 1), kGreen);
EXPECT_EQ(*blocks->getAddr32(1, 1), kBlue);
}
} // namespace visual_utils
} // namespace safe_browsing