OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/magnifier/partial_magnification_controller.h" | 5 #include "ash/magnifier/partial_magnification_controller.h" |
6 | 6 |
7 #include "ash/common/system/chromeos/palette/palette_utils.h" | 7 #include "ash/common/system/chromeos/palette/palette_utils.h" |
8 #include "ash/shell.h" | 8 #include "ash/shell.h" |
9 #include "third_party/skia/include/core/SkDrawLooper.h" | |
9 #include "ui/aura/window_event_dispatcher.h" | 10 #include "ui/aura/window_event_dispatcher.h" |
10 #include "ui/aura/window_tree_host.h" | 11 #include "ui/aura/window_tree_host.h" |
11 #include "ui/compositor/layer.h" | 12 #include "ui/compositor/layer.h" |
12 #include "ui/compositor/paint_recorder.h" | 13 #include "ui/compositor/paint_recorder.h" |
13 #include "ui/events/event.h" | 14 #include "ui/events/event.h" |
14 #include "ui/events/event_constants.h" | 15 #include "ui/events/event_constants.h" |
15 #include "ui/views/widget/widget.h" | 16 #include "ui/views/widget/widget.h" |
16 #include "ui/wm/core/coordinate_conversion.h" | 17 #include "ui/wm/core/coordinate_conversion.h" |
17 | 18 |
18 namespace ash { | 19 namespace ash { |
19 namespace { | 20 namespace { |
20 | 21 |
21 // Ratio of magnifier scale. | 22 // Ratio of magnifier scale. |
22 const float kMagnificationScale = 2.f; | 23 const float kMagnificationScale = 2.f; |
23 // Radius of the magnifying glass in DIP. | 24 // Radius of the magnifying glass in DIP. This does not include the thickness |
24 const int kMagnifierRadius = 200; | 25 // of the magnifying glass shadow and border. |
26 const int kMagnifierRadius = 188; | |
25 // Size of the border around the magnifying glass in DIP. | 27 // Size of the border around the magnifying glass in DIP. |
26 const int kBorderSize = 10; | 28 const int kBorderSize = 10; |
27 // Thickness of the outline around magnifying glass border in DIP. | 29 // Thickness of the outline around magnifying glass border in DIP. |
28 const int kBorderOutlineThickness = 2; | 30 const int kBorderOutlineThickness = 1; |
31 // Thickness of the shadow around the magnifying glass in DIP. | |
32 const int kShadowThickness = 24; | |
33 // Offset of the shadow around the magnifying glass in DIP. One of the shadows | |
34 // is lowered a bit, so we have to include |kShadowOffset| in our calculations | |
35 // to compensate. | |
36 const int kShadowOffset = 24; | |
29 // The color of the border and its outlines. The border has an outline on both | 37 // The color of the border and its outlines. The border has an outline on both |
30 // sides, producing a black/white/black ring. | 38 // sides, producing a black/white/black ring. |
31 const SkColor kBorderColor = SK_ColorWHITE; | 39 const SkColor kBorderColor = SkColorSetARGB(204, 255, 255, 255); |
32 const SkColor kBorderOutlineColor = SK_ColorBLACK; | 40 const SkColor kBorderOutlineColor = SkColorSetARGB(51, 0, 0, 0); |
41 // The colors of the two shadow around the magnifiying glass. | |
42 const SkColor kTopShadowColor = SkColorSetARGB(26, 0, 0, 0); | |
43 const SkColor kBottomShadowColor = SkColorSetARGB(61, 0, 0, 0); | |
33 // Inset on the zoom filter. | 44 // Inset on the zoom filter. |
34 const int kZoomInset = 0; | 45 const int kZoomInset = 0; |
35 // Vertical offset between the center of the magnifier and the tip of the | 46 // Vertical offset between the center of the magnifier and the tip of the |
36 // pointer. TODO(jdufault): The vertical offset should only apply to the window | 47 // pointer. TODO(jdufault): The vertical offset should only apply to the window |
37 // location, not the magnified contents. See crbug.com/637617. | 48 // location, not the magnified contents. See crbug.com/637617. |
38 const int kVerticalOffset = 0; | 49 const int kVerticalOffset = 0; |
39 | 50 |
40 // Name of the magnifier window. | 51 // Name of the magnifier window. |
41 const char kPartialMagniferWindowName[] = "PartialMagnifierWindow"; | 52 const char kPartialMagniferWindowName[] = "PartialMagnifierWindow"; |
42 | 53 |
43 gfx::Size GetWindowSize() { | 54 gfx::Size GetWindowSize() { |
44 return gfx::Size(kMagnifierRadius * 2, kMagnifierRadius * 2); | 55 // The diameter of the window is the diameter of the magnifier, border and |
56 // shadow combined. We apply |kShadowOffset| on all sides even though the | |
57 // shadow is only thicker on the bottom so as to keep the circle centered in | |
58 // the view and keep calculations (border rendering and content masking) | |
59 // simpler. | |
60 int window_diameter = | |
61 (kMagnifierRadius + kBorderSize + kShadowThickness + kShadowOffset) * 2; | |
62 return gfx::Size(window_diameter, window_diameter); | |
45 } | 63 } |
46 | 64 |
47 gfx::Rect GetBounds(gfx::Point mouse) { | 65 gfx::Rect GetBounds(gfx::Point mouse) { |
48 gfx::Size size = GetWindowSize(); | 66 gfx::Size size = GetWindowSize(); |
49 gfx::Point origin(mouse.x() - (size.width() / 2), | 67 gfx::Point origin(mouse.x() - (size.width() / 2), |
50 mouse.y() - (size.height() / 2) - kVerticalOffset); | 68 mouse.y() - (size.height() / 2) - kVerticalOffset); |
51 return gfx::Rect(origin, size); | 69 return gfx::Rect(origin, size); |
52 } | 70 } |
53 | 71 |
54 aura::Window* GetCurrentRootWindow() { | 72 aura::Window* GetCurrentRootWindow() { |
55 aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows(); | 73 aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows(); |
56 for (aura::Window* root_window : root_windows) { | 74 for (aura::Window* root_window : root_windows) { |
57 if (root_window->ContainsPointInRoot( | 75 if (root_window->ContainsPointInRoot( |
58 root_window->GetHost()->dispatcher()->GetLastMouseLocationInRoot())) | 76 root_window->GetHost()->dispatcher()->GetLastMouseLocationInRoot())) |
59 return root_window; | 77 return root_window; |
60 } | 78 } |
61 return nullptr; | 79 return nullptr; |
62 } | 80 } |
63 | 81 |
64 } // namespace | 82 } // namespace |
65 | 83 |
66 // The content mask provides a clipping layer for the magnification window so we | 84 // The content mask provides a clipping layer for the magnification window so we |
67 // can show a circular magnifier. | 85 // can show a circular magnifier. |
68 class PartialMagnificationController::ContentMask : public ui::LayerDelegate { | 86 class PartialMagnificationController::ContentMask : public ui::LayerDelegate { |
69 public: | 87 public: |
70 // If |stroke| is true, the circle will be a stroke. This is useful if we wish | 88 // If |is_border| is true, the circle will be a stroke. This is useful if we |
71 // to clip a border. | 89 // wish to clip a border. |
72 ContentMask(bool stroke, gfx::Size mask_bounds) | 90 ContentMask(bool is_border, gfx::Size mask_bounds) |
73 : layer_(ui::LAYER_TEXTURED), stroke_(stroke) { | 91 : layer_(ui::LAYER_TEXTURED), is_border_(is_border) { |
74 layer_.set_delegate(this); | 92 layer_.set_delegate(this); |
75 layer_.SetFillsBoundsOpaquely(false); | 93 layer_.SetFillsBoundsOpaquely(false); |
76 layer_.SetBounds(gfx::Rect(mask_bounds)); | 94 layer_.SetBounds(gfx::Rect(mask_bounds)); |
77 } | 95 } |
78 | 96 |
79 ~ContentMask() override { layer_.set_delegate(nullptr); } | 97 ~ContentMask() override { layer_.set_delegate(nullptr); } |
80 | 98 |
81 ui::Layer* layer() { return &layer_; } | 99 ui::Layer* layer() { return &layer_; } |
82 | 100 |
83 private: | 101 private: |
84 // ui::LayerDelegate: | 102 // ui::LayerDelegate: |
85 void OnPaintLayer(const ui::PaintContext& context) override { | 103 void OnPaintLayer(const ui::PaintContext& context) override { |
86 ui::PaintRecorder recorder(context, layer()->size()); | 104 ui::PaintRecorder recorder(context, layer()->size()); |
87 | 105 |
88 SkPaint paint; | 106 SkPaint paint; |
89 paint.setAlpha(255); | 107 paint.setAlpha(255); |
90 paint.setAntiAlias(true); | 108 paint.setAntiAlias(true); |
91 paint.setStrokeWidth(kBorderSize); | 109 // Stroke is used for clipping the border which consists of the rendered |
92 paint.setStyle(stroke_ ? SkPaint::kStroke_Style : SkPaint::kFill_Style); | 110 // border |kBorderSize| and the magnifier shadow |kShadowThickness| and |
111 // |kShadowOffset|. | |
112 paint.setStrokeWidth(kBorderSize + kShadowThickness + kShadowOffset); | |
113 paint.setStyle(is_border_ ? SkPaint::kStroke_Style : SkPaint::kFill_Style); | |
93 | 114 |
115 // If we want to clip the magnifier zone use the magnifiers radius. | |
116 // Otherwise we want to clip the border, shadow and shadowoffset so we start | |
jdufault
2016/10/04 22:19:47
shadowoffset => shadow offset
sammiequon
2016/10/05 17:54:36
Done.
| |
117 // at the halfway point of the stroke width. | |
94 gfx::Rect rect(layer()->bounds().size()); | 118 gfx::Rect rect(layer()->bounds().size()); |
95 recorder.canvas()->DrawCircle(rect.CenterPoint(), | 119 int clipping_radius = kMagnifierRadius; |
96 rect.width() / 2 - kBorderSize / 2, paint); | 120 if (is_border_) |
121 clipping_radius += (kShadowThickness + kShadowOffset + kBorderSize) / 2; | |
122 recorder.canvas()->DrawCircle(rect.CenterPoint(), clipping_radius, paint); | |
97 } | 123 } |
98 | 124 |
99 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {} | 125 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {} |
100 | 126 |
101 void OnDeviceScaleFactorChanged(float device_scale_factor) override { | 127 void OnDeviceScaleFactorChanged(float device_scale_factor) override { |
102 // Redrawing will take care of scale factor change. | 128 // Redrawing will take care of scale factor change. |
103 } | 129 } |
104 | 130 |
105 base::Closure PrepareForLayerBoundsChange() override { | 131 base::Closure PrepareForLayerBoundsChange() override { |
106 return base::Closure(); | 132 return base::Closure(); |
107 } | 133 } |
108 | 134 |
109 ui::Layer layer_; | 135 ui::Layer layer_; |
110 bool stroke_; | 136 bool is_border_; |
111 | |
112 DISALLOW_COPY_AND_ASSIGN(ContentMask); | 137 DISALLOW_COPY_AND_ASSIGN(ContentMask); |
113 }; | 138 }; |
114 | 139 |
115 // The border renderer draws the border as well as outline on both the outer and | 140 // The border renderer draws the border as well as outline on both the outer and |
116 // inner radius to increase visibility. | 141 // inner radius to increase visibility. The border renderer also handles drawing |
142 // the shadow. | |
117 class PartialMagnificationController::BorderRenderer | 143 class PartialMagnificationController::BorderRenderer |
118 : public ui::LayerDelegate { | 144 : public ui::LayerDelegate { |
119 public: | 145 public: |
120 explicit BorderRenderer(const gfx::Rect& magnifier_bounds) | 146 explicit BorderRenderer(const gfx::Rect& window_bounds) |
121 : magnifier_bounds_(magnifier_bounds) {} | 147 : magnifier_window_bounds_(window_bounds) { |
148 magnifier_shadows_.push_back(gfx::ShadowValue( | |
149 gfx::Vector2d(0, kShadowOffset), kShadowThickness, kBottomShadowColor)); | |
150 magnifier_shadows_.push_back(gfx::ShadowValue( | |
151 gfx::Vector2d(0, 0), kShadowThickness, kTopShadowColor)); | |
152 } | |
122 | 153 |
123 ~BorderRenderer() override {} | 154 ~BorderRenderer() override {} |
124 | 155 |
125 private: | 156 private: |
126 // ui::LayerDelegate: | 157 // ui::LayerDelegate: |
127 void OnPaintLayer(const ui::PaintContext& context) override { | 158 void OnPaintLayer(const ui::PaintContext& context) override { |
128 ui::PaintRecorder recorder(context, magnifier_bounds_.size()); | 159 ui::PaintRecorder recorder(context, magnifier_window_bounds_.size()); |
129 | 160 |
130 SkPaint paint; | 161 // Draw the shadow. |
131 paint.setAntiAlias(true); | 162 SkPaint shadow_paint; |
132 paint.setStyle(SkPaint::kStroke_Style); | 163 shadow_paint.setAntiAlias(true); |
164 shadow_paint.setColor(SK_ColorTRANSPARENT); | |
165 shadow_paint.setLooper(gfx::CreateShadowDrawLooper(magnifier_shadows_)); | |
166 gfx::Rect shadow_bounds(magnifier_window_bounds_.size()); | |
167 recorder.canvas()->DrawCircle( | |
168 shadow_bounds.CenterPoint(), | |
169 shadow_bounds.width() / 2 - kShadowThickness - kShadowOffset, | |
170 shadow_paint); | |
133 | 171 |
134 const int magnifier_radius = magnifier_bounds_.width() / 2; | 172 SkPaint border_paint; |
173 border_paint.setAntiAlias(true); | |
174 border_paint.setStyle(SkPaint::kStroke_Style); | |
175 | |
176 // The radius of the magnifier and its border. | |
177 const int magnifier_radius = | |
jdufault
2016/10/04 22:19:47
Can we compute this value from the constants inste
sammiequon
2016/10/05 17:54:36
Done.
| |
178 magnifier_window_bounds_.width() / 2 - kShadowThickness - kShadowOffset; | |
135 // Draw the inner border. | 179 // Draw the inner border. |
136 paint.setStrokeWidth(kBorderSize); | 180 border_paint.setStrokeWidth(kBorderSize); |
137 paint.setColor(kBorderColor); | 181 border_paint.setColor(kBorderColor); |
138 recorder.canvas()->DrawCircle(magnifier_bounds_.CenterPoint(), | 182 recorder.canvas()->DrawCircle(magnifier_window_bounds_.CenterPoint(), |
139 magnifier_radius - kBorderSize / 2, paint); | 183 magnifier_radius - kBorderSize / 2, |
184 border_paint); | |
140 | 185 |
141 // Draw border outer outline and then draw the border inner outline. | 186 // Draw border outer outline and then draw the border inner outline. |
142 paint.setStrokeWidth(kBorderOutlineThickness); | 187 border_paint.setStrokeWidth(kBorderOutlineThickness); |
143 paint.setColor(kBorderOutlineColor); | 188 border_paint.setColor(kBorderOutlineColor); |
144 recorder.canvas()->DrawCircle( | 189 recorder.canvas()->DrawCircle( |
145 magnifier_bounds_.CenterPoint(), | 190 magnifier_window_bounds_.CenterPoint(), |
146 magnifier_radius - kBorderOutlineThickness / 2, paint); | 191 magnifier_radius - kBorderOutlineThickness / 2, border_paint); |
147 recorder.canvas()->DrawCircle( | 192 recorder.canvas()->DrawCircle( |
148 magnifier_bounds_.CenterPoint(), | 193 magnifier_window_bounds_.CenterPoint(), |
149 magnifier_radius - kBorderSize + kBorderOutlineThickness / 2, paint); | 194 magnifier_radius - kBorderSize + kBorderOutlineThickness / 2, |
195 border_paint); | |
150 } | 196 } |
151 | 197 |
152 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {} | 198 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {} |
153 | 199 |
154 void OnDeviceScaleFactorChanged(float device_scale_factor) override {} | 200 void OnDeviceScaleFactorChanged(float device_scale_factor) override {} |
155 | 201 |
156 base::Closure PrepareForLayerBoundsChange() override { | 202 base::Closure PrepareForLayerBoundsChange() override { |
157 return base::Closure(); | 203 return base::Closure(); |
158 } | 204 } |
159 | 205 |
160 gfx::Rect magnifier_bounds_; | 206 gfx::Rect magnifier_window_bounds_; |
207 std::vector<gfx::ShadowValue> magnifier_shadows_; | |
161 | 208 |
162 DISALLOW_COPY_AND_ASSIGN(BorderRenderer); | 209 DISALLOW_COPY_AND_ASSIGN(BorderRenderer); |
163 }; | 210 }; |
164 | 211 |
165 PartialMagnificationController::PartialMagnificationController() { | 212 PartialMagnificationController::PartialMagnificationController() { |
166 Shell::GetInstance()->AddPreTargetHandler(this); | 213 Shell::GetInstance()->AddPreTargetHandler(this); |
167 } | 214 } |
168 | 215 |
169 PartialMagnificationController::~PartialMagnificationController() { | 216 PartialMagnificationController::~PartialMagnificationController() { |
170 CloseMagnifierWindow(); | 217 CloseMagnifierWindow(); |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
304 | 351 |
305 zoom_layer_.reset(new ui::Layer(ui::LayerType::LAYER_SOLID_COLOR)); | 352 zoom_layer_.reset(new ui::Layer(ui::LayerType::LAYER_SOLID_COLOR)); |
306 zoom_layer_->SetBounds(gfx::Rect(GetWindowSize())); | 353 zoom_layer_->SetBounds(gfx::Rect(GetWindowSize())); |
307 zoom_layer_->SetBackgroundZoom(kMagnificationScale, kZoomInset); | 354 zoom_layer_->SetBackgroundZoom(kMagnificationScale, kZoomInset); |
308 root_layer->Add(zoom_layer_.get()); | 355 root_layer->Add(zoom_layer_.get()); |
309 | 356 |
310 border_layer_.reset(new ui::Layer(ui::LayerType::LAYER_TEXTURED)); | 357 border_layer_.reset(new ui::Layer(ui::LayerType::LAYER_TEXTURED)); |
311 border_layer_->SetBounds(gfx::Rect(GetWindowSize())); | 358 border_layer_->SetBounds(gfx::Rect(GetWindowSize())); |
312 border_renderer_.reset(new BorderRenderer(gfx::Rect(GetWindowSize()))); | 359 border_renderer_.reset(new BorderRenderer(gfx::Rect(GetWindowSize()))); |
313 border_layer_->set_delegate(border_renderer_.get()); | 360 border_layer_->set_delegate(border_renderer_.get()); |
361 border_layer_->SetFillsBoundsOpaquely(false); | |
314 root_layer->Add(border_layer_.get()); | 362 root_layer->Add(border_layer_.get()); |
315 | 363 |
316 border_mask_.reset(new ContentMask(true, GetWindowSize())); | 364 border_mask_.reset(new ContentMask(true, GetWindowSize())); |
317 border_layer_->SetMaskLayer(border_mask_->layer()); | 365 border_layer_->SetMaskLayer(border_mask_->layer()); |
318 | 366 |
319 zoom_mask_.reset(new ContentMask(false, GetWindowSize())); | 367 zoom_mask_.reset(new ContentMask(false, GetWindowSize())); |
320 zoom_layer_->SetMaskLayer(zoom_mask_->layer()); | 368 zoom_layer_->SetMaskLayer(zoom_mask_->layer()); |
321 | 369 |
322 host_widget_->AddObserver(this); | 370 host_widget_->AddObserver(this); |
323 } | 371 } |
324 | 372 |
325 void PartialMagnificationController::CloseMagnifierWindow() { | 373 void PartialMagnificationController::CloseMagnifierWindow() { |
326 if (host_widget_) { | 374 if (host_widget_) { |
327 RemoveZoomWidgetObservers(); | 375 RemoveZoomWidgetObservers(); |
328 host_widget_->Close(); | 376 host_widget_->Close(); |
329 host_widget_ = nullptr; | 377 host_widget_ = nullptr; |
330 } | 378 } |
331 } | 379 } |
332 | 380 |
333 void PartialMagnificationController::RemoveZoomWidgetObservers() { | 381 void PartialMagnificationController::RemoveZoomWidgetObservers() { |
334 DCHECK(host_widget_); | 382 DCHECK(host_widget_); |
335 host_widget_->RemoveObserver(this); | 383 host_widget_->RemoveObserver(this); |
336 aura::Window* root_window = host_widget_->GetNativeView()->GetRootWindow(); | 384 aura::Window* root_window = host_widget_->GetNativeView()->GetRootWindow(); |
337 DCHECK(root_window); | 385 DCHECK(root_window); |
338 root_window->RemoveObserver(this); | 386 root_window->RemoveObserver(this); |
339 } | 387 } |
340 | 388 |
341 } // namespace ash | 389 } // namespace ash |
OLD | NEW |