| 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 aaca4c5199bbd39b983223edf8f44c68596c5b8c..b2c93a80312310a6239b2c9041c5518244bee748 100644
|
| --- a/chrome/browser/chromeos/ui/accessibility_focus_ring_controller.cc
|
| +++ b/chrome/browser/chromeos/ui/accessibility_focus_ring_controller.cc
|
| @@ -4,7 +4,11 @@
|
|
|
| #include "chrome/browser/chromeos/ui/accessibility_focus_ring_controller.h"
|
|
|
| +#include "ash/display/display_controller.h"
|
| +#include "ash/shell.h"
|
| +#include "base/logging.h"
|
| #include "chrome/browser/chromeos/ui/focus_ring_layer.h"
|
| +#include "ui/gfx/screen.h"
|
|
|
| namespace chromeos {
|
|
|
| @@ -13,7 +17,10 @@ namespace {
|
| // The number of pixels the focus ring is outset from the object it outlines,
|
| // which also determines the border radius of the rounded corners.
|
| // TODO(dmazzoni): take display resolution into account.
|
| -const int kAccessibilityFocusRingMargin = 16;
|
| +const int kAccessibilityFocusRingMargin = 7;
|
| +
|
| +// Time to transition between one location and the next.
|
| +const int kTransitionTimeMilliseconds = 300;
|
|
|
| // A Region is an unordered collection of Rects that maintains its
|
| // bounding box. Used in the middle of an algorithm that groups
|
| @@ -35,7 +42,8 @@ AccessibilityFocusRingController*
|
| return Singleton<AccessibilityFocusRingController>::get();
|
| }
|
|
|
| -AccessibilityFocusRingController::AccessibilityFocusRingController() {
|
| +AccessibilityFocusRingController::AccessibilityFocusRingController()
|
| + : compositor_(NULL) {
|
| }
|
|
|
| AccessibilityFocusRingController::~AccessibilityFocusRingController() {
|
| @@ -48,22 +56,57 @@ void AccessibilityFocusRingController::SetFocusRing(
|
| }
|
|
|
| void AccessibilityFocusRingController::Update() {
|
| + previous_rings_.swap(rings_);
|
| rings_.clear();
|
| RectsToRings(rects_, &rings_);
|
| + layers_.resize(rings_.size());
|
| + for (size_t i = 0; i < rings_.size(); ++i) {
|
| + if (!layers_[i])
|
| + layers_[i].reset(new AccessibilityFocusRingLayer(this));
|
| +
|
| + if (i > 0) {
|
| + // Focus rings other than the first one don't animate.
|
| + layers_[i]->Set(rings_[i]);
|
| + continue;
|
| + }
|
|
|
| - if (!main_focus_ring_layer_)
|
| - main_focus_ring_layer_.reset(new AccessibilityFocusRingLayer(this));
|
| + gfx::Rect bounds = rings_[0].GetBounds();
|
| + gfx::Display display =
|
| + gfx::Screen::GetNativeScreen()->GetDisplayMatching(bounds);
|
| + aura::Window* root_window = ash::Shell::GetInstance()->display_controller()
|
| + ->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_ = NULL;
|
| + }
|
| + continue;
|
| + }
|
|
|
| - if (!rings_.empty())
|
| - main_focus_ring_layer_->Set(rings_[0]);
|
| + focus_change_time_ = base::TimeTicks::Now();
|
| + if (!compositor->HasAnimationObserver(this)) {
|
| + compositor_ = compositor;
|
| + compositor_->AddAnimationObserver(this);
|
| + }
|
| + }
|
| }
|
|
|
| void AccessibilityFocusRingController::RectsToRings(
|
| - const std::vector<gfx::Rect>& rects,
|
| + const std::vector<gfx::Rect>& src_rects,
|
| std::vector<AccessibilityFocusRing>* rings) const {
|
| - if (rects.empty())
|
| + if (src_rects.empty())
|
| return;
|
|
|
| + // Give all of the rects a margin.
|
| + std::vector<gfx::Rect> rects;
|
| + rects.resize(src_rects.size());
|
| + for (size_t i = 0; i < src_rects.size(); ++i) {
|
| + rects[i] = src_rects[i];
|
| + rects[i].Inset(-GetMargin(), -GetMargin());
|
| + }
|
| +
|
| // Split the rects into contiguous regions.
|
| std::vector<Region> regions;
|
| regions.push_back(Region(rects[0]));
|
| @@ -244,4 +287,33 @@ void AccessibilityFocusRingController::OnDeviceScaleFactorChanged() {
|
| Update();
|
| }
|
|
|
| +void AccessibilityFocusRingController::OnAnimationStep(
|
| + base::TimeTicks timestamp) {
|
| + if (rings_.empty())
|
| + return;
|
| +
|
| + CHECK(compositor_);
|
| + CHECK(!rings_.empty());
|
| + CHECK(!layers_.empty());
|
| + CHECK(layers_[0]);
|
| +
|
| + base::TimeDelta delta = timestamp - focus_change_time_;
|
| + base::TimeDelta transition_time =
|
| + base::TimeDelta::FromMilliseconds(kTransitionTimeMilliseconds);
|
| + if (delta >= transition_time) {
|
| + layers_[0]->Set(rings_[0]);
|
| + compositor_->RemoveAnimationObserver(this);
|
| + compositor_ = NULL;
|
| + return;
|
| + }
|
| +
|
| + double fraction = delta.InSecondsF() / transition_time.InSecondsF();
|
| +
|
| + // Ease-in effect.
|
| + fraction = pow(fraction, 0.3);
|
| +
|
| + layers_[0]->Set(AccessibilityFocusRing::Interpolate(
|
| + previous_rings_[0], rings_[0], fraction));
|
| +}
|
| +
|
| } // namespace chromeos
|
|
|