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

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: Move initialization to header, fix compile error 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_animation_info_.fade_in_time =
67 base::TimeDelta::FromMilliseconds(kFocusFadeInTimeMilliseconds);
68 focus_animation_info_.fade_out_time =
69 base::TimeDelta::FromMilliseconds(kFocusFadeOutTimeMilliseconds);
70 cursor_animation_info_.fade_in_time =
71 base::TimeDelta::FromMilliseconds(kCursorFadeInTimeMilliseconds);
72 cursor_animation_info_.fade_out_time =
73 base::TimeDelta::FromMilliseconds(kCursorFadeOutTimeMilliseconds);
74 caret_animation_info_.fade_in_time =
75 base::TimeDelta::FromMilliseconds(kCaretFadeInTimeMilliseconds);
76 caret_animation_info_.fade_out_time =
77 base::TimeDelta::FromMilliseconds(kCaretFadeOutTimeMilliseconds);
78 }
62 79
63 AccessibilityFocusRingController::~AccessibilityFocusRingController() { 80 AccessibilityFocusRingController::~AccessibilityFocusRingController() {
64 } 81 }
65 82
66 void AccessibilityFocusRingController::SetFocusRing( 83 void AccessibilityFocusRingController::SetFocusRing(
67 const std::vector<gfx::Rect>& rects) { 84 const std::vector<gfx::Rect>& rects,
68 rects_ = rects; 85 AccessibilityFocusRingController::FocusRingBehavior focus_ring_behavior) {
69 Update(); 86 focus_ring_behavior_ = focus_ring_behavior;
87 OnLayerChange(&focus_animation_info_);
88 focus_rects_ = rects;
89 UpdateFocusRingsFromFocusRects();
70 } 90 }
71 91
72 void AccessibilityFocusRingController::Update() { 92 void AccessibilityFocusRingController::UpdateFocusRingsFromFocusRects() {
73 previous_rings_.swap(rings_); 93 previous_focus_rings_.swap(focus_rings_);
74 rings_.clear(); 94 focus_rings_.clear();
75 RectsToRings(rects_, &rings_); 95 RectsToRings(focus_rects_, &focus_rings_);
76 layers_.resize(rings_.size()); 96 focus_layers_.resize(focus_rings_.size());
77 if (rings_.empty()) 97 if (focus_rings_.empty())
78 return; 98 return;
79 99
80 for (size_t i = 0; i < rings_.size(); ++i) { 100 for (size_t i = 0; i < focus_rings_.size(); ++i) {
81 if (!layers_[i]) 101 if (!focus_layers_[i])
82 layers_[i] = new AccessibilityFocusRingLayer(this); 102 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 } 103 }
89 104
90 if (layers_[0]->CanAnimate()) { 105 if (focus_ring_behavior_ == PERSIST_FOCUS_RING &&
91 focus_change_time_ = base::TimeTicks::Now(); 106 focus_layers_[0]->CanAnimate()) {
107 // In PERSIST mode, animate the first ring to its destination
108 // location, then set the rest of the rings directly.
109 for (size_t i = 1; i < focus_rings_.size(); ++i)
110 focus_layers_[i]->Set(focus_rings_[i]);
92 } else { 111 } else {
93 // If we can't animate, set the location of the first ring. 112 // In FADE mode, set all focus rings to their destination location.
94 layers_[0]->Set(rings_[0]); 113 for (size_t i = 0; i < focus_rings_.size(); ++i)
114 focus_layers_[i]->Set(focus_rings_[i]);
95 } 115 }
96 } 116 }
97 117
118 void AccessibilityFocusRingController::OnLayerChange(
119 AccessibilityFocusRingController::LayerAnimationInfo* animation_info) {
120 animation_info->change_time = base::TimeTicks::Now();
121 if (animation_info->opacity == 0)
122 animation_info->start_time = animation_info->change_time;
123 }
124
98 void AccessibilityFocusRingController::SetCursorRing( 125 void AccessibilityFocusRingController::SetCursorRing(
99 const gfx::Point& location) { 126 const gfx::Point& location) {
100 cursor_location_ = location; 127 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_) { 128 if (!cursor_layer_) {
106 cursor_layer_.reset(new AccessibilityCursorRingLayer( 129 cursor_layer_.reset(new AccessibilityCursorRingLayer(
107 this, kCursorRingColorRed, kCursorRingColorGreen, 130 this, kCursorRingColorRed, kCursorRingColorGreen,
108 kCursorRingColorBlue)); 131 kCursorRingColorBlue));
109 } 132 }
110 cursor_layer_->Set(location); 133 cursor_layer_->Set(location);
134 OnLayerChange(&cursor_animation_info_);
111 } 135 }
112 136
113 void AccessibilityFocusRingController::SetCaretRing( 137 void AccessibilityFocusRingController::SetCaretRing(
114 const gfx::Point& location) { 138 const gfx::Point& location) {
115 caret_location_ = location; 139 caret_location_ = location;
116 140
117 if (!caret_layer_) { 141 if (!caret_layer_) {
118 caret_layer_.reset(new AccessibilityCursorRingLayer( 142 caret_layer_.reset(new AccessibilityCursorRingLayer(
119 this, kCaretRingColorRed, kCaretRingColorGreen, kCaretRingColorBlue)); 143 this, kCaretRingColorRed, kCaretRingColorGreen, kCaretRingColorBlue));
120 } 144 }
121 145
122 caret_layer_->Set(location); 146 caret_layer_->Set(location);
147 OnLayerChange(&caret_animation_info_);
123 } 148 }
124 149
125 void AccessibilityFocusRingController::RectsToRings( 150 void AccessibilityFocusRingController::RectsToRings(
126 const std::vector<gfx::Rect>& src_rects, 151 const std::vector<gfx::Rect>& src_rects,
127 std::vector<AccessibilityFocusRing>* rings) const { 152 std::vector<AccessibilityFocusRing>* rings) const {
128 if (src_rects.empty()) 153 if (src_rects.empty())
129 return; 154 return;
130 155
131 // Give all of the rects a margin. 156 // Give all of the rects a margin.
132 std::vector<gfx::Rect> rects; 157 std::vector<gfx::Rect> rects;
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
306 bool AccessibilityFocusRingController::Intersects( 331 bool AccessibilityFocusRingController::Intersects(
307 const gfx::Rect& r1, const gfx::Rect& r2) const { 332 const gfx::Rect& r1, const gfx::Rect& r2) const {
308 int slop = GetMargin(); 333 int slop = GetMargin();
309 return (r2.x() <= r1.right() + slop && 334 return (r2.x() <= r1.right() + slop &&
310 r2.right() >= r1.x() - slop && 335 r2.right() >= r1.x() - slop &&
311 r2.y() <= r1.bottom() + slop && 336 r2.y() <= r1.bottom() + slop &&
312 r2.bottom() >= r1.y() - slop); 337 r2.bottom() >= r1.y() - slop);
313 } 338 }
314 339
315 void AccessibilityFocusRingController::OnDeviceScaleFactorChanged() { 340 void AccessibilityFocusRingController::OnDeviceScaleFactorChanged() {
316 Update(); 341 UpdateFocusRingsFromFocusRects();
317 } 342 }
318 343
319 void AccessibilityFocusRingController::OnAnimationStep( 344 void AccessibilityFocusRingController::OnAnimationStep(
320 base::TimeTicks timestamp) { 345 base::TimeTicks timestamp) {
321 if (!rings_.empty() && layers_[0]->CanAnimate()) 346 if (!focus_rings_.empty() && focus_layers_[0]->CanAnimate())
322 AnimateFocusRings(timestamp); 347 AnimateFocusRings(timestamp);
323 348
324 if (cursor_layer_ && cursor_layer_->CanAnimate()) 349 if (cursor_layer_ && cursor_layer_->CanAnimate())
325 AnimateCursorRing(timestamp); 350 AnimateCursorRing(timestamp);
351
352 if (caret_layer_ && caret_layer_->CanAnimate())
353 AnimateCaretRing(timestamp);
326 } 354 }
327 355
328 void AccessibilityFocusRingController::AnimateFocusRings( 356 void AccessibilityFocusRingController::AnimateFocusRings(
329 base::TimeTicks timestamp) { 357 base::TimeTicks timestamp) {
330 CHECK(!rings_.empty()); 358 CHECK(!focus_rings_.empty());
331 CHECK(!layers_.empty()); 359 CHECK(!focus_layers_.empty());
332 CHECK(layers_[0]); 360 CHECK(focus_layers_[0]);
333 361
334 // It's quite possible for the first 1 or 2 animation frames to be 362 // 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 363 // 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. 364 // focus change, so we just treat those as a delta of zero.
337 if (timestamp < focus_change_time_) 365 if (timestamp < focus_animation_info_.change_time)
338 timestamp = focus_change_time_; 366 timestamp = focus_animation_info_.change_time;
339 367
340 base::TimeDelta delta = timestamp - focus_change_time_; 368 if (focus_ring_behavior_ == PERSIST_FOCUS_RING) {
341 base::TimeDelta transition_time = 369 base::TimeDelta delta = timestamp - focus_animation_info_.change_time;
342 base::TimeDelta::FromMilliseconds(kTransitionTimeMilliseconds); 370 base::TimeDelta transition_time =
343 if (delta >= transition_time) { 371 base::TimeDelta::FromMilliseconds(kTransitionTimeMilliseconds);
344 layers_[0]->Set(rings_[0]); 372 if (delta >= transition_time) {
373 focus_layers_[0]->Set(focus_rings_[0]);
374 return;
375 }
376
377 double fraction = delta.InSecondsF() / transition_time.InSecondsF();
378
379 // Ease-in effect.
380 fraction = pow(fraction, 0.3);
381
382 // Handle corner case where we're animating but we don't have previous
383 // rings.
384 if (previous_focus_rings_.empty())
385 previous_focus_rings_ = focus_rings_;
386
387 focus_layers_[0]->Set(AccessibilityFocusRing::Interpolate(
388 previous_focus_rings_[0], focus_rings_[0], fraction));
389 } else {
390 ComputeOpacity(&focus_animation_info_, timestamp);
391 for (size_t i = 0; i < focus_layers_.size(); ++i)
392 focus_layers_[i]->SetOpacity(focus_animation_info_.opacity);
393 }
394 }
395
396 void AccessibilityFocusRingController::ComputeOpacity(
397 AccessibilityFocusRingController::LayerAnimationInfo* animation_info,
398 base::TimeTicks timestamp) {
399 // It's quite possible for the first 1 or 2 animation frames to be
400 // for a timestamp that's earlier than the time we received the
401 // mouse movement, so we just treat those as a delta of zero.
402 if (timestamp < animation_info->start_time)
403 timestamp = animation_info->start_time;
404
405 base::TimeDelta start_delta = timestamp - animation_info->start_time;
406 base::TimeDelta change_delta = timestamp - animation_info->change_time;
407 base::TimeDelta fade_in_time = animation_info->fade_in_time;
408 base::TimeDelta fade_out_time = animation_info->fade_out_time;
409
410 if (change_delta > fade_in_time + fade_out_time) {
411 animation_info->opacity = 0.0;
345 return; 412 return;
346 } 413 }
347 414
348 double fraction = delta.InSecondsF() / transition_time.InSecondsF(); 415 float opacity;
416 if (start_delta < fade_in_time) {
417 opacity = start_delta.InSecondsF() / fade_in_time.InSecondsF();
418 if (opacity > 1.0)
419 opacity = 1.0;
420 } else {
421 opacity = 1.0 - (change_delta.InSecondsF() /
422 (fade_in_time + fade_out_time).InSecondsF());
423 if (opacity < 0.0)
424 opacity = 0.0;
425 }
349 426
350 // Ease-in effect. 427 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 } 428 }
361 429
362 void AccessibilityFocusRingController::AnimateCursorRing( 430 void AccessibilityFocusRingController::AnimateCursorRing(
363 base::TimeTicks timestamp) { 431 base::TimeTicks timestamp) {
364 CHECK(cursor_layer_); 432 CHECK(cursor_layer_);
365 433
366 // It's quite possible for the first 1 or 2 animation frames to be 434 ComputeOpacity(&cursor_animation_info_, timestamp);
367 // for a timestamp that's earlier than the time we received the 435 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(); 436 cursor_layer_.reset();
382 return; 437 return;
383 } 438 }
439 cursor_layer_->SetOpacity(cursor_animation_info_.opacity);
440 }
384 441
385 if (start_delta < fade_in_time) { 442 void AccessibilityFocusRingController::AnimateCaretRing(
386 cursor_opacity_ = start_delta.InSecondsF() / fade_in_time.InSecondsF(); 443 base::TimeTicks timestamp) {
387 if (cursor_opacity_ > 1.0) 444 CHECK(caret_layer_);
388 cursor_opacity_ = 1.0; 445
389 } else { 446 ComputeOpacity(&caret_animation_info_, timestamp);
390 cursor_opacity_ = 1.0 - (change_delta.InSecondsF() / 447 if (caret_animation_info_.opacity == 0.0) {
391 (fade_in_time + fade_out_time).InSecondsF()); 448 caret_layer_.reset();
392 if (cursor_opacity_ < 0.0) 449 return;
393 cursor_opacity_ = 0.0;
394 } 450 }
395 cursor_layer_->SetOpacity(cursor_opacity_); 451 caret_layer_->SetOpacity(caret_animation_info_.opacity);
396 } 452 }
397 453
398 } // namespace chromeos 454 } // 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