Commit 1d3a4939 authored by Ella Ge's avatar Ella Ge Committed by Commit Bot

Revert "[Media Notification] Derive background color from artwork"

This reverts commit e60e1e6e.

Reason for revert: 
MediaNotificationBackgroundTest.BoundsSanityCheck
MediaNotificationViewTest.UpdateArtworkFromItem
failure on  Linux ChromiumOS MSan Tests bot:
https://ci.chromium.org/p/chromium/builders/ci/Linux%20ChromiumOS%20MSan%20Tests/12036

Original change's description:
> [Media Notification] Derive background color from artwork
> 
> The media notification should derive its background
> color from prominent colors in the artwork. This
> uses as similar algorithm from Android.
> 
> Also breaks out some of the logic of CalculateProminentColors
> so we can use it without the reset of the function. This
> is because we want uninteresting colors and do not want
> the color profile matching.
> 
> BUG=944598
> 
> Change-Id: I60df7f600f6fc881dfb38d2057c903a5679845df
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1534923
> Commit-Queue: Becca Hughes <beccahughes@chromium.org>
> Reviewed-by: Sadrul Chowdhury <sadrul@chromium.org>
> Reviewed-by: Evan Stade <estade@chromium.org>
> Reviewed-by: Tommy Steimel <steimel@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#644985}

TBR=sadrul@chromium.org,estade@chromium.org,beccahughes@chromium.org,steimel@chromium.org

