• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/focus_ring_layer.h"
6 
7 #include "ash/system/tray/actionable_view.h"
8 #include "ash/system/tray/tray_background_view.h"
9 #include "ash/system/tray/tray_popup_header_button.h"
10 #include "base/bind.h"
11 #include "ui/aura/window.h"
12 #include "ui/compositor/layer.h"
13 #include "ui/gfx/canvas.h"
14 #include "ui/views/controls/button/label_button.h"
15 #include "ui/views/view.h"
16 #include "ui/views/widget/widget.h"
17 
18 namespace chromeos {
19 
20 namespace {
21 
22 const int kShadowRadius = 10;
23 const int kShadowAlpha = 90;
24 const SkColor kShadowColor = SkColorSetRGB(77, 144, 254);
25 
26 }  // namespace
27 
FocusRingLayer()28 FocusRingLayer::FocusRingLayer()
29     : window_(NULL),
30       root_window_(NULL) {
31 }
32 
~FocusRingLayer()33 FocusRingLayer::~FocusRingLayer() {}
34 
Update()35 void FocusRingLayer::Update() {
36   if (!window_)
37     return;
38 
39   aura::Window* root_window = window_->GetRootWindow();
40   if (!layer_ || root_window != root_window_) {
41     root_window_ = root_window;
42     ui::Layer* root_layer = root_window->layer();
43     layer_.reset(new ui::Layer(ui::LAYER_TEXTURED));
44     layer_->set_name("FocusRing");
45     layer_->set_delegate(this);
46     layer_->SetFillsBoundsOpaquely(false);
47     root_layer->Add(layer_.get());
48   }
49 
50   // Keep moving it to the top in case new layers have been added
51   // since we created this layer.
52   layer_->parent()->StackAtTop(layer_.get());
53 
54   // Translate native window coordinates to root window coordinates.
55   gfx::Point origin = focus_ring_.origin();
56   aura::Window::ConvertPointToTarget(window_, root_window_, &origin);
57   gfx::Rect layer_bounds = focus_ring_;
58   layer_bounds.set_origin(origin);
59   int inset = -(kShadowRadius + 2);
60   layer_bounds.Inset(inset, inset, inset, inset);
61   layer_->SetBounds(layer_bounds);
62 }
63 
SetForView(views::View * view)64 void FocusRingLayer::SetForView(views::View* view) {
65   if (!view) {
66     if (layer_ && !focus_ring_.IsEmpty())
67       layer_->SchedulePaint(focus_ring_);
68     focus_ring_ = gfx::Rect();
69     return;
70   }
71 
72   DCHECK(view->GetWidget());
73   window_ = view->GetWidget()->GetNativeWindow();
74 
75   gfx::Rect view_bounds = view->GetContentsBounds();
76 
77   // Workarounds that attempts to pick a better bounds.
78   if (view->GetClassName() == views::LabelButton::kViewClassName) {
79     view_bounds = view->GetLocalBounds();
80     view_bounds.Inset(2, 2, 2, 2);
81   }
82 
83   // Workarounds for system tray items that have customized focus borders.  The
84   // insets here must be consistent with the ones used by those classes.
85   if (view->GetClassName() ==
86       ash::internal::ActionableView::kViewClassName) {
87     view_bounds = view->GetLocalBounds();
88     view_bounds.Inset(1, 1, 3, 3);
89   } else if (view->GetClassName() ==
90              ash::internal::TrayBackgroundView::kViewClassName) {
91     view_bounds.Inset(1, 1, 3, 3);
92   } else if (view->GetClassName() ==
93              ash::internal::TrayPopupHeaderButton::kViewClassName) {
94     view_bounds = view->GetLocalBounds();
95     view_bounds.Inset(2, 1, 2, 2);
96   }
97 
98   focus_ring_ = view->ConvertRectToWidget(view_bounds);
99   Update();
100 }
101 
OnPaintLayer(gfx::Canvas * canvas)102 void FocusRingLayer::OnPaintLayer(gfx::Canvas* canvas) {
103   if (focus_ring_.IsEmpty())
104     return;
105 
106   // Convert the focus ring from native-window-relative coordinates to
107   // layer-relative coordinates.
108   gfx::Point origin = focus_ring_.origin();
109   aura::Window::ConvertPointToTarget(window_, root_window_, &origin);
110   origin -= layer_->bounds().OffsetFromOrigin();
111   gfx::Rect bounds = focus_ring_;
112   bounds.set_origin(origin);
113 
114   SkPaint paint;
115   paint.setColor(kShadowColor);
116   paint.setFlags(SkPaint::kAntiAlias_Flag);
117   paint.setStyle(SkPaint::kStroke_Style);
118   paint.setStrokeWidth(2);
119   int r = kShadowRadius;
120   for (int i = 0; i < r; i++) {
121     // Fade out alpha quadratically.
122     paint.setAlpha((kShadowAlpha * (r - i) * (r - i)) / (r * r));
123     gfx::Rect outsetRect = bounds;
124     outsetRect.Inset(-i, -i, -i, -i);
125     canvas->DrawRect(outsetRect, paint);
126   }
127 }
128 
OnDeviceScaleFactorChanged(float device_scale_factor)129 void FocusRingLayer::OnDeviceScaleFactorChanged(float device_scale_factor) {
130   Update();
131 }
132 
PrepareForLayerBoundsChange()133 base::Closure FocusRingLayer::PrepareForLayerBoundsChange() {
134   return base::Bind(&base::DoNothing);
135 }
136 
137 }  // namespace chromeos
138