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