Change-Id: Ie18b564a68ffdf2560492eb1e7cf53c59447ea54
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 944598
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1543464Reviewed-by: default avatarElla Ge <eirage@chromium.org>
Commit-Queue: Ella Ge <eirage@chromium.org>
Cr-Commit-Position: refs/heads/master@{#645338}
parent 557d75a1
...@@ -5,12 +5,8 @@ ...@@ -5,12 +5,8 @@
#include "ash/media/media_notification_background.h" #include "ash/media/media_notification_background.h"
#include <algorithm> #include <algorithm>
#include <vector>
#include "skia/ext/image_operations.h"
#include "ui/gfx/canvas.h" #include "ui/gfx/canvas.h"
#include "ui/gfx/color_analysis.h"
#include "ui/gfx/color_utils.h"
#include "ui/gfx/scoped_canvas.h" #include "ui/gfx/scoped_canvas.h"
#include "ui/views/view.h" #include "ui/views/view.h"
...@@ -20,66 +16,7 @@ namespace { ...@@ -20,66 +16,7 @@ namespace {
constexpr int kMediaImageGradientWidth = 40; constexpr int kMediaImageGradientWidth = 40;
constexpr SkColor kMediaNotificationDefaultBackgroundColor = SK_ColorWHITE; constexpr SkColor kMediaNotificationBackgroundColor = SK_ColorWHITE;
// The ratio for a background color option to be considered very popular.
constexpr double kMediaNotificationBackgroundColorVeryPopularRatio = 2.5;
bool IsNearlyWhiteOrBlack(SkColor color) {
color_utils::HSL hsl;
color_utils::SkColorToHSL(color, &hsl);
return hsl.l >= 0.9 || hsl.l <= 0.08;
}
base::Optional<SkColor> GetNotificationBackgroundColor(const SkBitmap* source) {
if (!source || source->empty())
return base::nullopt;
std::vector<color_utils::Swatch> swatches =
color_utils::CalculateColorSwatches(
*source, 16, gfx::Rect(source->width() / 2, source->height()),
false /* exclude_uninteresting */);
if (swatches.empty())
return base::nullopt;
base::Optional<color_utils::Swatch> most_popular;
base::Optional<color_utils::Swatch> non_white_black;
// Find the most popular color with the most weight and the color which
// is the color with the most weight that is not white or black.
for (auto& swatch : swatches) {
if (!IsNearlyWhiteOrBlack(swatch.color) &&
(!non_white_black || swatch.population > non_white_black->population)) {
non_white_black = swatch;
}
if (most_popular && swatch.population < most_popular->population)
continue;
most_popular = swatch;
}
DCHECK(most_popular);
// If the most popular color is not white or black then we should use that.
if (!IsNearlyWhiteOrBlack(most_popular->color))
return most_popular->color;
// If we could not find a color that is not white or black then we should
// use the most popular color.
if (!non_white_black)
return most_popular->color;
// If the most popular color is very popular then we should use that color.
if (static_cast<double>(most_popular->population) /
non_white_black->population >
kMediaNotificationBackgroundColorVeryPopularRatio) {
return most_popular->color;
}
return non_white_black->color;
}
} // namespace } // namespace
...@@ -95,8 +32,6 @@ MediaNotificationBackground::MediaNotificationBackground( ...@@ -95,8 +32,6 @@ MediaNotificationBackground::MediaNotificationBackground(
DCHECK(owner); DCHECK(owner);
} }
MediaNotificationBackground::~MediaNotificationBackground() = default;
void MediaNotificationBackground::Paint(gfx::Canvas* canvas, void MediaNotificationBackground::Paint(gfx::Canvas* canvas,
views::View* view) const { views::View* view) const {
DCHECK(view); DCHECK(view);
...@@ -135,16 +70,18 @@ void MediaNotificationBackground::Paint(gfx::Canvas* canvas, ...@@ -135,16 +70,18 @@ void MediaNotificationBackground::Paint(gfx::Canvas* canvas,
// Draw a filled rectangle which will act as the main background of the // Draw a filled rectangle which will act as the main background of the
// notification. This may cover up some of the artwork. // notification. This may cover up some of the artwork.
const SkColor background_color = canvas->FillRect(GetFilledBackgroundBounds(bounds),
background_color_.value_or(kMediaNotificationDefaultBackgroundColor); kMediaNotificationBackgroundColor);
canvas->FillRect(GetFilledBackgroundBounds(bounds), background_color);
{ {
// Draw a gradient to fade the color background and the image together. // Draw a gradient to fade the color background and the image together.
gfx::Rect draw_bounds = GetGradientBounds(bounds); gfx::Rect draw_bounds = GetGradientBounds(bounds);
const SkColor colors[2] = { const SkColor transparent =
background_color, SkColorSetA(background_color, SK_AlphaTRANSPARENT)}; SkColorSetA(kMediaNotificationBackgroundColor, 0);
const SkColor colors[2] = {kMediaNotificationBackgroundColor, transparent};
const SkPoint points[2] = {gfx::PointToSkPoint(draw_bounds.left_center()), const SkPoint points[2] = {gfx::PointToSkPoint(draw_bounds.left_center()),
gfx::PointToSkPoint(draw_bounds.right_center())}; gfx::PointToSkPoint(draw_bounds.right_center())};
...@@ -163,7 +100,6 @@ void MediaNotificationBackground::UpdateArtwork(const gfx::ImageSkia& image) { ...@@ -163,7 +100,6 @@ void MediaNotificationBackground::UpdateArtwork(const gfx::ImageSkia& image) {
return; return;
artwork_ = image; artwork_ = image;
background_color_ = GetNotificationBackgroundColor(artwork_.bitmap());
owner_->SchedulePaint(); owner_->SchedulePaint();
} }
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
#define ASH_MEDIA_MEDIA_NOTIFICATION_BACKGROUND_H_ #define ASH_MEDIA_MEDIA_NOTIFICATION_BACKGROUND_H_
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "base/optional.h"
#include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia.h"
#include "ui/views/background.h" #include "ui/views/background.h"
...@@ -30,7 +29,6 @@ class ASH_EXPORT MediaNotificationBackground : public views::Background { ...@@ -30,7 +29,6 @@ class ASH_EXPORT MediaNotificationBackground : public views::Background {
int top_radius, int top_radius,
int bottom_radius, int bottom_radius,
double artwork_max_width_pct); double artwork_max_width_pct);
~MediaNotificationBackground() override;
// views::Background // views::Background
void Paint(gfx::Canvas* canvas, views::View* view) const override; void Paint(gfx::Canvas* canvas, views::View* view) const override;
...@@ -40,7 +38,6 @@ class ASH_EXPORT MediaNotificationBackground : public views::Background { ...@@ -40,7 +38,6 @@ class ASH_EXPORT MediaNotificationBackground : public views::Background {
void UpdateArtworkMaxWidthPct(double max_width_pct); void UpdateArtworkMaxWidthPct(double max_width_pct);
private: private:
friend class MediaNotificationBackgroundTest;
friend class MediaNotificationViewTest; friend class MediaNotificationViewTest;
FRIEND_TEST_ALL_PREFIXES(MediaNotificationBackgroundTest, BoundsSanityCheck); FRIEND_TEST_ALL_PREFIXES(MediaNotificationBackgroundTest, BoundsSanityCheck);
...@@ -59,8 +56,6 @@ class ASH_EXPORT MediaNotificationBackground : public views::Background { ...@@ -59,8 +56,6 @@ class ASH_EXPORT MediaNotificationBackground : public views::Background {
gfx::ImageSkia artwork_; gfx::ImageSkia artwork_;
double artwork_max_width_pct_; double artwork_max_width_pct_;
base::Optional<SkColor> background_color_;
DISALLOW_COPY_AND_ASSIGN(MediaNotificationBackground); DISALLOW_COPY_AND_ASSIGN(MediaNotificationBackground);
}; };
......
...@@ -11,172 +11,53 @@ ...@@ -11,172 +11,53 @@
namespace ash { namespace ash {
namespace {
gfx::ImageSkia CreateTestBackgroundImage(SkColor first_color,
SkColor second_color,
int second_height) {
constexpr SkColor kRightHandSideColor = SK_ColorMAGENTA;
DCHECK_NE(kRightHandSideColor, first_color);
DCHECK_NE(kRightHandSideColor, second_color);
SkBitmap bitmap;
bitmap.allocN32Pixels(100, 100);
int first_height = bitmap.height() - second_height;
int right_width = bitmap.width() / 2;
// Fill the right hand side of the image with a constant color. The color
// derivation algorithm does not look at the right hand side so we should
// never see |kRightHandSideColor|.
bitmap.erase(kRightHandSideColor,
{right_width, 0, bitmap.width(), bitmap.height()});
// Fill the left hand side with |first_color|.
bitmap.erase(first_color, {0, 0, right_width, first_height});
// Fill the left hand side with |second_color|.
bitmap.erase(second_color, {0, first_height, right_width, bitmap.height()});
return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
}
gfx::ImageSkia CreateTestBackgroundImage(SkColor color) {
return CreateTestBackgroundImage(color, SK_ColorTRANSPARENT, 0);
}
} // namespace
class MediaNotificationBackgroundTest : public AshTestBase { class MediaNotificationBackgroundTest : public AshTestBase {
public: public:
MediaNotificationBackgroundTest() = default; MediaNotificationBackgroundTest() = default;
~MediaNotificationBackgroundTest() override = default; ~MediaNotificationBackgroundTest() override = default;
void SetUp() override {
AshTestBase::SetUp();
owner_ = std::make_unique<views::StaticSizedView>();
background_ = std::make_unique<MediaNotificationBackground>(owner_.get(),
10, 10, 0.1);
EXPECT_FALSE(GetBackgroundColor().has_value());
}
void TearDown() override {
background_.reset();
owner_.reset();
AshTestBase::TearDown();
}
MediaNotificationBackground* background() const { return background_.get(); }
base::Optional<SkColor> GetBackgroundColor() const {
return background_->background_color_;
}
private: private:
std::unique_ptr<views::StaticSizedView> owner_;
std::unique_ptr<MediaNotificationBackground> background_;
DISALLOW_COPY_AND_ASSIGN(MediaNotificationBackgroundTest); DISALLOW_COPY_AND_ASSIGN(MediaNotificationBackgroundTest);
}; };
TEST_F(MediaNotificationBackgroundTest, BoundsSanityCheck) { TEST_F(MediaNotificationBackgroundTest, BoundsSanityCheck) {
views::StaticSizedView owner;
MediaNotificationBackground background(&owner, 10, 10, 0.1);
// The test notification will have a width of 200 and a height of 50. // The test notification will have a width of 200 and a height of 50.
gfx::Rect bounds(0, 0, 200, 50); gfx::Rect bounds(0, 0, 200, 50);
// Check the artwork is not visible by default. // Check the artwork is not visible by default.
EXPECT_EQ(0, background()->GetArtworkWidth(bounds.size())); EXPECT_EQ(0, background.GetArtworkWidth(bounds.size()));
EXPECT_EQ(0, background()->GetArtworkVisibleWidth(bounds.size())); EXPECT_EQ(0, background.GetArtworkVisibleWidth(bounds.size()));
EXPECT_EQ(gfx::Rect(200, 0, 0, 50), background()->GetArtworkBounds(bounds)); EXPECT_EQ(gfx::Rect(200, 0, 0, 50), background.GetArtworkBounds(bounds));
EXPECT_EQ(gfx::Rect(0, 0, 200, 50), EXPECT_EQ(gfx::Rect(0, 0, 200, 50),
background()->GetFilledBackgroundBounds(bounds)); background.GetFilledBackgroundBounds(bounds));
EXPECT_EQ(gfx::Rect(0, 0, 0, 0), background()->GetGradientBounds(bounds)); EXPECT_EQ(gfx::Rect(0, 0, 0, 0), background.GetGradientBounds(bounds));
// The background artwork image will have an aspect ratio of 2:1. // The background artwork image will have an aspect ratio of 2:1.
SkBitmap bitmap; SkBitmap bitmap;
bitmap.allocN32Pixels(20, 10); bitmap.allocN32Pixels(20, 10);
background()->UpdateArtwork(gfx::ImageSkia::CreateFrom1xBitmap(bitmap)); background.UpdateArtwork(gfx::ImageSkia::CreateFrom1xBitmap(bitmap));
// The artwork width will be 2x the height of the notification and the visible // The artwork width will be 2x the height of the notification and the visible
// width will be limited to 10% the width of the notification. // width will be limited to 10% the width of the notification.
EXPECT_EQ(100, background()->GetArtworkWidth(bounds.size())); EXPECT_EQ(100, background.GetArtworkWidth(bounds.size()));
EXPECT_EQ(20, background()->GetArtworkVisibleWidth(bounds.size())); EXPECT_EQ(20, background.GetArtworkVisibleWidth(bounds.size()));
// Update the visible width % to be greater than the width of the image. // Update the visible width % to be greater than the width of the image.
background()->UpdateArtworkMaxWidthPct(0.6); background.UpdateArtworkMaxWidthPct(0.6);
EXPECT_EQ(100, background()->GetArtworkVisibleWidth(bounds.size())); EXPECT_EQ(100, background.GetArtworkVisibleWidth(bounds.size()));
// Check the artwork is positioned to the right. // Check the artwork is positioned to the right.
EXPECT_EQ(gfx::Rect(100, 0, 100, 50), background()->GetArtworkBounds(bounds)); EXPECT_EQ(gfx::Rect(100, 0, 100, 50), background.GetArtworkBounds(bounds));
// Check the filled background is to the left of the image. // Check the filled background is to the left of the image.
EXPECT_EQ(gfx::Rect(0, 0, 100, 50), EXPECT_EQ(gfx::Rect(0, 0, 100, 50),
background()->GetFilledBackgroundBounds(bounds)); background.GetFilledBackgroundBounds(bounds));
// Check the gradient is positioned above the artwork. // Check the gradient is positioned above the artwork.
EXPECT_EQ(gfx::Rect(100, 0, 40, 50), background()->GetGradientBounds(bounds)); EXPECT_EQ(gfx::Rect(100, 0, 40, 50), background.GetGradientBounds(bounds));
}
// If we have no artwork then we should use the default background color.
TEST_F(MediaNotificationBackgroundTest, DeriveBackgroundColor_NoArtwork) {
background()->UpdateArtwork(gfx::ImageSkia());
EXPECT_FALSE(GetBackgroundColor().has_value());
}
// If we have artwork with no popular color then we should use the default
// background color.
TEST_F(MediaNotificationBackgroundTest, DeriveBackgroundColor_NoPopularColor) {
background()->UpdateArtwork(CreateTestBackgroundImage(SK_ColorTRANSPARENT));
EXPECT_FALSE(GetBackgroundColor().has_value());
}
// If the most popular color is not white or black then we should use that
// color.
TEST_F(MediaNotificationBackgroundTest,
DeriveBackgroundColor_PopularNonWhiteBlackColor) {
constexpr SkColor kTestColor = SK_ColorYELLOW;
background()->UpdateArtwork(CreateTestBackgroundImage(kTestColor));
EXPECT_EQ(kTestColor, GetBackgroundColor());
}
// MediaNotificationBackgroundBlackWhiteTest will repeat these tests with a
// parameter that is either black or white.
class MediaNotificationBackgroundBlackWhiteTest
: public MediaNotificationBackgroundTest,
public testing::WithParamInterface<SkColor> {};
INSTANTIATE_TEST_SUITE_P(,
MediaNotificationBackgroundBlackWhiteTest,
testing::Values(SK_ColorBLACK, SK_ColorWHITE));
// If the most popular color is black or white but there is no secondary color
// we should use the most popular color.
TEST_P(MediaNotificationBackgroundBlackWhiteTest,
DeriveBackgroundColor_PopularBlackWhiteNoSecondaryColor) {
background()->UpdateArtwork(CreateTestBackgroundImage(GetParam()));
EXPECT_EQ(GetParam(), GetBackgroundColor());
}
// If the most popular color is black or white and there is a secondary color
// that is very minor then we should use the most popular color.
TEST_P(MediaNotificationBackgroundBlackWhiteTest,
DeriveBackgroundColor_VeryPopularBlackWhite) {
background()->UpdateArtwork(
CreateTestBackgroundImage(GetParam(), SK_ColorYELLOW, 20));
EXPECT_EQ(GetParam(), GetBackgroundColor());
}
// If the most popular color is black or white but it is not that popular then
// we should use the secondary color.
TEST_P(MediaNotificationBackgroundBlackWhiteTest,
DeriveBackgroundColor_NotVeryPopularBlackWhite) {
constexpr SkColor kTestColor = SK_ColorYELLOW;
background()->UpdateArtwork(
CreateTestBackgroundImage(GetParam(), kTestColor, 40));
EXPECT_EQ(kTestColor, GetBackgroundColor());
} }
} // namespace ash } // namespace ash
This diff is collapsed.
...@@ -16,10 +16,6 @@ ...@@ -16,10 +16,6 @@
class SkBitmap; class SkBitmap;
namespace gfx {
class Rect;
} // namespace gfx
namespace color_utils { namespace color_utils {
struct HSL; struct HSL;
...@@ -140,35 +136,6 @@ struct ColorProfile { ...@@ -140,35 +136,6 @@ struct ColorProfile {
SaturationRange saturation = SaturationRange::MUTED; SaturationRange saturation = SaturationRange::MUTED;
}; };
// A color value with an associated weight.
struct Swatch {
Swatch(SkColor color, size_t population)
: color(color), population(population) {}
SkColor color;
// The population correlates to a count, so it should be 1 or greater.
size_t population;
bool operator==(const Swatch& other) const {
return color == other.color && population == other.population;
}
};
// Returns a vector of |Swatch| that represent the prominent colors of the
// bitmap within |region|. The |max_swatches| is the maximum number of swatches.
// For landscapes, good values are in the range 12-16. For images which are
// largely made up of people's faces then this value should be increased to
// 24-32. |exclude_uninteresting| will exclude colors that are not interesting
// (e.g. too white or black).
// This is an implementation of the Android Palette API:
// https://developer.android.com/reference/android/support/v7/graphics/Palette
GFX_EXPORT std::vector<Swatch> CalculateColorSwatches(
const SkBitmap& bitmap,
size_t max_swatches,
const gfx::Rect& region,
bool exclude_uninteresting);
// Returns a vector of RGB colors that represents the bitmap based on the // Returns a vector of RGB colors that represents the bitmap based on the
// |color_profiles| provided. For each value, if a value is succesfully // |color_profiles| provided. For each value, if a value is succesfully
// calculated, the calculated value is fully opaque. For failure, the calculated // calculated, the calculated value is fully opaque. For failure, the calculated
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <exception>
#include <vector> #include <vector>
#include "skia/ext/platform_canvas.h" #include "skia/ext/platform_canvas.h"
...@@ -547,67 +546,4 @@ TEST_F(ColorAnalysisTest, ComputeProminentColors) { ...@@ -547,67 +546,4 @@ TEST_F(ColorAnalysisTest, ComputeProminentColors) {
EXPECT_EQ(expectations, computations); EXPECT_EQ(expectations, computations);
} }
TEST_F(ColorAnalysisTest, ComputeColorSwatches) {
SkBitmap bitmap;
bitmap.allocN32Pixels(100, 100);
bitmap.eraseColor(SK_ColorMAGENTA);
bitmap.erase(SK_ColorGREEN, {10, 10, 90, 90});
bitmap.erase(SK_ColorYELLOW, {40, 40, 60, 60});
const Swatch kYellowSwatch = Swatch(SK_ColorYELLOW, (20u * 20u));
const Swatch kGreenSwatch =
Swatch(SK_ColorGREEN, (80u * 80u) - kYellowSwatch.population);
const Swatch kMagentaSwatch =
Swatch(SK_ColorMAGENTA, (100u * 100u) - kGreenSwatch.population -
kYellowSwatch.population);
{
std::vector<Swatch> colors =
CalculateColorSwatches(bitmap, 10, gfx::Rect(100, 100), false);
EXPECT_EQ(3u, colors.size());
EXPECT_EQ(kGreenSwatch, colors[0]);
EXPECT_EQ(kMagentaSwatch, colors[1]);
EXPECT_EQ(kYellowSwatch, colors[2]);
}
{
std::vector<Swatch> colors =
CalculateColorSwatches(bitmap, 10, gfx::Rect(10, 10, 80, 80), false);
EXPECT_EQ(2u, colors.size());
EXPECT_EQ(kGreenSwatch, colors[0]);
EXPECT_EQ(kYellowSwatch, colors[1]);
}
}
TEST_F(ColorAnalysisTest, ComputeColorSwatches_Uninteresting) {
SkBitmap bitmap;
bitmap.allocN32Pixels(100, 100);
bitmap.eraseColor(SK_ColorMAGENTA);
bitmap.erase(SK_ColorBLACK, {10, 10, 90, 90});
bitmap.erase(SK_ColorWHITE, {40, 40, 60, 60});
const Swatch kWhiteSwatch = Swatch(SK_ColorWHITE, (20u * 20u));
const Swatch kBlackSwatch =
Swatch(SK_ColorBLACK, (80u * 80u) - kWhiteSwatch.population);
const Swatch kMagentaSwatch =
Swatch(SK_ColorMAGENTA,
(100u * 100u) - kBlackSwatch.population - kWhiteSwatch.population);
{
std::vector<Swatch> colors =
CalculateColorSwatches(bitmap, 10, gfx::Rect(100, 100), true);
EXPECT_EQ(1u, colors.size());
EXPECT_EQ(kMagentaSwatch, colors[0]);
}
{
std::vector<Swatch> colors =
CalculateColorSwatches(bitmap, 10, gfx::Rect(100, 100), false);
EXPECT_EQ(3u, colors.size());
EXPECT_EQ(kBlackSwatch, colors[0]);
EXPECT_EQ(kMagentaSwatch, colors[1]);
EXPECT_EQ(kWhiteSwatch, colors[2]);
}
}
} // namespace color_utils } // namespace color_utils
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