Chromium Code Reviews| 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 |