Commit b89144a4 authored by Alice Boxhall's avatar Alice Boxhall Committed by Commit Bot

Add pixel test for AccessibilityFocusHighlight based on FocusRingBrowserTest

AX-Relnotes: n/a

Bug: 1114959
Change-Id: Ib6d9f51a04fa8059dc6bd6192d182b8e0244367d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2352451
Commit-Queue: Alice Boxhall <aboxhall@chromium.org>
Reviewed-by: default avatarElly Fong-Jones <ellyjones@chromium.org>
Reviewed-by: default avatarJoey Arhar <jarhar@chromium.org>
Reviewed-by: default avatarMason Freed <masonfreed@chromium.org>
Cr-Commit-Position: refs/heads/master@{#803007}
parent 4f5a6631
...@@ -77,6 +77,9 @@ bool AccessibilityFocusHighlight::skip_activation_check_for_testing_ = false; ...@@ -77,6 +77,9 @@ bool AccessibilityFocusHighlight::skip_activation_check_for_testing_ = false;
// static // static
bool AccessibilityFocusHighlight::use_default_color_for_testing_ = false; bool AccessibilityFocusHighlight::use_default_color_for_testing_ = false;
// static
bool AccessibilityFocusHighlight::no_fade_for_testing_ = false;
AccessibilityFocusHighlight::AccessibilityFocusHighlight( AccessibilityFocusHighlight::AccessibilityFocusHighlight(
BrowserView* browser_view) BrowserView* browser_view)
: browser_view_(browser_view) { : browser_view_(browser_view) {
...@@ -98,7 +101,7 @@ AccessibilityFocusHighlight::AccessibilityFocusHighlight( ...@@ -98,7 +101,7 @@ AccessibilityFocusHighlight::AccessibilityFocusHighlight(
fade_in_time_ = kFadeInTime; fade_in_time_ = kFadeInTime;
persist_time_ = kHighlightPersistTime; persist_time_ = kHighlightPersistTime;
fade_out_time_ = kFadeOutTime; fade_out_time_ = kFadeOutTime;
default_color_ = SkColorSetRGB(16, 16, 16); // #101010 default_color_ = SkColorSetRGB(0x10, 0x10, 0x10); // #101010
} }
} }
...@@ -109,9 +112,7 @@ AccessibilityFocusHighlight::~AccessibilityFocusHighlight() { ...@@ -109,9 +112,7 @@ AccessibilityFocusHighlight::~AccessibilityFocusHighlight() {
// static // static
void AccessibilityFocusHighlight::SetNoFadeForTesting() { void AccessibilityFocusHighlight::SetNoFadeForTesting() {
fade_in_time_ = base::TimeDelta(); no_fade_for_testing_ = true;
persist_time_ = base::TimeDelta::FromHours(1);
fade_out_time_ = base::TimeDelta();
} }
// static // static
...@@ -124,7 +125,17 @@ void AccessibilityFocusHighlight::UseDefaultColorForTesting() { ...@@ -124,7 +125,17 @@ void AccessibilityFocusHighlight::UseDefaultColorForTesting() {
use_default_color_for_testing_ = true; use_default_color_for_testing_ = true;
} }
// static
ui::Layer* AccessibilityFocusHighlight::GetLayerForTesting() {
return layer_.get();
}
SkColor AccessibilityFocusHighlight::GetHighlightColor() { SkColor AccessibilityFocusHighlight::GetHighlightColor() {
#if !defined(OS_MAC)
// Match behaviour with renderer_preferences_util::UpdateFromSystemSettings
// setting prefs->focus_ring_color
return default_color_;
#else
ui::NativeTheme* native_theme = ui::NativeTheme::GetInstanceForWeb(); ui::NativeTheme* native_theme = ui::NativeTheme::GetInstanceForWeb();
SkColor theme_color = native_theme->GetSystemColor( SkColor theme_color = native_theme->GetSystemColor(
ui::NativeTheme::kColorId_FocusedBorderColor); ui::NativeTheme::kColorId_FocusedBorderColor);
...@@ -133,6 +144,7 @@ SkColor AccessibilityFocusHighlight::GetHighlightColor() { ...@@ -133,6 +144,7 @@ SkColor AccessibilityFocusHighlight::GetHighlightColor() {
return default_color_; return default_color_;
return native_theme->FocusRingColorForBaseColor(theme_color); return native_theme->FocusRingColorForBaseColor(theme_color);
#endif
} }
void AccessibilityFocusHighlight::CreateOrUpdateLayer(gfx::Rect node_bounds) { void AccessibilityFocusHighlight::CreateOrUpdateLayer(gfx::Rect node_bounds) {
...@@ -193,6 +205,9 @@ void AccessibilityFocusHighlight::CreateOrUpdateLayer(gfx::Rect node_bounds) { ...@@ -193,6 +205,9 @@ void AccessibilityFocusHighlight::CreateOrUpdateLayer(gfx::Rect node_bounds) {
} }
void AccessibilityFocusHighlight::RemoveLayer() { void AccessibilityFocusHighlight::RemoveLayer() {
if (no_fade_for_testing_)
return;
layer_.reset(); layer_.reset();
if (compositor_) { if (compositor_) {
compositor_->RemoveAnimationObserver(this); compositor_->RemoveAnimationObserver(this);
...@@ -311,6 +326,29 @@ void AccessibilityFocusHighlight::OnPaintLayer( ...@@ -311,6 +326,29 @@ void AccessibilityFocusHighlight::OnPaintLayer(
recorder.canvas()->DrawRoundRect(bounds, kBorderRadius, original_flags); recorder.canvas()->DrawRoundRect(bounds, kBorderRadius, original_flags);
} }
float AccessibilityFocusHighlight::ComputeOpacity(
base::TimeDelta time_since_layer_create,
base::TimeDelta time_since_focus_move) {
float opacity = 1.0f;
if (no_fade_for_testing_)
return opacity;
if (time_since_layer_create < fade_in_time_) {
// We're fading in.
opacity = time_since_layer_create / fade_in_time_;
}
if (time_since_focus_move > persist_time_) {
// Fading out.
base::TimeDelta time_since_began_fading =
time_since_focus_move - (fade_in_time_ + persist_time_);
opacity = 1.0f - (time_since_began_fading / fade_out_time_);
}
return base::ClampToRange(opacity, 0.0f, 1.0f);
}
void AccessibilityFocusHighlight::OnAnimationStep(base::TimeTicks timestamp) { void AccessibilityFocusHighlight::OnAnimationStep(base::TimeTicks timestamp) {
if (!layer_) if (!layer_)
return; return;
...@@ -338,21 +376,8 @@ void AccessibilityFocusHighlight::OnAnimationStep(base::TimeTicks timestamp) { ...@@ -338,21 +376,8 @@ void AccessibilityFocusHighlight::OnAnimationStep(base::TimeTicks timestamp) {
return; return;
} }
// Compute the opacity based on the fade in and fade out times. float opacity =
// TODO(aboxhall): figure out how to use cubic beziers ComputeOpacity(time_since_layer_create, time_since_focus_move);
float opacity = 1.0f;
if (time_since_layer_create < fade_in_time_) {
// We're fading in.
opacity = time_since_layer_create / fade_in_time_;
} else if (time_since_focus_move > persist_time_) {
// Fading out.
base::TimeDelta time_since_began_fading =
time_since_focus_move - (fade_in_time_ + persist_time_);
opacity = 1.0f - (time_since_began_fading / fade_out_time_);
}
// Layer::SetOpacity will throw an error if we're not within 0...1.
opacity = base::ClampToRange(opacity, 0.0f, 1.0f);
layer_->SetOpacity(opacity); layer_->SetOpacity(opacity);
} }
......
...@@ -42,10 +42,13 @@ class AccessibilityFocusHighlight : public ui::LayerDelegate, ...@@ -42,10 +42,13 @@ class AccessibilityFocusHighlight : public ui::LayerDelegate,
private: private:
FRIEND_TEST_ALL_PREFIXES(AccessibilityFocusHighlightBrowserTest, FRIEND_TEST_ALL_PREFIXES(AccessibilityFocusHighlightBrowserTest,
DrawsHighlight); DrawsHighlight);
FRIEND_TEST_ALL_PREFIXES(AccessibilityFocusHighlightBrowserTest,
FocusAppearance);
// For testing. // For testing.
static void SetNoFadeForTesting(); static void SetNoFadeForTesting();
static void SkipActivationCheckForTesting(); static void SkipActivationCheckForTesting();
static void UseDefaultColorForTesting(); static void UseDefaultColorForTesting();
ui::Layer* GetLayerForTesting();
// Create the layer if needed, and set node_bounds_ // Create the layer if needed, and set node_bounds_
void CreateOrUpdateLayer(gfx::Rect node_bounds); void CreateOrUpdateLayer(gfx::Rect node_bounds);
...@@ -73,6 +76,11 @@ class AccessibilityFocusHighlight : public ui::LayerDelegate, ...@@ -73,6 +76,11 @@ class AccessibilityFocusHighlight : public ui::LayerDelegate,
// Compute the highlight color based on theme colors and defaults. // Compute the highlight color based on theme colors and defaults.
SkColor GetHighlightColor(); SkColor GetHighlightColor();
// Compute the opacity based on the fade in and fade out times.
// TODO(aboxhall): figure out how to use cubic beziers
float ComputeOpacity(base::TimeDelta time_since_layer_create,
base::TimeDelta time_since_focus_move);
// The layer, if visible. // The layer, if visible.
std::unique_ptr<ui::Layer> layer_; std::unique_ptr<ui::Layer> layer_;
...@@ -94,6 +102,9 @@ class AccessibilityFocusHighlight : public ui::LayerDelegate, ...@@ -94,6 +102,9 @@ class AccessibilityFocusHighlight : public ui::LayerDelegate,
// The default color used for the highlight. // The default color used for the highlight.
static SkColor default_color_; static SkColor default_color_;
// Whether to skip fade in/fade out for testing.
static bool no_fade_for_testing_;
// The amount of time it should take for the highlight to fade in. // The amount of time it should take for the highlight to fade in.
static base::TimeDelta fade_in_time_; static base::TimeDelta fade_in_time_;
......
...@@ -4,12 +4,18 @@ ...@@ -4,12 +4,18 @@
#include "math.h" #include "math.h"
#include "base/path_service.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "cc/test/pixel_comparator.h"
#include "cc/test/pixel_test_utils.h"
#include "chrome/browser/ui/views/accessibility/accessibility_focus_highlight.h" #include "chrome/browser/ui/views/accessibility/accessibility_focus_highlight.h"
#include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
#include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h" #include "chrome/test/base/ui_test_utils.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "content/public/browser/focused_node_details.h" #include "content/public/browser/focused_node_details.h"
#include "content/public/browser/notification_registrar.h" #include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_types.h" #include "content/public/browser/notification_types.h"
...@@ -20,6 +26,19 @@ ...@@ -20,6 +26,19 @@
#include "ui/snapshot/snapshot.h" #include "ui/snapshot/snapshot.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
#if defined(OS_MAC)
#include "base/mac/mac_util.h"
#endif
// To rebaseline this test on all platforms:
// 1. Run a CQ+1 dry run.
// 2. Click the failing bots for android, windows, mac, and linux.
// 3. Find the failing interactive_ui_browsertests step.
// 4. Click the "Deterministic failure" link for the failing test case.
// 5. Copy the "Actual pixels" data url and paste into browser.
// 6. Save the image into your chromium checkout in
// chrome/test/data/accessibility.
class AccessibilityFocusHighlightBrowserTest : public InProcessBrowserTest { class AccessibilityFocusHighlightBrowserTest : public InProcessBrowserTest {
public: public:
AccessibilityFocusHighlightBrowserTest() = default; AccessibilityFocusHighlightBrowserTest() = default;
...@@ -229,3 +248,98 @@ IN_PROC_BROWSER_TEST_F(AccessibilityFocusHighlightBrowserTest, ...@@ -229,3 +248,98 @@ IN_PROC_BROWSER_TEST_F(AccessibilityFocusHighlightBrowserTest,
// Not sure where the extra px of height are coming from... // Not sure where the extra px of height are coming from...
EXPECT_EQ(147, bounds.height()); EXPECT_EQ(147, bounds.height());
} }
class ReadbackHolder : public base::RefCountedThreadSafe<ReadbackHolder> {
public:
ReadbackHolder() : run_loop_(std::make_unique<base::RunLoop>()) {}
void OutputRequestCallback(std::unique_ptr<viz::CopyOutputResult> result) {
if (result->IsEmpty())
result_.reset();
else
result_ = std::make_unique<SkBitmap>(result->AsSkBitmap());
run_loop_->Quit();
}
void WaitForReadback() { run_loop_->Run(); }
const SkBitmap& result() const { return *result_; }
private:
friend class base::RefCountedThreadSafe<ReadbackHolder>;
virtual ~ReadbackHolder() = default;
std::unique_ptr<SkBitmap> result_;
std::unique_ptr<base::RunLoop> run_loop_;
};
const cc::ExactPixelComparator pixel_comparator(/*discard_alpha=*/false);
IN_PROC_BROWSER_TEST_F(AccessibilityFocusHighlightBrowserTest,
FocusAppearance) {
base::ScopedAllowBlockingForTesting allow_blocking;
AccessibilityFocusHighlight::SetNoFadeForTesting();
AccessibilityFocusHighlight::SkipActivationCheckForTesting();
browser()->profile()->GetPrefs()->SetBoolean(
prefs::kAccessibilityFocusHighlightEnabled, true);
ui_test_utils::NavigateToURL(browser(), GURL("data:text/html,"
"<a id='link' href=''>"
"<img width='10' height='10'>"
"</a>"));
FocusedNodeChangedObserver observer;
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
std::string script("document.getElementById('link').focus();");
ASSERT_TRUE(content::ExecuteScript(web_contents, script));
observer.WaitForFocusChangeInPage();
BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
AccessibilityFocusHighlight* highlight =
browser_view->GetAccessibilityFocusHighlightForTesting();
ui::Layer* layer = highlight->GetLayerForTesting();
gfx::Rect source_rect = gfx::Rect(layer->size());
scoped_refptr<ReadbackHolder> holder(new ReadbackHolder);
std::unique_ptr<viz::CopyOutputRequest> request =
std::make_unique<viz::CopyOutputRequest>(
viz::CopyOutputRequest::ResultFormat::RGBA_BITMAP,
base::BindOnce(&ReadbackHolder::OutputRequestCallback, holder));
request->set_area(source_rect);
layer->RequestCopyOfOutput(std::move(request));
holder->WaitForReadback();
SkBitmap bitmap(holder->result());
ASSERT_FALSE(bitmap.drawsNothing());
base::FilePath dir_test_data;
ASSERT_TRUE(base::PathService::Get(chrome::DIR_TEST_DATA, &dir_test_data));
std::string screenshot_filename = "focus_highlight_appearance";
std::string platform_suffix;
#if defined(OS_MAC)
// Mac 10.14 used a subtly different highlight color.
if (base::mac::IsOS10_14())
platform_suffix = "_mac10.14";
else
platform_suffix = "_mac";
#elif defined(OS_WIN)
platform_suffix = "_win";
#endif
base::FilePath golden_filepath =
dir_test_data.AppendASCII("accessibility")
.AppendASCII(screenshot_filename + ".png");
base::FilePath golden_filepath_platform =
golden_filepath.InsertBeforeExtensionASCII(platform_suffix);
if (base::PathExists(golden_filepath_platform)) {
golden_filepath = golden_filepath_platform;
}
bool snapshot_matches =
cc::MatchesPNGFile(bitmap, golden_filepath, pixel_comparator);
EXPECT_TRUE(snapshot_matches);
}
...@@ -593,6 +593,10 @@ class BrowserView : public BrowserWindow, ...@@ -593,6 +593,10 @@ class BrowserView : public BrowserWindow,
// Create and open the tab search bubble. // Create and open the tab search bubble.
void CreateTabSearchBubble() override; void CreateTabSearchBubble() override;
AccessibilityFocusHighlight* GetAccessibilityFocusHighlightForTesting() {
return accessibility_focus_highlight_.get();
}
private: private:
// Do not friend BrowserViewLayout. Use the BrowserViewLayoutDelegate // Do not friend BrowserViewLayout. Use the BrowserViewLayoutDelegate
// interface to keep these two classes decoupled and testable. // interface to keep these two classes decoupled and testable.
......
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