Commit 7920770b authored by David Bertoni's avatar David Bertoni Committed by Commit Bot

[Extensions] Initial implementation of checking toolbar icon visibility.

The toolbar icon is a visible indicator to the user that an extension is installed. Thus, a bad actor can attempt to hide the icon to disguise its presence. In addition, the icon allows the user an easy way to uninstall it.

Bug: 805600
Change-Id: I178901d03b8ce6b13b70932114bbf9747890ae9d
Reviewed-on: https://chromium-review.googlesource.com/1144253
Commit-Queue: David Bertoni <dbertoni@chromium.org>
Reviewed-by: default avatarDevlin <rdevlin.cronin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577057}
parent 1e9b094f
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "third_party/re2/src/re2/re2.h" #include "third_party/re2/src/re2/re2.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/utils/SkParse.h" #include "third_party/skia/include/utils/SkParse.h"
#include "ui/gfx/color_utils.h" #include "ui/gfx/color_utils.h"
...@@ -158,5 +159,33 @@ bool ParseHslColorString(const std::string& color_string, SkColor* result) { ...@@ -158,5 +159,33 @@ bool ParseHslColorString(const std::string& color_string, SkColor* result) {
return true; return true;
} }
bool IsIconSufficientlyVisible(const SkBitmap& bitmap) {
// TODO(crbug.com/805600): Currently, we only consider if there are enough
// visible pixels that it won't be difficult for the user to see. Future
// revisions will consider the background color of the display context.
// If the alpha value of any pixel is greater than kAlphaThreshold, the
// pixmap is not transparent. These values will likely be adjusted, based
// on stats and research into visibility thresholds.
constexpr unsigned int kAlphaThreshold = 10;
// The minimum "percent" of pixels that must be visible for the icon to be
// considered OK.
constexpr double kMinPercentVisiblePixels = 0.05;
const unsigned int total_pixels = bitmap.height() * bitmap.width();
unsigned int visible_pixels = 0;
for (int y = 0; y < bitmap.width(); ++y) {
for (int x = 0; x < bitmap.height(); ++x) {
if (SkColorGetA(bitmap.getColor(x, y)) >= kAlphaThreshold) {
++visible_pixels;
}
}
}
// TODO(crbug.com/805600): Add UMA stats when we move to a more
// sophisticated analysis of the image and the background display
// color.
return static_cast<double>(visible_pixels) / total_pixels >=
kMinPercentVisiblePixels;
}
} // namespace image_util } // namespace image_util
} // namespace extensions } // namespace extensions
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
#include <string> #include <string>
class SkBitmap;
typedef unsigned int SkColor; typedef unsigned int SkColor;
// This file contains various utility functions for extension images and colors. // This file contains various utility functions for extension images and colors.
...@@ -30,6 +32,10 @@ bool ParseRgbColorString(const std::string& color_string, SkColor* result); ...@@ -30,6 +32,10 @@ bool ParseRgbColorString(const std::string& color_string, SkColor* result);
// Parses hsl() or hsla() string to a SkColor. Returns true for success. // Parses hsl() or hsla() string to a SkColor. Returns true for success.
bool ParseHslColorString(const std::string& color_string, SkColor* result); bool ParseHslColorString(const std::string& color_string, SkColor* result);
// Analyzes an icon image to determine if it will be visible in its display
// context.
bool IsIconSufficientlyVisible(const SkBitmap& bitmap);
} // namespace image_util } // namespace image_util
} // namespace extensions } // namespace extensions
......
...@@ -4,11 +4,31 @@ ...@@ -4,11 +4,31 @@
#include <string> #include <string>
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "extensions/common/extension_paths.h"
#include "extensions/common/image_util.h" #include "extensions/common/image_util.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h" #include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/color_utils.h" #include "ui/gfx/color_utils.h"
namespace {
bool LoadPngFromFile(const base::FilePath& path, SkBitmap* dst) {
std::string png_bytes;
if (!base::ReadFileToString(path, &png_bytes)) {
return false;
}
return gfx::PNGCodec::Decode(
reinterpret_cast<const unsigned char*>(png_bytes.data()),
png_bytes.length(), dst);
}
} // namespace
namespace extensions { namespace extensions {
void RunPassHexTest(const std::string& css_string, SkColor expected_result) { void RunPassHexTest(const std::string& css_string, SkColor expected_result) {
...@@ -176,4 +196,38 @@ TEST(ImageUtilTest, BasicColorKeyword) { ...@@ -176,4 +196,38 @@ TEST(ImageUtilTest, BasicColorKeyword) {
EXPECT_FALSE(image_util::ParseCssColorString("my_red", &color)); EXPECT_FALSE(image_util::ParseCssColorString("my_red", &color));
} }
TEST(ImageUtilTest, IsIconSufficientlyVisible) {
base::FilePath test_dir;
ASSERT_TRUE(base::PathService::Get(DIR_TEST_DATA, &test_dir));
base::FilePath icon_path;
{
// This icon has all transparent pixels, so it will fail.
icon_path = test_dir.AppendASCII("transparent_icon.png");
SkBitmap transparent_icon;
ASSERT_TRUE(LoadPngFromFile(icon_path, &transparent_icon));
EXPECT_FALSE(image_util::IsIconSufficientlyVisible(transparent_icon));
}
{
// Test with an icon that has one opaque pixel.
icon_path = test_dir.AppendASCII("one_pixel_opaque_icon.png");
SkBitmap visible_icon;
ASSERT_TRUE(LoadPngFromFile(icon_path, &visible_icon));
EXPECT_FALSE(image_util::IsIconSufficientlyVisible(visible_icon));
}
{
// Test with an icon that has one transparent pixel.
icon_path = test_dir.AppendASCII("one_pixel_transparent_icon.png");
SkBitmap visible_icon;
ASSERT_TRUE(LoadPngFromFile(icon_path, &visible_icon));
EXPECT_TRUE(image_util::IsIconSufficientlyVisible(visible_icon));
}
{
// Test with an icon that is completely opaque.
icon_path = test_dir.AppendASCII("opaque_icon.png");
SkBitmap visible_icon;
ASSERT_TRUE(LoadPngFromFile(icon_path, &visible_icon));
EXPECT_TRUE(image_util::IsIconSufficientlyVisible(visible_icon));
}
}
} // namespace extensions } // namespace extensions
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment