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

Side by Side Diff: chrome/browser/chromeos/ui/accessibility_focus_ring_controller.cc

Issue 2046563009: Make the focus, caret, and cursor highlights fade out. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 6 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 unified diff | Download patch
OLDNEW
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 <stddef.h> 7 #include <stddef.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 10
11 #include "ash/shell.h" 11 #include "ash/shell.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "chrome/browser/chromeos/ui/focus_ring_layer.h" 13 #include "chrome/browser/chromeos/ui/focus_ring_layer.h"
14 14
15 namespace chromeos { 15 namespace chromeos {
16 16
17 namespace { 17 namespace {
18 18
19 // The number of pixels the focus ring is outset from the object it outlines, 19 // The number of pixels the focus ring is outset from the object it outlines,
20 // which also determines the border radius of the rounded corners. 20 // which also determines the border radius of the rounded corners.
21 // TODO(dmazzoni): take display resolution into account. 21 // TODO(dmazzoni): take display resolution into account.
22 const int kAccessibilityFocusRingMargin = 7; 22 const int kAccessibilityFocusRingMargin = 7;
23 23
24 // Time to transition between one location and the next. 24 // Time to transition between one location and the next.
25 const int kTransitionTimeMilliseconds = 300; 25 const int kTransitionTimeMilliseconds = 300;
26 26
27 // Focus constants.
28 const int kFocusFadeInTimeMilliseconds = 100;
29 const int kFocusFadeOutTimeMilliseconds = 1600;
30
31 // Cursor constants.
27 const int kCursorFadeInTimeMilliseconds = 400; 32 const int kCursorFadeInTimeMilliseconds = 400;
28 const int kCursorFadeOutTimeMilliseconds = 1200; 33 const int kCursorFadeOutTimeMilliseconds = 1200;
29
30 // The color of the cursor ring.
31 const int kCursorRingColorRed = 255; 34 const int kCursorRingColorRed = 255;
32 const int kCursorRingColorGreen = 51; 35 const int kCursorRingColorGreen = 51;
33 const int kCursorRingColorBlue = 51; 36 const int kCursorRingColorBlue = 51;
34 37
35 // The color of the caret ring. 38 // Caret constants.
39 const int kCaretFadeInTimeMilliseconds = 100;
40 const int kCaretFadeOutTimeMilliseconds = 1600;
36 const int kCaretRingColorRed = 51; 41 const int kCaretRingColorRed = 51;
37 const int kCaretRingColorGreen = 51; 42 const int kCaretRingColorGreen = 51;
38 const int kCaretRingColorBlue = 255; 43 const int kCaretRingColorBlue = 255;
39 44
40 // A Region is an unordered collection of Rects that maintains its 45 // A Region is an unordered collection of Rects that maintains its
41 // bounding box. Used in the middle of an algorithm that groups 46 // bounding box. Used in the middle of an algorithm that groups
42 // adjacent and overlapping rects. 47 // adjacent and overlapping rects.
43 struct Region { 48 struct Region {
44 explicit Region(gfx::Rect initial_rect) { 49 explicit Region(gfx::Rect initial_rect) {
45 bounds = initial_rect; 50 bounds = initial_rect;
46 rects.push_back(initial_rect); 51 rects.push_back(initial_rect);
47 } 52 }
48 gfx::Rect bounds; 53 gfx::Rect bounds;
49 std::vector<gfx::Rect> rects; 54 std::vector<gfx::Rect> rects;
50 }; 55 };
51 56
52 } // namespace 57 } // namespace
53 58
54 // static 59 // static
55 AccessibilityFocusRingController* 60 AccessibilityFocusRingController*
56 AccessibilityFocusRingController::GetInstance() { 61 AccessibilityFocusRingController::GetInstance() {
57 return base::Singleton<AccessibilityFocusRingController>::get(); 62 return base::Singleton<AccessibilityFocusRingController>::get();
58 } 63 }
59 64
60 AccessibilityFocusRingController::AccessibilityFocusRingController() 65 AccessibilityFocusRingController::AccessibilityFocusRingController()
61 : cursor_opacity_(0) {} 66 : focus_ring_behavior_(
67 AccessibilityFocusRingController::FADE_OUT_FOCUS_RING) {
xiyuan 2016/06/08 18:17:52 nit: initialize in header?
dmazzoni 2016/06/08 20:01:23 Done.
68 focus_animation_info_.fade_in_time =
69 base::TimeDelta::FromMilliseconds(kFocusFadeInTimeMilliseconds);
70 focus_animation_info_.fade_out_time =
71 base::TimeDelta::FromMilliseconds(kFocusFadeOutTimeMilliseconds);
72 cursor_animation_info_.fade_in_time =
73 base::TimeDelta::FromMilliseconds(kCursorFadeInTimeMilliseconds);
74 cursor_animation_info_.fade_out_time =
75 base::TimeDelta::FromMilliseconds(kCursorFadeOutTimeMilliseconds);
76 caret_animation_info_.fade_in_time =
77 base::TimeDelta::FromMilliseconds(kCaretFadeInTimeMilliseconds);
78 caret_animation_info_.fade_out_time =
79 base::TimeDelta::FromMilliseconds(kCaretFadeOutTimeMilliseconds);
80 }
62 81
63 AccessibilityFocusRingController::~AccessibilityFocusRingController() { 82 AccessibilityFocusRingController::~AccessibilityFocusRingController() {
64 } 83 }
65 84
66 void AccessibilityFocusRingController::SetFocusRing( 85 void AccessibilityFocusRingController::SetFocusRing(
67 const std::vector<gfx::Rect>& rects) { 86 const std::vector<gfx::Rect>& rects,
68 rects_ = rects; 87 AccessibilityFocusRingController::FocusRingBehavior focus_ring_behavior) {
69 Update(); 88 focus_ring_behavior_ = focus_ring_behavior;
89 OnLayerChange(&focus_animation_info_);
90 focus_rects_ = rects;
91 UpdateFocusRingsFromFocusRects();
70 } 92 }
71 93
72 void AccessibilityFocusRingController::Update() { 94 void AccessibilityFocusRingController::UpdateFocusRingsFromFocusRects() {
73 previous_rings_.swap(rings_); 95 previous_focus_rings_.swap(focus_rings_);
74 rings_.clear(); 96 focus_rings_.clear();
75 RectsToRings(rects_, &rings_); 97 RectsToRings(focus_rects_, &focus_rings_);
76 layers_.resize(rings_.size()); 98 focus_layers_.resize(focus_rings_.size());
77 if (rings_.empty()) 99 if (focus_rings_.empty())
78 return; 100 return;
79 101
80 for (size_t i = 0; i < rings_.size(); ++i) { 102 for (size_t i = 0; i < focus_rings_.size(); ++i) {
81 if (!layers_[i]) 103 if (!focus_layers_[i])
82 layers_[i] = new AccessibilityFocusRingLayer(this); 104 focus_layers_[i] = new AccessibilityFocusRingLayer(this);
83
84 if (i > 0) {
85 // Focus rings other than the first one don't animate.
86 layers_[i]->Set(rings_[i]);
87 }
88 } 105 }
89 106
90 if (layers_[0]->CanAnimate()) { 107 if (focus_ring_behavior_ == PERSIST_FOCUS_RING &&
91 focus_change_time_ = base::TimeTicks::Now(); 108 focus_layers_[0]->CanAnimate()) {
109 // In PERSIST mode, animate the first ring to its destination
110 // location, then set the rest of the rings directly.
111 for (size_t i = 1; i < focus_rings_.size(); ++i)
112 focus_layers_[i]->Set(focus_rings_[i]);
92 } else { 113 } else {
93 // If we can't animate, set the location of the first ring. 114 // In FADE mode, set all focus rings to their destination location.
94 layers_[0]->Set(rings_[0]); 115 for (size_t i = 0; i < focus_rings_.size(); ++i)
116 focus_layers_[i]->Set(focus_rings_[i]);
95 } 117 }
96 } 118 }
97 119
120 void AccessibilityFocusRingController::OnLayerChange(
121 AccessibilityFocusRingController::LayerAnimationInfo* animation_info) {
122 animation_info->change_time = base::TimeTicks::Now();
123 if (animation_info->opacity == 0)
124 animation_info->start_time = animation_info->change_time;
125 }
126
98 void AccessibilityFocusRingController::SetCursorRing( 127 void AccessibilityFocusRingController::SetCursorRing(
99 const gfx::Point& location) { 128 const gfx::Point& location) {
100 cursor_location_ = location; 129 cursor_location_ = location;
101 cursor_change_time_ = base::TimeTicks::Now();
102 if (cursor_opacity_ == 0)
103 cursor_start_time_ = cursor_change_time_;
104
105 if (!cursor_layer_) { 130 if (!cursor_layer_) {
106 cursor_layer_.reset(new AccessibilityCursorRingLayer( 131 cursor_layer_.reset(new AccessibilityCursorRingLayer(
107 this, kCursorRingColorRed, kCursorRingColorGreen, 132 this, kCursorRingColorRed, kCursorRingColorGreen,
108 kCursorRingColorBlue)); 133 kCursorRingColorBlue));
109 } 134 }
110 cursor_layer_->Set(location); 135 cursor_layer_->Set(location);
136 OnLayerChange(&cursor_animation_info_);
111 } 137 }
112 138
113 void AccessibilityFocusRingController::SetCaretRing( 139 void AccessibilityFocusRingController::SetCaretRing(
114 const gfx::Point& location) { 140 const gfx::Point& location) {
115 caret_location_ = location; 141 caret_location_ = location;
116 142
117 if (!caret_layer_) { 143 if (!caret_layer_) {
118 caret_layer_.reset(new AccessibilityCursorRingLayer( 144 caret_layer_.reset(new AccessibilityCursorRingLayer(
119 this, kCaretRingColorRed, kCaretRingColorGreen, kCaretRingColorBlue)); 145 this, kCaretRingColorRed, kCaretRingColorGreen, kCaretRingColorBlue));
120 } 146 }
121 147
122 caret_layer_->Set(location); 148 caret_layer_->Set(location);
149 OnLayerChange(&caret_animation_info_);
123 } 150 }
124 151
125 void AccessibilityFocusRingController::RectsToRings( 152 void AccessibilityFocusRingController::RectsToRings(
126 const std::vector<gfx::Rect>& src_rects, 153 const std::vector<gfx::Rect>& src_rects,
127 std::vector<AccessibilityFocusRing>* rings) const { 154 std::vector<AccessibilityFocusRing>* rings) const {
128 if (src_rects.empty()) 155 if (src_rects.empty())
129 return; 156 return;
130 157
131 // Give all of the rects a margin. 158 // Give all of the rects a margin.
132 std::vector<gfx::Rect> rects; 159 std::vector<gfx::Rect> rects;
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
306 bool AccessibilityFocusRingController::Intersects( 333 bool AccessibilityFocusRingController::Intersects(
307 const gfx::Rect& r1, const gfx::Rect& r2) const { 334 const gfx::Rect& r1, const gfx::Rect& r2) const {
308 int slop = GetMargin(); 335 int slop = GetMargin();
309 return (r2.x() <= r1.right() + slop && 336 return (r2.x() <= r1.right() + slop &&
310 r2.right() >= r1.x() - slop && 337 r2.right() >= r1.x() - slop &&
311 r2.y() <= r1.bottom() + slop && 338 r2.y() <= r1.bottom() + slop &&
312 r2.bottom() >= r1.y() - slop); 339 r2.bottom() >= r1.y() - slop);
313 } 340 }
314 341
315 void AccessibilityFocusRingController::OnDeviceScaleFactorChanged() { 342 void AccessibilityFocusRingController::OnDeviceScaleFactorChanged() {
316 Update(); 343 UpdateFocusRingsFromFocusRects();
317 } 344 }
318 345
319 void AccessibilityFocusRingController::OnAnimationStep( 346 void AccessibilityFocusRingController::OnAnimationStep(
320 base::TimeTicks timestamp) { 347 base::TimeTicks timestamp) {
321 if (!rings_.empty() && layers_[0]->CanAnimate()) 348 if (!focus_rings_.empty() && focus_layers_[0]->CanAnimate())
322 AnimateFocusRings(timestamp); 349 AnimateFocusRings(timestamp);
323 350
324 if (cursor_layer_ && cursor_layer_->CanAnimate()) 351 if (cursor_layer_ && cursor_layer_->CanAnimate())
325 AnimateCursorRing(timestamp); 352 AnimateCursorRing(timestamp);
353
354 if (caret_layer_ && caret_layer_->CanAnimate())
355 AnimateCaretRing(timestamp);
326 } 356 }
327 357
328 void AccessibilityFocusRingController::AnimateFocusRings( 358 void AccessibilityFocusRingController::AnimateFocusRings(
329 base::TimeTicks timestamp) { 359 base::TimeTicks timestamp) {
330 CHECK(!rings_.empty()); 360 CHECK(!focus_rings_.empty());
331 CHECK(!layers_.empty()); 361 CHECK(!focus_layers_.empty());
332 CHECK(layers_[0]); 362 CHECK(focus_layers_[0]);
333 363
334 // It's quite possible for the first 1 or 2 animation frames to be 364 // It's quite possible for the first 1 or 2 animation frames to be
335 // for a timestamp that's earlier than the time we received the 365 // for a timestamp that's earlier than the time we received the
336 // focus change, so we just treat those as a delta of zero. 366 // focus change, so we just treat those as a delta of zero.
337 if (timestamp < focus_change_time_) 367 if (timestamp < focus_animation_info_.change_time)
338 timestamp = focus_change_time_; 368 timestamp = focus_animation_info_.change_time;
339 369
340 base::TimeDelta delta = timestamp - focus_change_time_; 370 if (focus_ring_behavior_ == PERSIST_FOCUS_RING) {
341 base::TimeDelta transition_time = 371 base::TimeDelta delta = timestamp - focus_animation_info_.change_time;
342 base::TimeDelta::FromMilliseconds(kTransitionTimeMilliseconds); 372 base::TimeDelta transition_time =
343 if (delta >= transition_time) { 373 base::TimeDelta::FromMilliseconds(kTransitionTimeMilliseconds);
344 layers_[0]->Set(rings_[0]); 374 if (delta >= transition_time) {
375 focus_layers_[0]->Set(focus_rings_[0]);
376 return;
377 }
378
379 double fraction = delta.InSecondsF() / transition_time.InSecondsF();
380
381 // Ease-in effect.
382 fraction = pow(fraction, 0.3);
383
384 // Handle corner case where we're animating but we don't have previous
385 // rings.
386 if (previous_focus_rings_.empty())
387 previous_focus_rings_ = focus_rings_;
388
389 focus_layers_[0]->Set(AccessibilityFocusRing::Interpolate(
390 previous_focus_rings_[0], focus_rings_[0], fraction));
391 } else {
392 ComputeOpacity(&focus_animation_info_, timestamp);
393 for (size_t i = 0; i < focus_layers_.size(); ++i)
394 focus_layers_[i]->SetOpacity(focus_animation_info_.opacity);
395 }
396 }
397
398 void AccessibilityFocusRingController::ComputeOpacity(
399 AccessibilityFocusRingController::LayerAnimationInfo* animation_info,
400 base::TimeTicks timestamp) {
401 // It's quite possible for the first 1 or 2 animation frames to be
402 // for a timestamp that's earlier than the time we received the
403 // mouse movement, so we just treat those as a delta of zero.
404 if (timestamp < animation_info->start_time)
405 timestamp = animation_info->start_time;
406
407 base::TimeDelta start_delta = timestamp - animation_info->start_time;
408 base::TimeDelta change_delta = timestamp - animation_info->change_time;
409 base::TimeDelta fade_in_time = animation_info->fade_in_time;
410 base::TimeDelta fade_out_time = animation_info->fade_out_time;
411
412 if (change_delta > fade_in_time + fade_out_time) {
413 animation_info->opacity = 0.0;
345 return; 414 return;
346 } 415 }
347 416
348 double fraction = delta.InSecondsF() / transition_time.InSecondsF(); 417 float opacity;
418 if (start_delta < fade_in_time) {
419 opacity = start_delta.InSecondsF() / fade_in_time.InSecondsF();
420 if (opacity > 1.0)
421 opacity = 1.0;
422 } else {
423 opacity = 1.0 - (change_delta.InSecondsF() /
424 (fade_in_time + fade_out_time).InSecondsF());
425 if (opacity < 0.0)
426 opacity = 0.0;
427 }
349 428
350 // Ease-in effect. 429 animation_info->opacity = opacity;
351 fraction = pow(fraction, 0.3);
352
353 // Handle corner case where we're animating but we don't have previous
354 // rings.
355 if (previous_rings_.empty())
356 previous_rings_ = rings_;
357
358 layers_[0]->Set(AccessibilityFocusRing::Interpolate(
359 previous_rings_[0], rings_[0], fraction));
360 } 430 }
361 431
362 void AccessibilityFocusRingController::AnimateCursorRing( 432 void AccessibilityFocusRingController::AnimateCursorRing(
363 base::TimeTicks timestamp) { 433 base::TimeTicks timestamp) {
364 CHECK(cursor_layer_); 434 CHECK(cursor_layer_);
365 435
366 // It's quite possible for the first 1 or 2 animation frames to be 436 ComputeOpacity(&cursor_animation_info_, timestamp);
367 // for a timestamp that's earlier than the time we received the 437 if (cursor_animation_info_.opacity == 0.0) {
368 // mouse movement, so we just treat those as a delta of zero.
369 if (timestamp < cursor_start_time_)
370 timestamp = cursor_start_time_;
371
372 base::TimeDelta start_delta = timestamp - cursor_start_time_;
373 base::TimeDelta change_delta = timestamp - cursor_change_time_;
374 base::TimeDelta fade_in_time =
375 base::TimeDelta::FromMilliseconds(kCursorFadeInTimeMilliseconds);
376 base::TimeDelta fade_out_time =
377 base::TimeDelta::FromMilliseconds(kCursorFadeOutTimeMilliseconds);
378
379 if (change_delta > fade_in_time + fade_out_time) {
380 cursor_opacity_ = 0.0;
381 cursor_layer_.reset(); 438 cursor_layer_.reset();
382 return; 439 return;
383 } 440 }
441 cursor_layer_->SetOpacity(cursor_animation_info_.opacity);
442 }
384 443
385 if (start_delta < fade_in_time) { 444 void AccessibilityFocusRingController::AnimateCaretRing(
386 cursor_opacity_ = start_delta.InSecondsF() / fade_in_time.InSecondsF(); 445 base::TimeTicks timestamp) {
387 if (cursor_opacity_ > 1.0) 446 CHECK(caret_layer_);
388 cursor_opacity_ = 1.0; 447
389 } else { 448 ComputeOpacity(&caret_animation_info_, timestamp);
390 cursor_opacity_ = 1.0 - (change_delta.InSecondsF() / 449 if (caret_animation_info_.opacity == 0.0) {
391 (fade_in_time + fade_out_time).InSecondsF()); 450 caret_layer_.reset();
392 if (cursor_opacity_ < 0.0) 451 return;
393 cursor_opacity_ = 0.0;
394 } 452 }
395 cursor_layer_->SetOpacity(cursor_opacity_); 453 caret_layer_->SetOpacity(caret_animation_info_.opacity);
396 } 454 }
397 455
398 } // namespace chromeos 456 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/ui/accessibility_focus_ring_controller.h ('k') | chrome/browser/chromeos/ui/focus_ring_layer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698