| 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 shadow offset so we |
| 117 // start |
| 118 // at the halfway point of the stroke width. |
| 94 gfx::Rect rect(layer()->bounds().size()); | 119 gfx::Rect rect(layer()->bounds().size()); |
| 95 recorder.canvas()->DrawCircle(rect.CenterPoint(), | 120 int clipping_radius = kMagnifierRadius; |
| 96 rect.width() / 2 - kBorderSize / 2, paint); | 121 if (is_border_) |
| 122 clipping_radius += (kShadowThickness + kShadowOffset + kBorderSize) / 2; |
| 123 recorder.canvas()->DrawCircle(rect.CenterPoint(), clipping_radius, paint); |
| 97 } | 124 } |
| 98 | 125 |
| 99 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {} | 126 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {} |
| 100 | 127 |
| 101 void OnDeviceScaleFactorChanged(float device_scale_factor) override { | 128 void OnDeviceScaleFactorChanged(float device_scale_factor) override { |
| 102 // Redrawing will take care of scale factor change. | 129 // Redrawing will take care of scale factor change. |
| 103 } | 130 } |
| 104 | 131 |
| 105 base::Closure PrepareForLayerBoundsChange() override { | 132 base::Closure PrepareForLayerBoundsChange() override { |
| 106 return base::Closure(); | 133 return base::Closure(); |
| 107 } | 134 } |
| 108 | 135 |
| 109 ui::Layer layer_; | 136 ui::Layer layer_; |
| 110 bool stroke_; | 137 bool is_border_; |
| 111 | |
| 112 DISALLOW_COPY_AND_ASSIGN(ContentMask); | 138 DISALLOW_COPY_AND_ASSIGN(ContentMask); |
| 113 }; | 139 }; |
| 114 | 140 |
| 115 // The border renderer draws the border as well as outline on both the outer and | 141 // The border renderer draws the border as well as outline on both the outer and |
| 116 // inner radius to increase visibility. | 142 // inner radius to increase visibility. The border renderer also handles drawing |
| 143 // the shadow. |
| 117 class PartialMagnificationController::BorderRenderer | 144 class PartialMagnificationController::BorderRenderer |
| 118 : public ui::LayerDelegate { | 145 : public ui::LayerDelegate { |
| 119 public: | 146 public: |
| 120 explicit BorderRenderer(const gfx::Rect& magnifier_bounds) | 147 explicit BorderRenderer(const gfx::Rect& window_bounds) |
| 121 : magnifier_bounds_(magnifier_bounds) {} | 148 : magnifier_window_bounds_(window_bounds) { |
| 149 magnifier_shadows_.push_back(gfx::ShadowValue( |
| 150 gfx::Vector2d(0, kShadowOffset), kShadowThickness, kBottomShadowColor)); |
| 151 magnifier_shadows_.push_back(gfx::ShadowValue( |
| 152 gfx::Vector2d(0, 0), kShadowThickness, kTopShadowColor)); |
| 153 } |
| 122 | 154 |
| 123 ~BorderRenderer() override {} | 155 ~BorderRenderer() override {} |
| 124 | 156 |
| 125 private: | 157 private: |
| 126 // ui::LayerDelegate: | 158 // ui::LayerDelegate: |
| 127 void OnPaintLayer(const ui::PaintContext& context) override { | 159 void OnPaintLayer(const ui::PaintContext& context) override { |
| 128 ui::PaintRecorder recorder(context, magnifier_bounds_.size()); | 160 ui::PaintRecorder recorder(context, magnifier_window_bounds_.size()); |
| 129 | 161 |
| 130 SkPaint paint; | 162 // Draw the shadow. |
| 131 paint.setAntiAlias(true); | 163 SkPaint shadow_paint; |
| 132 paint.setStyle(SkPaint::kStroke_Style); | 164 shadow_paint.setAntiAlias(true); |
| 165 shadow_paint.setColor(SK_ColorTRANSPARENT); |
| 166 shadow_paint.setLooper( |
| 167 gfx::CreateShadowDrawLooperCorrectBlur(magnifier_shadows_)); |
| 168 gfx::Rect shadow_bounds(magnifier_window_bounds_.size()); |
| 169 recorder.canvas()->DrawCircle( |
| 170 shadow_bounds.CenterPoint(), |
| 171 shadow_bounds.width() / 2 - kShadowThickness - kShadowOffset, |
| 172 shadow_paint); |
| 133 | 173 |
| 134 const int magnifier_radius = magnifier_bounds_.width() / 2; | 174 SkPaint border_paint; |
| 175 border_paint.setAntiAlias(true); |
| 176 border_paint.setStyle(SkPaint::kStroke_Style); |
| 177 |
| 178 // The radius of the magnifier and its border. |
| 179 const int magnifier_radius = kMagnifierRadius + kBorderSize; |
| 180 |
| 135 // Draw the inner border. | 181 // Draw the inner border. |
| 136 paint.setStrokeWidth(kBorderSize); | 182 border_paint.setStrokeWidth(kBorderSize); |
| 137 paint.setColor(kBorderColor); | 183 border_paint.setColor(kBorderColor); |
| 138 recorder.canvas()->DrawCircle(magnifier_bounds_.CenterPoint(), | 184 recorder.canvas()->DrawCircle(magnifier_window_bounds_.CenterPoint(), |
| 139 magnifier_radius - kBorderSize / 2, paint); | 185 magnifier_radius - kBorderSize / 2, |
| 186 border_paint); |
| 140 | 187 |
| 141 // Draw border outer outline and then draw the border inner outline. | 188 // Draw border outer outline and then draw the border inner outline. |
| 142 paint.setStrokeWidth(kBorderOutlineThickness); | 189 border_paint.setStrokeWidth(kBorderOutlineThickness); |
| 143 paint.setColor(kBorderOutlineColor); | 190 border_paint.setColor(kBorderOutlineColor); |
| 144 recorder.canvas()->DrawCircle( | 191 recorder.canvas()->DrawCircle( |
| 145 magnifier_bounds_.CenterPoint(), | 192 magnifier_window_bounds_.CenterPoint(), |
| 146 magnifier_radius - kBorderOutlineThickness / 2, paint); | 193 magnifier_radius - kBorderOutlineThickness / 2, border_paint); |
| 147 recorder.canvas()->DrawCircle( | 194 recorder.canvas()->DrawCircle( |
| 148 magnifier_bounds_.CenterPoint(), | 195 magnifier_window_bounds_.CenterPoint(), |
| 149 magnifier_radius - kBorderSize + kBorderOutlineThickness / 2, paint); | 196 magnifier_radius - kBorderSize + kBorderOutlineThickness / 2, |
| 197 border_paint); |
| 150 } | 198 } |
| 151 | 199 |
| 152 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {} | 200 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {} |
| 153 | 201 |
| 154 void OnDeviceScaleFactorChanged(float device_scale_factor) override {} | 202 void OnDeviceScaleFactorChanged(float device_scale_factor) override {} |
| 155 | 203 |
| 156 base::Closure PrepareForLayerBoundsChange() override { | 204 base::Closure PrepareForLayerBoundsChange() override { |
| 157 return base::Closure(); | 205 return base::Closure(); |
| 158 } | 206 } |
| 159 | 207 |
| 160 gfx::Rect magnifier_bounds_; | 208 gfx::Rect magnifier_window_bounds_; |
| 209 std::vector<gfx::ShadowValue> magnifier_shadows_; |
| 161 | 210 |
| 162 DISALLOW_COPY_AND_ASSIGN(BorderRenderer); | 211 DISALLOW_COPY_AND_ASSIGN(BorderRenderer); |
| 163 }; | 212 }; |
| 164 | 213 |
| 165 PartialMagnificationController::PartialMagnificationController() { | 214 PartialMagnificationController::PartialMagnificationController() { |
| 166 Shell::GetInstance()->AddPreTargetHandler(this); | 215 Shell::GetInstance()->AddPreTargetHandler(this); |
| 167 } | 216 } |
| 168 | 217 |
| 169 PartialMagnificationController::~PartialMagnificationController() { | 218 PartialMagnificationController::~PartialMagnificationController() { |
| 170 CloseMagnifierWindow(); | 219 CloseMagnifierWindow(); |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 304 | 353 |
| 305 zoom_layer_.reset(new ui::Layer(ui::LayerType::LAYER_SOLID_COLOR)); | 354 zoom_layer_.reset(new ui::Layer(ui::LayerType::LAYER_SOLID_COLOR)); |
| 306 zoom_layer_->SetBounds(gfx::Rect(GetWindowSize())); | 355 zoom_layer_->SetBounds(gfx::Rect(GetWindowSize())); |
| 307 zoom_layer_->SetBackgroundZoom(kMagnificationScale, kZoomInset); | 356 zoom_layer_->SetBackgroundZoom(kMagnificationScale, kZoomInset); |
| 308 root_layer->Add(zoom_layer_.get()); | 357 root_layer->Add(zoom_layer_.get()); |
| 309 | 358 |
| 310 border_layer_.reset(new ui::Layer(ui::LayerType::LAYER_TEXTURED)); | 359 border_layer_.reset(new ui::Layer(ui::LayerType::LAYER_TEXTURED)); |
| 311 border_layer_->SetBounds(gfx::Rect(GetWindowSize())); | 360 border_layer_->SetBounds(gfx::Rect(GetWindowSize())); |
| 312 border_renderer_.reset(new BorderRenderer(gfx::Rect(GetWindowSize()))); | 361 border_renderer_.reset(new BorderRenderer(gfx::Rect(GetWindowSize()))); |
| 313 border_layer_->set_delegate(border_renderer_.get()); | 362 border_layer_->set_delegate(border_renderer_.get()); |
| 363 border_layer_->SetFillsBoundsOpaquely(false); |
| 314 root_layer->Add(border_layer_.get()); | 364 root_layer->Add(border_layer_.get()); |
| 315 | 365 |
| 316 border_mask_.reset(new ContentMask(true, GetWindowSize())); | 366 border_mask_.reset(new ContentMask(true, GetWindowSize())); |
| 317 border_layer_->SetMaskLayer(border_mask_->layer()); | 367 border_layer_->SetMaskLayer(border_mask_->layer()); |
| 318 | 368 |
| 319 zoom_mask_.reset(new ContentMask(false, GetWindowSize())); | 369 zoom_mask_.reset(new ContentMask(false, GetWindowSize())); |
| 320 zoom_layer_->SetMaskLayer(zoom_mask_->layer()); | 370 zoom_layer_->SetMaskLayer(zoom_mask_->layer()); |
| 321 | 371 |
| 322 host_widget_->AddObserver(this); | 372 host_widget_->AddObserver(this); |
| 323 } | 373 } |
| 324 | 374 |
| 325 void PartialMagnificationController::CloseMagnifierWindow() { | 375 void PartialMagnificationController::CloseMagnifierWindow() { |
| 326 if (host_widget_) { | 376 if (host_widget_) { |
| 327 RemoveZoomWidgetObservers(); | 377 RemoveZoomWidgetObservers(); |
| 328 host_widget_->Close(); | 378 host_widget_->Close(); |
| 329 host_widget_ = nullptr; | 379 host_widget_ = nullptr; |
| 330 } | 380 } |
| 331 } | 381 } |
| 332 | 382 |
| 333 void PartialMagnificationController::RemoveZoomWidgetObservers() { | 383 void PartialMagnificationController::RemoveZoomWidgetObservers() { |
| 334 DCHECK(host_widget_); | 384 DCHECK(host_widget_); |
| 335 host_widget_->RemoveObserver(this); | 385 host_widget_->RemoveObserver(this); |
| 336 aura::Window* root_window = host_widget_->GetNativeView()->GetRootWindow(); | 386 aura::Window* root_window = host_widget_->GetNativeView()->GetRootWindow(); |
| 337 DCHECK(root_window); | 387 DCHECK(root_window); |
| 338 root_window->RemoveObserver(this); | 388 root_window->RemoveObserver(this); |
| 339 } | 389 } |
| 340 | 390 |
| 341 } // namespace ash | 391 } // namespace ash |
| OLD | NEW |