blob: b4e4afbed15fe72dc02e1b18a752328c1279b0d4 [file] [log] [blame]
// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/apps/icon_standardizer.h"
#include "base/compiler_specific.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkImage.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h"
namespace {
constexpr int kIconSize = 64;
constexpr float kMaxCircleIconSize = 176.0f / 192.0f;
constexpr float kStandardCircleRadius = kIconSize * kMaxCircleIconSize / 2.0f;
// Returns whether the bitmaps are equal.
bool AreBitmapsEqual(const SkBitmap& first_bitmap,
const SkBitmap& second_bitmap) {
if (first_bitmap.width() != second_bitmap.width() ||
first_bitmap.height() != second_bitmap.height() ||
first_bitmap.colorType() != second_bitmap.colorType()) {
return false;
}
for (int y = 0; y < first_bitmap.height(); ++y) {
for (int x = 0; x < first_bitmap.width(); ++x) {
if (first_bitmap.getColor(x, y) != second_bitmap.getColor(x, y)) {
return false;
}
}
}
return true;
}
bool DoesIconHaveWhiteBackgroundCircle(const SkBitmap& bitmap) {
const int y = kIconSize / 2;
for (int x = 0; x < bitmap.width(); ++x) {
if (bitmap.getColor(x, y) == SK_ColorWHITE) {
return true;
}
}
return false;
}
} // namespace
using CreateStandardIconTest = testing::Test;
// Test that a square icon gets scaled down and drawn on top of a circular
// background when converted to a standard icon.
TEST_F(CreateStandardIconTest, SquareIconToStandardIcon) {
SkBitmap square_icon_bitmap;
square_icon_bitmap.allocN32Pixels(kIconSize, kIconSize);
square_icon_bitmap.eraseColor(SK_ColorRED);
gfx::ImageSkia standard_icon = apps::CreateStandardIconImage(
gfx::ImageSkia::CreateFrom1xBitmap(square_icon_bitmap));
// Create |test_standard_bitmap| which will be a manually created standard
// icon, with background circle and a scaled down square icon inside.
SkBitmap test_standard_bitmap;
test_standard_bitmap.allocN32Pixels(kIconSize, kIconSize);
test_standard_bitmap.eraseColor(SK_ColorTRANSPARENT);
SkCanvas canvas(test_standard_bitmap);
SkPaint paint_background_circle;
paint_background_circle.setAntiAlias(true);
paint_background_circle.setColor(SK_ColorWHITE);
paint_background_circle.setStyle(SkPaint::kFill_Style);
canvas.drawCircle(
SkPoint::Make((kIconSize - 1) / 2.0f, (kIconSize - 1) / 2.0f),
kStandardCircleRadius, paint_background_circle);
const SkBitmap scaled_bitmap = skia::ImageOperations::Resize(
square_icon_bitmap, skia::ImageOperations::RESIZE_BEST, 36, 36);
canvas.drawImage(scaled_bitmap.asImage(), 14, 14);
EXPECT_TRUE(DoesIconHaveWhiteBackgroundCircle(*standard_icon.bitmap()));
EXPECT_TRUE(AreBitmapsEqual(*standard_icon.bitmap(), test_standard_bitmap));
}
// Test that a large circular icon gets scaled down when converted to a standard
// icon.
TEST_F(CreateStandardIconTest, CircularIconToStandardIcon) {
// Create a bitmap for drawing a red circle as a placeholder circular icon.
SkBitmap circle_icon_bitmap;
circle_icon_bitmap.allocN32Pixels(kIconSize, kIconSize);
circle_icon_bitmap.eraseColor(SK_ColorTRANSPARENT);
SkCanvas canvas(circle_icon_bitmap);
SkPaint paint_circle_icon;
paint_circle_icon.setAntiAlias(true);
paint_circle_icon.setColor(SK_ColorRED);
paint_circle_icon.setStyle(SkPaint::kFill_Style);
canvas.drawCircle(SkPoint::Make(kIconSize / 2, kIconSize / 2), kIconSize / 2,
paint_circle_icon);
// Get the standard icon version of the red circle icon.
gfx::ImageSkia generated_standard_icon = apps::CreateStandardIconImage(
gfx::ImageSkia::CreateFromBitmap(circle_icon_bitmap, 2.0f));
// Scale the bitmap to fit the size of a standardized circle icon.
SkBitmap scaled_bitmap = skia::ImageOperations::Resize(
circle_icon_bitmap, skia::ImageOperations::RESIZE_BEST, 58, 58);
// Draw the |scaled_bitmap| to |manually_scaled_bitmap| to ensure the size
// of the bitmap is the same as the |generated_standard_icon| for comparison.
SkBitmap manually_scaled_bitmap;
manually_scaled_bitmap.allocN32Pixels(kIconSize, kIconSize);
manually_scaled_bitmap.eraseColor(SK_ColorTRANSPARENT);
SkCanvas canvas2(manually_scaled_bitmap);
canvas2.drawImage(scaled_bitmap.asImage(), 3, 3);
EXPECT_FALSE(
DoesIconHaveWhiteBackgroundCircle(*generated_standard_icon.bitmap()));
EXPECT_TRUE(AreBitmapsEqual(*generated_standard_icon.bitmap(),
manually_scaled_bitmap));
}
// Test that a circle icon that is already standard size, keeps the same size
// when standardized.
TEST_F(CreateStandardIconTest, StandardCircularIconToStandardIcon) {
// Create a bitmap with a red circle as a placeholder circular icon.
SkBitmap circle_icon_bitmap;
circle_icon_bitmap.allocN32Pixels(kIconSize, kIconSize);
circle_icon_bitmap.eraseColor(SK_ColorTRANSPARENT);
SkCanvas canvas(circle_icon_bitmap);
SkPaint paint_circle_icon;
paint_circle_icon.setAntiAlias(true);
paint_circle_icon.setColor(SK_ColorRED);
paint_circle_icon.setStyle(SkPaint::kFill_Style);
canvas.drawCircle(SkPoint::Make(kIconSize / 2.0f, kIconSize / 2.0f),
kStandardCircleRadius, paint_circle_icon);
// Get the standard icon version of the red circle icon.
gfx::ImageSkia standard_icon = apps::CreateStandardIconImage(
gfx::ImageSkia::CreateFromBitmap(circle_icon_bitmap, 2.0f));
EXPECT_FALSE(DoesIconHaveWhiteBackgroundCircle(*standard_icon.bitmap()));
EXPECT_TRUE(AreBitmapsEqual(*standard_icon.bitmap(), circle_icon_bitmap));
}
// Test that a circle icon that has an extra opaque area near the outside of the
// circle will have a background circle added when standardized.
TEST_F(CreateStandardIconTest, AlmostCircularIconToStandardIcon) {
// Create a bitmap with a red circle as a placeholder circular icon.
SkBitmap almost_circle_icon_bitmap;
almost_circle_icon_bitmap.allocN32Pixels(kIconSize, kIconSize);
almost_circle_icon_bitmap.eraseColor(SK_ColorTRANSPARENT);
SkCanvas canvas(almost_circle_icon_bitmap);
SkPaint paint_flags;
paint_flags.setAntiAlias(true);
paint_flags.setColor(SK_ColorRED);
paint_flags.setStyle(SkPaint::kFill_Style);
canvas.drawCircle(SkPoint::Make(kIconSize / 2.0f, kIconSize / 2.0f),
kStandardCircleRadius, paint_flags);
// Draw a small square partially outside of the main red circle.
canvas.drawRect(SkRect::MakeXYWH(6, 6, 15, 15), paint_flags);
// Get the standard icon version of the almost red circle icon.
gfx::ImageSkia standard_icon = apps::CreateStandardIconImage(
gfx::ImageSkia::CreateFromBitmap(almost_circle_icon_bitmap, 2.0f));
EXPECT_TRUE(DoesIconHaveWhiteBackgroundCircle(*standard_icon.bitmap()));
EXPECT_FALSE(
AreBitmapsEqual(*standard_icon.bitmap(), almost_circle_icon_bitmap));
}