Revert of Add button to add new FSP services to Files app. (patchset #8 id:140001...
[chromium-blink-merge.git] / ash / utility / partial_screenshot_controller.cc
blob76841a621bd6486693182f3cbdab3a830d39f30a
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
3 // found in the LICENSE file.
5 #include "ash/utility/partial_screenshot_controller.h"
7 #include <cmath>
9 #include "ash/screenshot_delegate.h"
10 #include "ash/shell.h"
11 #include "ash/shell_window_ids.h"
12 #include "base/stl_util.h"
13 #include "ui/events/event_handler.h"
14 #include "ui/gfx/canvas.h"
15 #include "ui/wm/core/cursor_manager.h"
17 namespace ash {
19 namespace {
21 // The size to increase the invalidated area in the layer to repaint. The area
22 // should be slightly bigger than the actual region because the region indicator
23 // rectangles are drawn outside of the selected region.
24 const int kInvalidateRegionAdditionalSize = 3;
26 } // namespace
28 class PartialScreenshotController::PartialScreenshotLayer
29 : public ui::LayerOwner,
30 public ui::LayerDelegate {
31 public:
32 PartialScreenshotLayer(ui::Layer* parent) {
33 SetLayer(new ui::Layer(ui::LAYER_TEXTURED));
34 layer()->SetFillsBoundsOpaquely(false);
35 layer()->SetBounds(parent->bounds());
36 parent->Add(layer());
37 parent->StackAtTop(layer());
38 layer()->SetVisible(true);
39 layer()->set_delegate(this);
41 ~PartialScreenshotLayer() override {}
43 const gfx::Rect& region() const { return region_; }
45 void SetRegion(const gfx::Rect& region) {
46 // Invalidates the region which covers the current and new region.
47 gfx::Rect union_rect(region_);
48 union_rect.Union(region);
49 union_rect.Inset(-kInvalidateRegionAdditionalSize,
50 -kInvalidateRegionAdditionalSize);
51 union_rect.Intersects(layer()->bounds());
53 region_ = region;
54 layer()->SchedulePaint(union_rect);
57 private:
58 // ui::LayerDelegate:
59 void OnPaintLayer(gfx::Canvas* canvas) override {
60 if (region_.IsEmpty())
61 return;
63 // Screenshot area representation: black rectangle with white
64 // rectangle inside. To avoid capturing these rectangles when mouse
65 // release, they should be outside of the actual capturing area.
66 gfx::Rect rect(region_);
67 rect.Inset(-1, -1);
68 canvas->DrawRect(rect, SK_ColorWHITE);
69 rect.Inset(-1, -1);
70 canvas->DrawRect(rect, SK_ColorBLACK);
73 void OnDelegatedFrameDamage(const gfx::Rect& damage_rect_in_dip) override {}
75 void OnDeviceScaleFactorChanged(float device_scale_factor) override {}
77 base::Closure PrepareForLayerBoundsChange() override {
78 return base::Closure();
81 gfx::Rect region_;
83 DISALLOW_COPY_AND_ASSIGN(PartialScreenshotLayer);
86 class PartialScreenshotController::ScopedCursorSetter {
87 public:
88 ScopedCursorSetter(::wm::CursorManager* cursor_manager,
89 gfx::NativeCursor cursor)
90 : cursor_manager_(nullptr) {
91 if (cursor_manager->IsCursorLocked())
92 return;
93 gfx::NativeCursor original_cursor = cursor_manager->GetCursor();
94 cursor_manager_ = cursor_manager;
95 cursor_manager_->SetCursor(cursor);
96 cursor_manager_->LockCursor();
97 // SetCursor does not make any effects at this point but it sets back to the
98 // original cursor when unlocked.
99 cursor_manager_->SetCursor(original_cursor);
102 ~ScopedCursorSetter() {
103 if (cursor_manager_)
104 cursor_manager_->UnlockCursor();
107 private:
108 ::wm::CursorManager* cursor_manager_;
110 DISALLOW_COPY_AND_ASSIGN(ScopedCursorSetter);
113 PartialScreenshotController::PartialScreenshotController()
114 : root_window_(nullptr), screenshot_delegate_(nullptr) {
115 Shell* shell = Shell::GetInstance();
116 shell->PrependPreTargetHandler(this);
119 PartialScreenshotController::~PartialScreenshotController() {
120 if (screenshot_delegate_)
121 Cancel();
122 Shell::GetInstance()->RemovePreTargetHandler(this);
125 void PartialScreenshotController::StartPartialScreenshotSession(
126 ScreenshotDelegate* screenshot_delegate) {
127 // Already in a screenshot session.
128 if (screenshot_delegate_) {
129 DCHECK_EQ(screenshot_delegate_, screenshot_delegate);
130 return;
133 screenshot_delegate_ = screenshot_delegate;
134 Shell::GetScreen()->AddObserver(this);
135 for (aura::Window* root : Shell::GetAllRootWindows()) {
136 layers_[root] = new PartialScreenshotLayer(
137 Shell::GetContainer(root, kShellWindowId_OverlayContainer)->layer());
140 cursor_setter_.reset(new ScopedCursorSetter(
141 Shell::GetInstance()->cursor_manager(), ui::kCursorCross));
144 void PartialScreenshotController::MaybeStart(const ui::LocatedEvent& event) {
145 aura::Window* current_root =
146 static_cast<aura::Window*>(event.target())->GetRootWindow();
147 if (root_window_) {
148 // It's already started. This can happen when the second finger touches
149 // the screen, or combination of the touch and mouse. We should grab the
150 // partial screenshot instead of restarting.
151 if (current_root == root_window_) {
152 Update(event);
153 Complete();
155 } else {
156 root_window_ = current_root;
157 start_position_ = event.root_location();
161 void PartialScreenshotController::Complete() {
162 const gfx::Rect& region = layers_[root_window_]->region();
163 if (!region.IsEmpty()) {
164 screenshot_delegate_->HandleTakePartialScreenshot(
165 root_window_, gfx::IntersectRects(root_window_->bounds(), region));
167 Cancel();
170 void PartialScreenshotController::Cancel() {
171 root_window_ = nullptr;
172 screenshot_delegate_ = nullptr;
173 Shell::GetScreen()->RemoveObserver(this);
174 STLDeleteValues(&layers_);
175 cursor_setter_.reset();
178 void PartialScreenshotController::Update(const ui::LocatedEvent& event) {
179 // Update may happen without MaybeStart() if the partial screenshot session
180 // starts when dragging.
181 if (!root_window_)
182 MaybeStart(event);
184 DCHECK(layers_.find(root_window_) != layers_.end());
185 layers_[root_window_]->SetRegion(
186 gfx::Rect(std::min(start_position_.x(), event.root_location().x()),
187 std::min(start_position_.y(), event.root_location().y()),
188 ::abs(start_position_.x() - event.root_location().x()),
189 ::abs(start_position_.y() - event.root_location().y())));
192 void PartialScreenshotController::OnKeyEvent(ui::KeyEvent* event) {
193 if (!screenshot_delegate_)
194 return;
195 if (event->type() == ui::ET_KEY_RELEASED &&
196 event->key_code() == ui::VKEY_ESCAPE) {
197 Cancel();
200 // Intercepts all key events.
201 event->StopPropagation();
204 void PartialScreenshotController::OnMouseEvent(ui::MouseEvent* event) {
205 if (!screenshot_delegate_)
206 return;
207 switch (event->type()) {
208 case ui::ET_MOUSE_PRESSED:
209 MaybeStart(*event);
210 break;
211 case ui::ET_MOUSE_DRAGGED:
212 Update(*event);
213 break;
214 case ui::ET_MOUSE_RELEASED:
215 Complete();
216 break;
217 default:
218 // Do nothing.
219 break;
221 event->StopPropagation();
224 void PartialScreenshotController::OnTouchEvent(ui::TouchEvent* event) {
225 if (!screenshot_delegate_)
226 return;
227 switch (event->type()) {
228 case ui::ET_TOUCH_PRESSED:
229 MaybeStart(*event);
230 break;
231 case ui::ET_TOUCH_MOVED:
232 Update(*event);
233 break;
234 case ui::ET_TOUCH_RELEASED:
235 Complete();
236 break;
237 default:
238 // Do nothing.
239 break;
241 event->StopPropagation();
244 void PartialScreenshotController::OnDisplayAdded(
245 const gfx::Display& new_display) {
246 if (!screenshot_delegate_)
247 return;
248 Cancel();
251 void PartialScreenshotController::OnDisplayRemoved(
252 const gfx::Display& old_display) {
253 if (!screenshot_delegate_)
254 return;
255 Cancel();
258 void PartialScreenshotController::OnDisplayMetricsChanged(
259 const gfx::Display& display,
260 uint32_t changed_metrics) {
263 } // namespace ash