Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/chromeos/ui/accessibility_focus_ring_controller.h" | 5 #include "chrome/browser/chromeos/ui/accessibility_focus_ring_controller.h" |
| 6 | 6 |
| 7 #include "ash/display/display_controller.h" | |
| 8 #include "ash/shell.h" | |
| 9 #include "base/logging.h" | |
| 7 #include "chrome/browser/chromeos/ui/focus_ring_layer.h" | 10 #include "chrome/browser/chromeos/ui/focus_ring_layer.h" |
| 11 #include "ui/gfx/screen.h" | |
| 8 | 12 |
| 9 namespace chromeos { | 13 namespace chromeos { |
| 10 | 14 |
| 11 namespace { | 15 namespace { |
| 12 | 16 |
| 13 // The number of pixels the focus ring is outset from the object it outlines, | 17 // The number of pixels the focus ring is outset from the object it outlines, |
| 14 // which also determines the border radius of the rounded corners. | 18 // which also determines the border radius of the rounded corners. |
| 15 // TODO(dmazzoni): take display resolution into account. | 19 // TODO(dmazzoni): take display resolution into account. |
| 16 const int kAccessibilityFocusRingMargin = 16; | 20 const int kAccessibilityFocusRingMargin = 7; |
| 21 | |
| 22 // Time to transition between one location and the next. | |
| 23 const int kTransitionTimeMilliseconds = 300; | |
| 17 | 24 |
| 18 // A Region is an unordered collection of Rects that maintains its | 25 // A Region is an unordered collection of Rects that maintains its |
| 19 // bounding box. Used in the middle of an algorithm that groups | 26 // bounding box. Used in the middle of an algorithm that groups |
| 20 // adjacent and overlapping rects. | 27 // adjacent and overlapping rects. |
| 21 struct Region { | 28 struct Region { |
| 22 explicit Region(gfx::Rect initial_rect) { | 29 explicit Region(gfx::Rect initial_rect) { |
| 23 bounds = initial_rect; | 30 bounds = initial_rect; |
| 24 rects.push_back(initial_rect); | 31 rects.push_back(initial_rect); |
| 25 } | 32 } |
| 26 gfx::Rect bounds; | 33 gfx::Rect bounds; |
| 27 std::vector<gfx::Rect> rects; | 34 std::vector<gfx::Rect> rects; |
| 28 }; | 35 }; |
| 29 | 36 |
| 30 } // namespace | 37 } // namespace |
| 31 | 38 |
| 32 // static | 39 // static |
| 33 AccessibilityFocusRingController* | 40 AccessibilityFocusRingController* |
| 34 AccessibilityFocusRingController::GetInstance() { | 41 AccessibilityFocusRingController::GetInstance() { |
| 35 return Singleton<AccessibilityFocusRingController>::get(); | 42 return Singleton<AccessibilityFocusRingController>::get(); |
| 36 } | 43 } |
| 37 | 44 |
| 38 AccessibilityFocusRingController::AccessibilityFocusRingController() { | 45 AccessibilityFocusRingController::AccessibilityFocusRingController() |
| 46 : compositor_(NULL) { | |
| 39 } | 47 } |
| 40 | 48 |
| 41 AccessibilityFocusRingController::~AccessibilityFocusRingController() { | 49 AccessibilityFocusRingController::~AccessibilityFocusRingController() { |
| 42 } | 50 } |
| 43 | 51 |
| 44 void AccessibilityFocusRingController::SetFocusRing( | 52 void AccessibilityFocusRingController::SetFocusRing( |
| 45 const std::vector<gfx::Rect>& rects) { | 53 const std::vector<gfx::Rect>& rects) { |
| 46 rects_ = rects; | 54 rects_ = rects; |
| 47 Update(); | 55 Update(); |
| 48 } | 56 } |
| 49 | 57 |
| 50 void AccessibilityFocusRingController::Update() { | 58 void AccessibilityFocusRingController::Update() { |
| 59 previous_rings_.swap(rings_); | |
| 51 rings_.clear(); | 60 rings_.clear(); |
| 52 RectsToRings(rects_, &rings_); | 61 RectsToRings(rects_, &rings_); |
| 62 layers_.resize(rings_.size()); | |
| 63 for (size_t i = 0; i < rings_.size(); ++i) { | |
| 64 if (!layers_[i]) | |
| 65 layers_[i].reset(new AccessibilityFocusRingLayer(this)); | |
| 53 | 66 |
| 54 if (!main_focus_ring_layer_) | 67 if (i > 0) { |
| 55 main_focus_ring_layer_.reset(new AccessibilityFocusRingLayer(this)); | 68 // Focus rings other than the first one don't animate. |
| 69 layers_[i]->Set(rings_[i]); | |
| 70 continue; | |
| 71 } | |
| 56 | 72 |
| 57 if (!rings_.empty()) | 73 gfx::Rect bounds = rings_[0].GetBounds(); |
| 58 main_focus_ring_layer_->Set(rings_[0]); | 74 gfx::Display display = |
| 75 gfx::Screen::GetNativeScreen()->GetDisplayMatching(bounds); | |
| 76 aura::Window* root_window = ash::Shell::GetInstance()->display_controller() | |
| 77 ->GetRootWindowForDisplayId(display.id()); | |
| 78 ui::Compositor* compositor = root_window->layer()->GetCompositor(); | |
| 79 if (!compositor || root_window != layers_[0]->root_window()) { | |
| 80 layers_[0]->Set(rings_[0]); | |
| 81 if (compositor_ && compositor_->HasAnimationObserver(this)) { | |
| 82 compositor_->RemoveAnimationObserver(this); | |
| 83 compositor_ = NULL; | |
| 84 } | |
| 85 continue; | |
| 86 } | |
| 87 | |
| 88 focus_change_time_ = base::TimeTicks::Now(); | |
| 89 if (!compositor->HasAnimationObserver(this)) { | |
| 90 compositor_ = compositor; | |
| 91 compositor_->AddAnimationObserver(this); | |
| 92 } | |
| 93 } | |
| 59 } | 94 } |
| 60 | 95 |
| 61 void AccessibilityFocusRingController::RectsToRings( | 96 void AccessibilityFocusRingController::RectsToRings( |
| 62 const std::vector<gfx::Rect>& rects, | 97 const std::vector<gfx::Rect>& src_rects, |
| 63 std::vector<AccessibilityFocusRing>* rings) const { | 98 std::vector<AccessibilityFocusRing>* rings) const { |
| 64 if (rects.empty()) | 99 if (src_rects.empty()) |
| 65 return; | 100 return; |
| 66 | 101 |
| 102 // Give all of the rects a margin. | |
| 103 std::vector<gfx::Rect> rects; | |
| 104 rects.resize(src_rects.size()); | |
| 105 for (size_t i = 0; i < src_rects.size(); i++) { | |
|
xiyuan
2014/09/24 19:40:35
nit: ++i
dmazzoni
2014/09/24 21:40:56
Done.
| |
| 106 rects[i] = src_rects[i]; | |
| 107 rects[i].Inset(-kAccessibilityFocusRingMargin, | |
| 108 -kAccessibilityFocusRingMargin); | |
| 109 } | |
| 110 | |
| 67 // Split the rects into contiguous regions. | 111 // Split the rects into contiguous regions. |
| 68 std::vector<Region> regions; | 112 std::vector<Region> regions; |
| 69 regions.push_back(Region(rects[0])); | 113 regions.push_back(Region(rects[0])); |
| 70 for (size_t i = 1; i < rects.size(); ++i) { | 114 for (size_t i = 1; i < rects.size(); ++i) { |
| 71 bool found = false; | 115 bool found = false; |
| 72 for (size_t j = 0; j < regions.size(); ++j) { | 116 for (size_t j = 0; j < regions.size(); ++j) { |
| 73 if (Intersects(rects[i], regions[j].bounds)) { | 117 if (Intersects(rects[i], regions[j].bounds)) { |
| 74 regions[j].rects.push_back(rects[i]); | 118 regions[j].rects.push_back(rects[i]); |
| 75 regions[j].bounds.Union(rects[i]); | 119 regions[j].bounds.Union(rects[i]); |
| 76 found = true; | 120 found = true; |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 237 return (r2.x() <= r1.right() + slop && | 281 return (r2.x() <= r1.right() + slop && |
| 238 r2.right() >= r1.x() - slop && | 282 r2.right() >= r1.x() - slop && |
| 239 r2.y() <= r1.bottom() + slop && | 283 r2.y() <= r1.bottom() + slop && |
| 240 r2.bottom() >= r1.y() - slop); | 284 r2.bottom() >= r1.y() - slop); |
| 241 } | 285 } |
| 242 | 286 |
| 243 void AccessibilityFocusRingController::OnDeviceScaleFactorChanged() { | 287 void AccessibilityFocusRingController::OnDeviceScaleFactorChanged() { |
| 244 Update(); | 288 Update(); |
| 245 } | 289 } |
| 246 | 290 |
| 291 void AccessibilityFocusRingController::OnAnimationStep( | |
| 292 base::TimeTicks timestamp) { | |
| 293 CHECK(compositor_); | |
| 294 CHECK(!rings_.empty()); | |
| 295 CHECK(!layers_.empty()); | |
| 296 CHECK(layers_[0]); | |
| 297 | |
| 298 base::TimeDelta delta = timestamp - focus_change_time_; | |
| 299 base::TimeDelta transition_time = | |
| 300 base::TimeDelta::FromMilliseconds(kTransitionTimeMilliseconds); | |
| 301 if (delta >= transition_time) { | |
| 302 layers_[0]->Set(rings_[0]); | |
| 303 compositor_->RemoveAnimationObserver(this); | |
| 304 compositor_ = NULL; | |
| 305 return; | |
| 306 } | |
| 307 | |
| 308 double fraction = delta.InSecondsF() / transition_time.InSecondsF(); | |
| 309 | |
| 310 // Ease-in effect. | |
| 311 fraction = pow(fraction, 0.3); | |
| 312 | |
| 313 layers_[0]->Set(AccessibilityFocusRing::Interpolate( | |
| 314 previous_rings_[0], rings_[0], fraction)); | |
| 315 } | |
| 316 | |
| 247 } // namespace chromeos | 317 } // namespace chromeos |
| OLD | NEW |