1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/ui/accessibility_focus_ring_layer.h"
#include "ash/display/window_tree_host_manager.h"
#include "ash/shell.h"
#include "base/bind.h"
#include "third_party/skia/include/core/SkPaint.h"
#include "third_party/skia/include/core/SkPath.h"
#include "ui/aura/window.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/paint_recorder.h"
#include "ui/gfx/canvas.h"
namespace chromeos {
namespace {
// The number of pixels in the color gradient that fades to transparent.
const int kGradientWidth = 6;
// The color of the focus ring. In the future this might be a parameter.
const int kFocusRingColorRed = 247;
const int kFocusRingColorGreen = 152;
const int kFocusRingColorBlue = 58;
int sign(int x) {
return ((x > 0) ? 1 : (x == 0) ? 0 : -1);
}
SkPath MakePath(const AccessibilityFocusRing& input_ring,
int outset,
const gfx::Vector2d& offset) {
AccessibilityFocusRing ring = input_ring;
for (int i = 0; i < 36; i++) {
gfx::Point p = input_ring.points[i];
gfx::Point prev;
gfx::Point next;
int prev_index = i;
do {
prev_index = (prev_index + 35) % 36;
prev = input_ring.points[prev_index];
} while (prev.x() == p.x() && prev.y() == p.y() && prev_index != i);
int next_index = i;
do {
next_index = (next_index + 1) % 36;
next = input_ring.points[next_index];
} while (next.x() == p.x() && next.y() == p.y() && next_index != i);
gfx::Point delta0 = gfx::Point(sign(p.x() - prev.x()),
sign(p.y() - prev.y()));
gfx::Point delta1 = gfx::Point(sign(next.x() - p.x()),
sign(next.y() - p.y()));
if (delta0.x() == delta1.x() && delta0.y() == delta1.y()) {
ring.points[i] = gfx::Point(
input_ring.points[i].x() + outset * delta0.y(),
input_ring.points[i].y() - outset * delta0.x());
} else {
ring.points[i] = gfx::Point(
input_ring.points[i].x() + ((i + 13) % 36 >= 18 ? outset : -outset),
input_ring.points[i].y() + ((i + 4) % 36 >= 18 ? outset : -outset));
}
}
SkPath path;
gfx::Point p0 = ring.points[0] - offset;
path.moveTo(SkIntToScalar(p0.x()), SkIntToScalar(p0.y()));
for (int i = 0; i < 12; i++) {
int index0 = ((3 * i) + 1) % 36;
int index1 = ((3 * i) + 2) % 36;
int index2 = ((3 * i) + 3) % 36;
gfx::Point p0 = ring.points[index0] - offset;
gfx::Point p1 = ring.points[index1] - offset;
gfx::Point p2 = ring.points[index2] - offset;
path.lineTo(SkIntToScalar(p0.x()), SkIntToScalar(p0.y()));
path.quadTo(SkIntToScalar(p1.x()), SkIntToScalar(p1.y()),
SkIntToScalar(p2.x()), SkIntToScalar(p2.y()));
}
return path;
}
} // namespace
AccessibilityFocusRingLayer::AccessibilityFocusRingLayer(
FocusRingLayerDelegate* delegate)
: FocusRingLayer(delegate) {
}
AccessibilityFocusRingLayer::~AccessibilityFocusRingLayer() {}
void AccessibilityFocusRingLayer::Set(const AccessibilityFocusRing& ring) {
ring_ = ring;
gfx::Rect bounds = ring.GetBounds();
int inset = kGradientWidth;
bounds.Inset(-inset, -inset, -inset, -inset);
gfx::Display display =
gfx::Screen::GetNativeScreen()->GetDisplayMatching(bounds);
aura::Window* root_window = ash::Shell::GetInstance()
->window_tree_host_manager()
->GetRootWindowForDisplayId(display.id());
CreateOrUpdateLayer(root_window, "AccessibilityFocusRing");
// Update the layer bounds.
layer()->SetBounds(bounds);
}
void AccessibilityFocusRingLayer::OnPaintLayer(
const ui::PaintContext& context) {
ui::PaintRecorder recorder(context, layer()->size());
SkPaint paint;
paint.setFlags(SkPaint::kAntiAlias_Flag);
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(2);
SkPath path;
gfx::Vector2d offset = layer()->bounds().OffsetFromOrigin();
const int w = kGradientWidth;
for (int i = 0; i < w; ++i) {
paint.setColor(
SkColorSetARGBMacro(
255 * (w - i) * (w - i) / (w * w),
kFocusRingColorRed, kFocusRingColorGreen, kFocusRingColorBlue));
path = MakePath(ring_, i, offset);
recorder.canvas()->DrawPath(path, paint);
}
}
} // namespace chromeos
|