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 |