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