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