| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/utility/screenshot_controller.h" | 5 #include "ash/utility/screenshot_controller.h" |
| 6 | 6 |
| 7 #include <cmath> | 7 #include <cmath> |
| 8 | 8 |
| 9 #include "ash/display/mouse_cursor_event_filter.h" | 9 #include "ash/display/mouse_cursor_event_filter.h" |
| 10 #include "ash/screenshot_delegate.h" | 10 #include "ash/screenshot_delegate.h" |
| 11 #include "ash/shell.h" | 11 #include "ash/shell.h" |
| 12 #include "ash/shell_window_ids.h" | 12 #include "ash/shell_window_ids.h" |
| 13 #include "ash/wm/window_util.h" | 13 #include "ash/wm/window_util.h" |
| 14 #include "base/stl_util.h" | 14 #include "base/stl_util.h" |
| 15 #include "ui/aura/client/capture_client.h" | 15 #include "ui/aura/client/capture_client.h" |
| 16 #include "ui/aura/client/screen_position_client.h" | 16 #include "ui/aura/client/screen_position_client.h" |
| 17 #include "ui/aura/window_targeter.h" | 17 #include "ui/aura/window_targeter.h" |
| 18 #include "ui/compositor/paint_recorder.h" | 18 #include "ui/compositor/paint_recorder.h" |
| 19 #include "ui/display/screen.h" | 19 #include "ui/display/screen.h" |
| 20 #include "ui/events/event.h" | 20 #include "ui/events/event.h" |
| 21 #include "ui/events/event_handler.h" | 21 #include "ui/events/event_handler.h" |
| 22 #include "ui/gfx/canvas.h" | 22 #include "ui/gfx/canvas.h" |
| 23 #include "ui/views/widget/widget.h" | 23 #include "ui/views/widget/widget.h" |
| 24 #include "ui/wm/core/cursor_manager.h" | 24 #include "ui/wm/core/cursor_manager.h" |
| 25 | 25 |
| 26 namespace ash { | 26 namespace ash { |
| 27 | 27 |
| 28 namespace { | 28 namespace { |
| 29 | 29 |
| 30 // The size to increase the invalidated area in the layer to repaint. The area | 30 const int kCursorSize = 12; |
| 31 // should be slightly bigger than the actual region because the region indicator | |
| 32 // rectangles are drawn outside of the selected region. | |
| 33 const int kInvalidateRegionAdditionalSize = 3; | |
| 34 | 31 |
| 35 // This will prevent the user from taking a screenshot across multiple | 32 // This will prevent the user from taking a screenshot across multiple |
| 36 // monitors. it will stop the mouse at the any edge of the screen. must | 33 // monitors. it will stop the mouse at the any edge of the screen. must |
| 37 // swtich back on when the screenshot is complete. | 34 // swtich back on when the screenshot is complete. |
| 38 void EnableMouseWarp(bool enable) { | 35 void EnableMouseWarp(bool enable) { |
| 39 Shell::GetInstance()->mouse_cursor_filter()->set_mouse_warp_enabled(enable); | 36 Shell::GetInstance()->mouse_cursor_filter()->set_mouse_warp_enabled(enable); |
| 40 } | 37 } |
| 41 | 38 |
| 42 class ScreenshotWindowTargeter : public aura::WindowTargeter { | 39 class ScreenshotWindowTargeter : public aura::WindowTargeter { |
| 43 public: | 40 public: |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 98 layer()->set_delegate(this); | 95 layer()->set_delegate(this); |
| 99 } | 96 } |
| 100 ~ScreenshotLayer() override {} | 97 ~ScreenshotLayer() override {} |
| 101 | 98 |
| 102 const gfx::Rect& region() const { return region_; } | 99 const gfx::Rect& region() const { return region_; } |
| 103 | 100 |
| 104 void SetRegion(const gfx::Rect& region) { | 101 void SetRegion(const gfx::Rect& region) { |
| 105 // Invalidates the region which covers the current and new region. | 102 // Invalidates the region which covers the current and new region. |
| 106 gfx::Rect union_rect(region_); | 103 gfx::Rect union_rect(region_); |
| 107 union_rect.Union(region); | 104 union_rect.Union(region); |
| 108 union_rect.Inset(-kInvalidateRegionAdditionalSize, | |
| 109 -kInvalidateRegionAdditionalSize); | |
| 110 union_rect.Intersects(layer()->bounds()); | 105 union_rect.Intersects(layer()->bounds()); |
| 106 union_rect.Inset(-kCursorSize, -kCursorSize, -kCursorSize, -kCursorSize); |
| 111 region_ = region; | 107 region_ = region; |
| 112 layer()->SchedulePaint(union_rect); | 108 layer()->SchedulePaint(union_rect); |
| 113 } | 109 } |
| 114 | 110 |
| 111 void set_cursor_location_in_root(const gfx::Point& point) { |
| 112 cursor_location_in_root_ = point; |
| 113 } |
| 114 |
| 115 private: | 115 private: |
| 116 // ui::LayerDelegate: | 116 // ui::LayerDelegate: |
| 117 void OnPaintLayer(const ui::PaintContext& context) override { | 117 void OnPaintLayer(const ui::PaintContext& context) override { |
| 118 const SkColor kSelectedAreaOverlayColor = 0x40000000; | 118 const SkColor kSelectedAreaOverlayColor = 0x60000000; |
| 119 if (region_.IsEmpty()) | 119 // Screenshot area representation: transparent hole with half opaque gray |
| 120 return; | 120 // overlay. |
| 121 // Screenshot area representation: black rectangle with white | |
| 122 // rectangle inside. To avoid capturing these rectangles when mouse | |
| 123 // release, they should be outside of the actual capturing area. | |
| 124 gfx::Rect rect(region_); | 121 gfx::Rect rect(region_); |
| 125 ui::PaintRecorder recorder(context, layer()->size()); | 122 ui::PaintRecorder recorder(context, layer()->size()); |
| 126 | 123 |
| 127 recorder.canvas()->FillRect(region_, kSelectedAreaOverlayColor); | 124 recorder.canvas()->FillRect(gfx::Rect(layer()->size()), |
| 125 kSelectedAreaOverlayColor); |
| 128 | 126 |
| 129 rect.Inset(-1, -1); | 127 DrawPseudoCursor(recorder.canvas()); |
| 130 recorder.canvas()->DrawRect(rect, SK_ColorWHITE); | 128 |
| 131 rect.Inset(-1, -1); | 129 if (!region_.IsEmpty()) |
| 132 recorder.canvas()->DrawRect(rect, SK_ColorBLACK); | 130 recorder.canvas()->FillRect(region_, SK_ColorBLACK, |
| 131 SkXfermode::kClear_Mode); |
| 133 } | 132 } |
| 134 | 133 |
| 135 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {} | 134 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {} |
| 136 | 135 |
| 137 void OnDeviceScaleFactorChanged(float device_scale_factor) override {} | 136 void OnDeviceScaleFactorChanged(float device_scale_factor) override {} |
| 138 | 137 |
| 139 base::Closure PrepareForLayerBoundsChange() override { | 138 base::Closure PrepareForLayerBoundsChange() override { |
| 140 return base::Closure(); | 139 return base::Closure(); |
| 141 } | 140 } |
| 142 | 141 |
| 142 // Mouse cursor may move sub DIP, so paint pseudo cursor instead of |
| 143 // using platform cursor so that it's aliend with the region. |
| 144 void DrawPseudoCursor(gfx::Canvas* canvas) { |
| 145 // Don't draw if window selection mode. |
| 146 if (cursor_location_in_root_.IsOrigin()) |
| 147 return; |
| 148 |
| 149 gfx::Point pseudo_cursor_point = cursor_location_in_root_; |
| 150 |
| 151 // The cursor is above/before region. |
| 152 if (pseudo_cursor_point.x() == region_.x()) |
| 153 pseudo_cursor_point.Offset(-1, 0); |
| 154 |
| 155 if (pseudo_cursor_point.y() == region_.y()) |
| 156 pseudo_cursor_point.Offset(0, -1); |
| 157 |
| 158 SkPaint paint; |
| 159 paint.setAntiAlias(false); |
| 160 paint.setStrokeWidth(1); |
| 161 paint.setColor(SK_ColorWHITE); |
| 162 paint.setXfermodeMode(SkXfermode::kSrc_Mode); |
| 163 gfx::Vector2d width(kCursorSize / 2, 0); |
| 164 gfx::Vector2d height(0, kCursorSize / 2); |
| 165 gfx::Vector2d white_x_offset(1, -1); |
| 166 gfx::Vector2d white_y_offset(1, -1); |
| 167 // Horizontal |
| 168 canvas->DrawLine(pseudo_cursor_point - width + white_x_offset, |
| 169 pseudo_cursor_point + width + white_x_offset, paint); |
| 170 paint.setStrokeWidth(1); |
| 171 // Vertical |
| 172 canvas->DrawLine(pseudo_cursor_point - height + white_y_offset, |
| 173 pseudo_cursor_point + height + white_y_offset, paint); |
| 174 |
| 175 paint.setColor(SK_ColorBLACK); |
| 176 // Horizontal |
| 177 canvas->DrawLine(pseudo_cursor_point - width, pseudo_cursor_point + width, |
| 178 paint); |
| 179 // Vertical |
| 180 canvas->DrawLine(pseudo_cursor_point - height, pseudo_cursor_point + height, |
| 181 paint); |
| 182 } |
| 183 |
| 143 gfx::Rect region_; | 184 gfx::Rect region_; |
| 144 | 185 |
| 186 gfx::Point cursor_location_in_root_; |
| 187 |
| 145 DISALLOW_COPY_AND_ASSIGN(ScreenshotLayer); | 188 DISALLOW_COPY_AND_ASSIGN(ScreenshotLayer); |
| 146 }; | 189 }; |
| 147 | 190 |
| 148 class ScreenshotController::ScopedCursorSetter { | 191 class ScreenshotController::ScopedCursorSetter { |
| 149 public: | 192 public: |
| 150 ScopedCursorSetter(::wm::CursorManager* cursor_manager, | 193 ScopedCursorSetter(::wm::CursorManager* cursor_manager, |
| 151 gfx::NativeCursor cursor) | 194 gfx::NativeCursor cursor) |
| 152 : cursor_manager_(nullptr) { | 195 : cursor_manager_(nullptr) { |
| 153 if (cursor_manager->IsCursorLocked()) | 196 if (cursor_manager->IsCursorLocked()) |
| 154 return; | 197 return; |
| 155 gfx::NativeCursor original_cursor = cursor_manager->GetCursor(); | 198 gfx::NativeCursor original_cursor = cursor_manager->GetCursor(); |
| 156 cursor_manager_ = cursor_manager; | 199 cursor_manager_ = cursor_manager; |
| 157 cursor_manager_->SetCursor(cursor); | 200 if (cursor == ui::kCursorNone) { |
| 158 if (!cursor_manager_->IsCursorVisible()) | 201 cursor_manager_->HideCursor(); |
| 202 } else { |
| 203 cursor_manager_->SetCursor(cursor); |
| 159 cursor_manager_->ShowCursor(); | 204 cursor_manager_->ShowCursor(); |
| 205 } |
| 160 cursor_manager_->LockCursor(); | 206 cursor_manager_->LockCursor(); |
| 161 // SetCursor does not make any effects at this point but it sets back to | 207 // Set/ShowCursor does not make any effects at this point but it sets |
| 162 // the original cursor when unlocked. | 208 // back to the original cursor when unlocked. |
| 163 cursor_manager_->SetCursor(original_cursor); | 209 cursor_manager_->SetCursor(original_cursor); |
| 210 cursor_manager_->ShowCursor(); |
| 164 } | 211 } |
| 165 | 212 |
| 166 ~ScopedCursorSetter() { | 213 ~ScopedCursorSetter() { |
| 167 if (cursor_manager_) | 214 if (cursor_manager_) |
| 168 cursor_manager_->UnlockCursor(); | 215 cursor_manager_->UnlockCursor(); |
| 169 } | 216 } |
| 170 | 217 |
| 171 private: | 218 private: |
| 172 ::wm::CursorManager* cursor_manager_; | 219 ::wm::CursorManager* cursor_manager_; |
| 173 | 220 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 241 // It's already started. This can happen when the second finger touches | 288 // It's already started. This can happen when the second finger touches |
| 242 // the screen, or combination of the touch and mouse. We should grab the | 289 // the screen, or combination of the touch and mouse. We should grab the |
| 243 // partial screenshot instead of restarting. | 290 // partial screenshot instead of restarting. |
| 244 if (current_root == root_window_) { | 291 if (current_root == root_window_) { |
| 245 Update(event); | 292 Update(event); |
| 246 CompletePartialScreenshot(); | 293 CompletePartialScreenshot(); |
| 247 } | 294 } |
| 248 } else { | 295 } else { |
| 249 root_window_ = current_root; | 296 root_window_ = current_root; |
| 250 start_position_ = event.root_location(); | 297 start_position_ = event.root_location(); |
| 298 // ScopedCursorSetter must be reset first to make sure that its dtor is |
| 299 // called before ctor is called. |
| 300 cursor_setter_.reset(); |
| 301 cursor_setter_.reset(new ScopedCursorSetter( |
| 302 Shell::GetInstance()->cursor_manager(), ui::kCursorNone)); |
| 303 Update(event); |
| 251 } | 304 } |
| 252 } | 305 } |
| 253 | 306 |
| 254 void ScreenshotController::CompleteWindowScreenshot() { | 307 void ScreenshotController::CompleteWindowScreenshot() { |
| 255 if (selected_) | 308 if (selected_) |
| 256 screenshot_delegate_->HandleTakeWindowScreenshot(selected_); | 309 screenshot_delegate_->HandleTakeWindowScreenshot(selected_); |
| 257 Cancel(); | 310 Cancel(); |
| 258 } | 311 } |
| 259 | 312 |
| 260 void ScreenshotController::CompletePartialScreenshot() { | 313 void ScreenshotController::CompletePartialScreenshot() { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 287 STLDeleteValues(&layers_); | 340 STLDeleteValues(&layers_); |
| 288 cursor_setter_.reset(); | 341 cursor_setter_.reset(); |
| 289 EnableMouseWarp(true); | 342 EnableMouseWarp(true); |
| 290 } | 343 } |
| 291 | 344 |
| 292 void ScreenshotController::Update(const ui::LocatedEvent& event) { | 345 void ScreenshotController::Update(const ui::LocatedEvent& event) { |
| 293 // Update may happen without MaybeStart() if the partial screenshot session | 346 // Update may happen without MaybeStart() if the partial screenshot session |
| 294 // starts when dragging. | 347 // starts when dragging. |
| 295 if (!root_window_) | 348 if (!root_window_) |
| 296 MaybeStart(event); | 349 MaybeStart(event); |
| 350 DCHECK(layers_.find(root_window_) != layers_.end()); |
| 297 | 351 |
| 298 DCHECK(layers_.find(root_window_) != layers_.end()); | 352 ScreenshotLayer* layer = layers_.at(root_window_); |
| 299 layers_.at(root_window_) | 353 layer->set_cursor_location_in_root(event.root_location()); |
| 300 ->SetRegion( | 354 layer->SetRegion( |
| 301 gfx::Rect(std::min(start_position_.x(), event.root_location().x()), | 355 gfx::Rect(std::min(start_position_.x(), event.root_location().x()), |
| 302 std::min(start_position_.y(), event.root_location().y()), | 356 std::min(start_position_.y(), event.root_location().y()), |
| 303 ::abs(start_position_.x() - event.root_location().x()), | 357 ::abs(start_position_.x() - event.root_location().x()), |
| 304 ::abs(start_position_.y() - event.root_location().y()))); | 358 ::abs(start_position_.y() - event.root_location().y()))); |
| 305 } | 359 } |
| 306 | 360 |
| 307 void ScreenshotController::UpdateSelectedWindow(ui::LocatedEvent* event) { | 361 void ScreenshotController::UpdateSelectedWindow(ui::LocatedEvent* event) { |
| 308 aura::Window* selected = ScreenshotWindowTargeter().FindWindowForEvent(event); | 362 aura::Window* selected = ScreenshotWindowTargeter().FindWindowForEvent(event); |
| 309 | 363 |
| 310 // Find a window that is backed with a widget. | 364 // Find a window that is backed with a widget. |
| 311 while (selected && (selected->type() == ui::wm::WINDOW_TYPE_CONTROL || | 365 while (selected && (selected->type() == ui::wm::WINDOW_TYPE_CONTROL || |
| 312 !selected->delegate())) { | 366 !selected->delegate())) { |
| 313 selected = selected->parent(); | 367 selected = selected->parent(); |
| 314 } | 368 } |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 450 | 504 |
| 451 void ScreenshotController::OnDisplayMetricsChanged( | 505 void ScreenshotController::OnDisplayMetricsChanged( |
| 452 const display::Display& display, | 506 const display::Display& display, |
| 453 uint32_t changed_metrics) {} | 507 uint32_t changed_metrics) {} |
| 454 | 508 |
| 455 void ScreenshotController::OnWindowDestroying(aura::Window* window) { | 509 void ScreenshotController::OnWindowDestroying(aura::Window* window) { |
| 456 SetSelectedWindow(nullptr); | 510 SetSelectedWindow(nullptr); |
| 457 } | 511 } |
| 458 | 512 |
| 459 } // namespace ash | 513 } // namespace ash |
| OLD | NEW |