Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(704)

Unified Diff: chrome/browser/chromeos/ui/accessibility_focus_ring_controller.cc

Issue 1822823002: Implement Chrome OS accessibility features to highlight focus, caret & cursor. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Landing without views_delegate change for now Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/ui/accessibility_focus_ring_controller.cc
diff --git a/chrome/browser/chromeos/ui/accessibility_focus_ring_controller.cc b/chrome/browser/chromeos/ui/accessibility_focus_ring_controller.cc
index c34aa443b02817a042bfc882b85c10efe36ac687..6cbad6e4967039f03c96079a67885419a3c4a7bf 100644
--- a/chrome/browser/chromeos/ui/accessibility_focus_ring_controller.cc
+++ b/chrome/browser/chromeos/ui/accessibility_focus_ring_controller.cc
@@ -6,6 +6,8 @@
#include <stddef.h>
+#include <algorithm>
+
#include "ash/display/window_tree_host_manager.h"
#include "ash/shell.h"
#include "base/logging.h"
@@ -24,6 +26,19 @@ const int kAccessibilityFocusRingMargin = 7;
// Time to transition between one location and the next.
const int kTransitionTimeMilliseconds = 300;
+const int kCursorFadeInTimeMilliseconds = 400;
+const int kCursorFadeOutTimeMilliseconds = 1200;
+
+// The color of the cursor ring.
+const int kCursorRingColorRed = 255;
+const int kCursorRingColorGreen = 51;
+const int kCursorRingColorBlue = 51;
+
+// The color of the caret ring.
+const int kCaretRingColorRed = 51;
+const int kCaretRingColorGreen = 51;
+const int kCaretRingColorBlue = 255;
+
// A Region is an unordered collection of Rects that maintains its
// bounding box. Used in the middle of an algorithm that groups
// adjacent and overlapping rects.
@@ -45,8 +60,7 @@ AccessibilityFocusRingController*
}
AccessibilityFocusRingController::AccessibilityFocusRingController()
- : compositor_(nullptr) {
-}
+ : compositor_(nullptr), cursor_opacity_(0), cursor_compositor_(nullptr) {}
AccessibilityFocusRingController::~AccessibilityFocusRingController() {
}
@@ -62,6 +76,9 @@ void AccessibilityFocusRingController::Update() {
rings_.clear();
RectsToRings(rects_, &rings_);
layers_.resize(rings_.size());
+ if (rings_.empty())
+ return;
+
for (size_t i = 0; i < rings_.size(); ++i) {
if (!layers_[i])
layers_[i] = new AccessibilityFocusRingLayer(this);
@@ -69,32 +86,82 @@ void AccessibilityFocusRingController::Update() {
if (i > 0) {
// Focus rings other than the first one don't animate.
layers_[i]->Set(rings_[i]);
- continue;
}
+ }
- gfx::Rect bounds = rings_[0].GetBounds();
- gfx::Display display = gfx::Screen::GetScreen()->GetDisplayMatching(bounds);
- aura::Window* root_window = ash::Shell::GetInstance()
- ->window_tree_host_manager()
- ->GetRootWindowForDisplayId(display.id());
- ui::Compositor* compositor = root_window->layer()->GetCompositor();
- if (!compositor || root_window != layers_[0]->root_window()) {
- layers_[0]->Set(rings_[0]);
- if (compositor_ && compositor_->HasAnimationObserver(this)) {
- compositor_->RemoveAnimationObserver(this);
- compositor_ = nullptr;
- }
- continue;
- }
+ ui::Compositor* compositor = CompositorForBounds(rings_[0].GetBounds());
+ if (compositor != compositor_) {
+ RemoveAnimationObservers();
+ compositor_ = compositor;
+ AddAnimationObservers();
+ }
+ if (compositor_ && compositor_->HasAnimationObserver(this)) {
focus_change_time_ = base::TimeTicks::Now();
- if (!compositor->HasAnimationObserver(this)) {
- compositor_ = compositor;
- compositor_->AddAnimationObserver(this);
- }
+ } else {
+ // If we can't animate, set the location of the first ring.
+ layers_[0]->Set(rings_[0]);
+ }
+}
+
+ui::Compositor* AccessibilityFocusRingController::CompositorForBounds(
+ const gfx::Rect& bounds) {
+ gfx::Display display = gfx::Screen::GetScreen()->GetDisplayMatching(bounds);
+ aura::Window* root_window = ash::Shell::GetInstance()
+ ->window_tree_host_manager()
+ ->GetRootWindowForDisplayId(display.id());
+ return root_window->layer()->GetCompositor();
+}
+
+void AccessibilityFocusRingController::RemoveAnimationObservers() {
+ if (compositor_ && compositor_->HasAnimationObserver(this))
+ compositor_->RemoveAnimationObserver(this);
+ if (cursor_compositor_ && cursor_compositor_->HasAnimationObserver(this))
+ cursor_compositor_->RemoveAnimationObserver(this);
+}
+
+void AccessibilityFocusRingController::AddAnimationObservers() {
+ if (compositor_ && !compositor_->HasAnimationObserver(this))
+ compositor_->AddAnimationObserver(this);
+ if (cursor_compositor_ && !cursor_compositor_->HasAnimationObserver(this))
+ cursor_compositor_->AddAnimationObserver(this);
+}
+
+void AccessibilityFocusRingController::SetCursorRing(
+ const gfx::Point& location) {
+ cursor_location_ = location;
+ cursor_change_time_ = base::TimeTicks::Now();
+ if (cursor_opacity_ == 0)
+ cursor_start_time_ = cursor_change_time_;
+
+ if (!cursor_layer_) {
+ cursor_layer_.reset(new AccessibilityCursorRingLayer(
+ this, kCursorRingColorRed, kCursorRingColorGreen,
+ kCursorRingColorBlue));
+ }
+ cursor_layer_->Set(location);
+
+ ui::Compositor* compositor =
+ CompositorForBounds(gfx::Rect(location.x(), location.y(), 0, 0));
+ if (compositor != cursor_compositor_) {
+ RemoveAnimationObservers();
+ cursor_compositor_ = compositor;
+ AddAnimationObservers();
}
}
+void AccessibilityFocusRingController::SetCaretRing(
+ const gfx::Point& location) {
+ caret_location_ = location;
+
+ if (!caret_layer_) {
+ caret_layer_.reset(new AccessibilityCursorRingLayer(
+ this, kCaretRingColorRed, kCaretRingColorGreen, kCaretRingColorBlue));
+ }
+
+ caret_layer_->Set(location);
+}
+
void AccessibilityFocusRingController::RectsToRings(
const std::vector<gfx::Rect>& src_rects,
std::vector<AccessibilityFocusRing>* rings) const {
@@ -291,10 +358,15 @@ void AccessibilityFocusRingController::OnDeviceScaleFactorChanged() {
void AccessibilityFocusRingController::OnAnimationStep(
base::TimeTicks timestamp) {
- if (rings_.empty())
- return;
+ if (!rings_.empty() && compositor_)
+ AnimateFocusRings(timestamp);
- CHECK(compositor_);
+ if (cursor_layer_ && cursor_compositor_)
+ AnimateCursorRing(timestamp);
+}
+
+void AccessibilityFocusRingController::AnimateFocusRings(
+ base::TimeTicks timestamp) {
CHECK(!rings_.empty());
CHECK(!layers_.empty());
CHECK(layers_[0]);
@@ -310,8 +382,10 @@ void AccessibilityFocusRingController::OnAnimationStep(
base::TimeDelta::FromMilliseconds(kTransitionTimeMilliseconds);
if (delta >= transition_time) {
layers_[0]->Set(rings_[0]);
- compositor_->RemoveAnimationObserver(this);
+
+ RemoveAnimationObservers();
compositor_ = nullptr;
+ AddAnimationObservers();
return;
}
@@ -320,15 +394,60 @@ void AccessibilityFocusRingController::OnAnimationStep(
// Ease-in effect.
fraction = pow(fraction, 0.3);
+ // Handle corner case where we're animating but we don't have previous
+ // rings.
+ if (previous_rings_.empty())
+ previous_rings_ = rings_;
+
layers_[0]->Set(AccessibilityFocusRing::Interpolate(
previous_rings_[0], rings_[0], fraction));
}
+void AccessibilityFocusRingController::AnimateCursorRing(
+ base::TimeTicks timestamp) {
+ CHECK(cursor_layer_);
+
+ // It's quite possible for the first 1 or 2 animation frames to be
+ // for a timestamp that's earlier than the time we received the
+ // mouse movement, so we just treat those as a delta of zero.
+ if (timestamp < cursor_start_time_)
+ timestamp = cursor_start_time_;
+
+ base::TimeDelta start_delta = timestamp - cursor_start_time_;
+ base::TimeDelta change_delta = timestamp - cursor_change_time_;
+ base::TimeDelta fade_in_time =
+ base::TimeDelta::FromMilliseconds(kCursorFadeInTimeMilliseconds);
+ base::TimeDelta fade_out_time =
+ base::TimeDelta::FromMilliseconds(kCursorFadeOutTimeMilliseconds);
+
+ if (change_delta > fade_in_time + fade_out_time) {
+ cursor_opacity_ = 0.0;
+ cursor_layer_.reset();
+ return;
+ }
+
+ if (start_delta < fade_in_time) {
+ cursor_opacity_ = start_delta.InSecondsF() / fade_in_time.InSecondsF();
+ if (cursor_opacity_ > 1.0)
+ cursor_opacity_ = 1.0;
+ } else {
+ cursor_opacity_ = 1.0 - (change_delta.InSecondsF() /
+ (fade_in_time + fade_out_time).InSecondsF());
+ if (cursor_opacity_ < 0.0)
+ cursor_opacity_ = 0.0;
+ }
+ cursor_layer_->SetOpacity(cursor_opacity_);
+}
+
void AccessibilityFocusRingController::OnCompositingShuttingDown(
ui::Compositor* compositor) {
- DCHECK_EQ(compositor_, compositor);
- compositor_->RemoveAnimationObserver(this);
- compositor_ = nullptr;
+ if (compositor == compositor_ || compositor == cursor_compositor_)
+ compositor->RemoveAnimationObserver(this);
+
+ if (compositor == compositor_)
+ compositor_ = nullptr;
+ if (compositor == cursor_compositor_)
+ cursor_compositor_ = nullptr;
}
} // namespace chromeos
« no previous file with comments | « chrome/browser/chromeos/ui/accessibility_focus_ring_controller.h ('k') | chrome/chrome_browser_chromeos.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698