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 14namespace chromeos { 15 16namespace { 17 18// The number of pixels in the color gradient that fades to transparent. 19const int kGradientWidth = 6; 20 21// The color of the focus ring. In the future this might be a parameter. 22const int kFocusRingColorRed = 247; 23const int kFocusRingColorGreen = 152; 24const int kFocusRingColorBlue = 58; 25 26int sign(int x) { 27 return ((x > 0) ? 1 : (x == 0) ? 0 : -1); 28} 29 30SkPath 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() && prev_index != i); 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() && next_index != i); 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 88AccessibilityFocusRingLayer::AccessibilityFocusRingLayer( 89 FocusRingLayerDelegate* delegate) 90 : FocusRingLayer(delegate) { 91} 92 93AccessibilityFocusRingLayer::~AccessibilityFocusRingLayer() {} 94 95void 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 // Update the layer bounds. 109 layer()->SetBounds(bounds); 110} 111 112void AccessibilityFocusRingLayer::OnPaintLayer(gfx::Canvas* canvas) { 113 gfx::Vector2d offset = layer()->bounds().OffsetFromOrigin(); 114 115 SkPaint paint; 116 paint.setFlags(SkPaint::kAntiAlias_Flag); 117 paint.setStyle(SkPaint::kStroke_Style); 118 paint.setStrokeWidth(2); 119 120 SkPath path; 121 const int w = kGradientWidth; 122 for (int i = 0; i < w; ++i) { 123 paint.setColor( 124 SkColorSetARGBMacro( 125 255 * (w - i) * (w - i) / (w * w), 126 kFocusRingColorRed, kFocusRingColorGreen, kFocusRingColorBlue)); 127 path = MakePath(ring_, i, offset); 128 canvas->DrawPath(path, paint); 129 } 130} 131 132} // namespace chromeos 133