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"
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"
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;
30 return ((x
> 0) ? 1 : (x
== 0) ? 0 : -1);
33 SkPath
MakePath(const AccessibilityFocusRing
& input_ring
,
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
];
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
);
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());
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
));
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()));
91 AccessibilityFocusRingLayer::AccessibilityFocusRingLayer(
92 FocusRingLayerDelegate
* delegate
)
93 : FocusRingLayer(delegate
) {
96 AccessibilityFocusRingLayer::~AccessibilityFocusRingLayer() {}
98 void AccessibilityFocusRingLayer::Set(const AccessibilityFocusRing
& 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());
121 paint
.setFlags(SkPaint::kAntiAlias_Flag
);
122 paint
.setStyle(SkPaint::kStroke_Style
);
123 paint
.setStrokeWidth(2);
126 gfx::Vector2d offset
= layer()->bounds().OffsetFromOrigin();
127 const int w
= kGradientWidth
;
128 for (int i
= 0; i
< w
; ++i
) {
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