Index: chrome/browser/chromeos/ui/accessibility_focus_ring_layer.cc |
diff --git a/chrome/browser/chromeos/ui/accessibility_focus_ring_layer.cc b/chrome/browser/chromeos/ui/accessibility_focus_ring_layer.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b0fafba3c8bff7d5e13dce6eab7fa91ca6bcc4e6 |
--- /dev/null |
+++ b/chrome/browser/chromeos/ui/accessibility_focus_ring_layer.cc |
@@ -0,0 +1,138 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "chrome/browser/chromeos/ui/accessibility_focus_ring_layer.h" |
+ |
+#include "ash/shell.h" |
+#include "base/bind.h" |
+#include "ui/aura/window.h" |
+#include "ui/compositor/layer.h" |
+#include "ui/gfx/canvas.h" |
+ |
+namespace chromeos { |
+ |
+namespace { |
+ |
+// The number of pixels in the color gradient that fades to transparent. |
+const int kGradientWidth = 10; |
+ |
+// The color of the focus ring. In the future this might be a parameter. |
+const int kFocusRingColorRed = 247; |
+const int kFocusRingColorGreen = 152; |
+const int kFocusRingColorBlue = 58; |
+ |
+int sign(int x) { |
+ return ((x > 0) ? 1 : (x == 0) ? 0 : -1); |
+} |
+ |
+SkPath MakePath(const AccessibilityFocusRing& input_ring, |
+ int outset, |
+ const gfx::Vector2d& offset) { |
+ AccessibilityFocusRing ring = input_ring; |
+ |
+ for (int i = 0; i < 36; i++) { |
+ gfx::Point p = input_ring.points[i]; |
+ gfx::Point prev; |
+ gfx::Point next; |
+ |
+ int prev_index = i; |
+ do { |
+ prev_index = (prev_index + 35) % 36; |
+ prev = input_ring.points[prev_index]; |
+ } while (prev.x() == p.x() && prev.y() == p.y()); |
+ |
+ int next_index = i; |
+ do { |
+ next_index = (next_index + 1) % 36; |
+ next = input_ring.points[next_index]; |
+ } while (next.x() == p.x() && next.y() == p.y()); |
+ |
+ gfx::Point delta0 = gfx::Point(sign(p.x() - prev.x()), |
+ sign(p.y() - prev.y())); |
+ gfx::Point delta1 = gfx::Point(sign(next.x() - p.x()), |
+ sign(next.y() - p.y())); |
+ |
+ if (delta0.x() == delta1.x() && delta0.y() == delta1.y()) { |
+ ring.points[i] = gfx::Point( |
+ input_ring.points[i].x() + outset * delta0.y(), |
+ input_ring.points[i].y() - outset * delta0.x()); |
+ } else { |
+ ring.points[i] = gfx::Point( |
+ input_ring.points[i].x() + ((i + 13) % 36 >= 18 ? outset : -outset), |
+ input_ring.points[i].y() + ((i + 4) % 36 >= 18 ? outset : -outset)); |
+ } |
+ } |
+ |
+ SkPath path; |
+ gfx::Point p0 = ring.points[0] - offset; |
+ path.moveTo(SkIntToScalar(p0.x()), SkIntToScalar(p0.y())); |
+ for (int i = 0; i < 12; i++) { |
+ int index0 = ((3 * i) + 1) % 36; |
+ int index1 = ((3 * i) + 2) % 36; |
+ int index2 = ((3 * i) + 3) % 36; |
+ gfx::Point p0 = ring.points[index0] - offset; |
+ gfx::Point p1 = ring.points[index1] - offset; |
+ gfx::Point p2 = ring.points[index2] - offset; |
+ path.lineTo(SkIntToScalar(p0.x()), SkIntToScalar(p0.y())); |
+ path.quadTo(SkIntToScalar(p1.x()), SkIntToScalar(p1.y()), |
+ SkIntToScalar(p2.x()), SkIntToScalar(p2.y())); |
+ } |
+ |
+ return path; |
+} |
+ |
+} // namespace |
+ |
+AccessibilityFocusRingLayer::AccessibilityFocusRingLayer( |
+ FocusRingLayerDelegate* delegate) |
+ : FocusRingLayer(delegate) { |
+} |
+ |
+AccessibilityFocusRingLayer::~AccessibilityFocusRingLayer() {} |
+ |
+void AccessibilityFocusRingLayer::Set(const AccessibilityFocusRing& ring) { |
+ ring_ = ring; |
+ |
+ gfx::Rect bounds = ring.GetBounds(); |
+ int inset = kGradientWidth; |
+ bounds.Inset(-inset, -inset, -inset, -inset); |
+ |
+ if (!layer_) { |
+ 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
|
+ ui::Layer* root_layer = root_window->layer(); |
+ layer_.reset(new ui::Layer(ui::LAYER_TEXTURED)); |
+ layer_->set_name("AccessibilityFocusRing"); |
+ layer_->set_delegate(this); |
+ layer_->SetFillsBoundsOpaquely(false); |
+ root_layer->Add(layer_.get()); |
+ } |
+ |
+ // Keep moving it to the top in case new layers have been added |
+ // since we created this layer. |
+ layer_->parent()->StackAtTop(layer_.get()); |
+ |
+ // Update the layer bounds. |
+ layer_->SetBounds(bounds); |
+} |
+ |
+void AccessibilityFocusRingLayer::OnPaintLayer(gfx::Canvas* canvas) { |
+ gfx::Vector2d offset = layer_->bounds().OffsetFromOrigin(); |
+ |
+ SkPaint paint; |
+ paint.setFlags(SkPaint::kAntiAlias_Flag); |
+ paint.setStyle(SkPaint::kStroke_Style); |
+ paint.setStrokeWidth(2); |
+ |
+ SkPath path; |
+ for (int i = 0; i < kGradientWidth; i++) { |
+ paint.setColor( |
+ SkColorSetARGBMacro( |
+ 255 - (255 * i / kGradientWidth), |
+ kFocusRingColorRed, kFocusRingColorGreen, kFocusRingColorBlue)); |
+ path = MakePath(ring_, i, offset); |
+ canvas->DrawPath(path, paint); |
+ } |
+} |
+ |
+} // namespace chromeos |