Commit d560e5cf authored by Ahmed Fakhry's avatar Ahmed Fakhry Committed by Commit Bot

capture_mode: More capture session work

This CL fills in more impl of the capture session:
- Paints the capture region according to the current selected
  source.
- Add support for event handling.
- Pressing ESC dismisses the session, while ENTER performs
  the capture and dismisses the session.

BUG=1116137
TEST=Manual

Change-Id: Ic86fd1230dea04d8d59ed19cbf7455e70d0a7795
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2354567Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Commit-Queue: Ahmed Fakhry <afakhry@chromium.org>
Cr-Commit-Position: refs/heads/master@{#798276}
parent 86ac7381
...@@ -63,13 +63,19 @@ void CaptureModeController::Start() { ...@@ -63,13 +63,19 @@ void CaptureModeController::Start() {
// TODO(afakhry): Use root window of the mouse cursor or the one for new // TODO(afakhry): Use root window of the mouse cursor or the one for new
// windows. // windows.
capture_mode_session_ = capture_mode_session_ =
std::make_unique<CaptureModeSession>(Shell::GetPrimaryRootWindow()); std::make_unique<CaptureModeSession>(this, Shell::GetPrimaryRootWindow());
} }
void CaptureModeController::Stop() { void CaptureModeController::Stop() {
capture_mode_session_.reset(); capture_mode_session_.reset();
} }
void CaptureModeController::PerformCapture() {
DCHECK(IsActive());
// TODO(afakhry): Fill in here.
Stop();
}
void CaptureModeController::EndVideoRecording() { void CaptureModeController::EndVideoRecording() {
// TODO(afakhry): Fill in here. // TODO(afakhry): Fill in here.
} }
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "ash/capture_mode/capture_mode_types.h" #include "ash/capture_mode/capture_mode_types.h"
#include "ash/public/cpp/capture_mode_delegate.h" #include "ash/public/cpp/capture_mode_delegate.h"
#include "ui/gfx/geometry/rect.h"
namespace ash { namespace ash {
...@@ -32,6 +33,10 @@ class ASH_EXPORT CaptureModeController { ...@@ -32,6 +33,10 @@ class ASH_EXPORT CaptureModeController {
CaptureModeSession* capture_mode_session() const { CaptureModeSession* capture_mode_session() const {
return capture_mode_session_.get(); return capture_mode_session_.get();
} }
gfx::Rect user_capture_region() const { return user_capture_region_; }
void set_user_capture_region(const gfx::Rect& region) {
user_capture_region_ = region;
}
// Returns true if a capture mode session is currently active. // Returns true if a capture mode session is currently active.
bool IsActive() const { return !!capture_mode_session_; } bool IsActive() const { return !!capture_mode_session_; }
...@@ -48,6 +53,11 @@ class ASH_EXPORT CaptureModeController { ...@@ -48,6 +53,11 @@ class ASH_EXPORT CaptureModeController {
// Stops an existing capture session. // Stops an existing capture session.
void Stop(); void Stop();
// Called only while a capture session is in progress to perform the actual
// capture depending on the current selected |source_| and |type_|, and ends
// the capture session.
void PerformCapture();
void EndVideoRecording(); void EndVideoRecording();
private: private:
...@@ -56,6 +66,11 @@ class ASH_EXPORT CaptureModeController { ...@@ -56,6 +66,11 @@ class ASH_EXPORT CaptureModeController {
CaptureModeType type_ = CaptureModeType::kImage; CaptureModeType type_ = CaptureModeType::kImage;
CaptureModeSource source_ = CaptureModeSource::kRegion; CaptureModeSource source_ = CaptureModeSource::kRegion;
// We remember the user selected capture region when the source is |kRegion|
// between sessions. Initially, this value is empty at which point we display
// a message to the user instructing them to start selecting a region.
gfx::Rect user_capture_region_;
std::unique_ptr<CaptureModeSession> capture_mode_session_; std::unique_ptr<CaptureModeSession> capture_mode_session_;
}; };
......
...@@ -4,23 +4,74 @@ ...@@ -4,23 +4,74 @@
#include "ash/capture_mode/capture_mode_session.h" #include "ash/capture_mode/capture_mode_session.h"
#include <memory>
#include "ash/capture_mode/capture_mode_bar_view.h" #include "ash/capture_mode/capture_mode_bar_view.h"
#include "ash/capture_mode/capture_mode_controller.h"
#include "ash/display/mouse_cursor_event_filter.h"
#include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/shell_window_ids.h"
#include "ash/shell.h"
#include "ash/style/ash_color_provider.h"
#include "ash/wm/mru_window_tracker.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_type.h"
#include "ui/compositor/paint_recorder.h"
#include "ui/events/types/event_type.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/scoped_canvas.h"
namespace ash { namespace ash {
CaptureModeSession::CaptureModeSession(aura::Window* root) namespace {
: capture_mode_bar_view_(new CaptureModeBarView()) {
constexpr int kBorderStrokePx = 2;
// Blue300 at 30%.
constexpr SkColor kCaptureRegionColor = SkColorSetA(gfx::kGoogleBlue300, 77);
// Mouse cursor warping is disabled when the capture source is a custom region.
// Sets the mouse warp status to |enable| and return the original value.
bool SetMouseWarpEnabled(bool enable) {
auto* mouse_cursor_filter = Shell::Get()->mouse_cursor_filter();
const bool old_value = mouse_cursor_filter->mouse_warp_enabled();
mouse_cursor_filter->set_mouse_warp_enabled(enable);
return old_value;
}
// Gets the overlay container inside |root|.
aura::Window* GetParentContainer(aura::Window* root) {
DCHECK(root); DCHECK(root);
DCHECK(root->IsRootWindow()); DCHECK(root->IsRootWindow());
return root->GetChildById(kShellWindowId_OverlayContainer);
}
} // namespace
CaptureModeSession::CaptureModeSession(CaptureModeController* controller,
aura::Window* root)
: controller_(controller),
current_root_(root),
capture_mode_bar_view_(new CaptureModeBarView()),
old_mouse_warp_status_(SetMouseWarpEnabled(controller_->source() !=
CaptureModeSource::kRegion)) {
Shell::Get()->AddPreTargetHandler(this);
SetLayer(std::make_unique<ui::Layer>(ui::LAYER_TEXTURED));
layer()->SetFillsBoundsOpaquely(false);
layer()->set_delegate(this);
auto* parent = GetParentContainer(current_root_);
parent->layer()->Add(layer());
layer()->SetBounds(parent->bounds());
views::Widget::InitParams params( views::Widget::InitParams params(
views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); views::Widget::InitParams::TYPE_WINDOW_FRAMELESS);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET; params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent; params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
params.parent = root->GetChildById(kShellWindowId_OverlayContainer); params.parent = parent;
params.bounds = CaptureModeBarView::GetBounds(root); params.bounds = CaptureModeBarView::GetBounds(root);
params.name = "CaptureModeBarWidget"; params.name = "CaptureModeBarWidget";
...@@ -28,16 +79,128 @@ CaptureModeSession::CaptureModeSession(aura::Window* root) ...@@ -28,16 +79,128 @@ CaptureModeSession::CaptureModeSession(aura::Window* root)
capture_mode_bar_widget_.SetContentsView( capture_mode_bar_widget_.SetContentsView(
base::WrapUnique(capture_mode_bar_view_)); base::WrapUnique(capture_mode_bar_view_));
capture_mode_bar_widget_.Show(); capture_mode_bar_widget_.Show();
RefreshStackingOrder(parent);
} }
CaptureModeSession::~CaptureModeSession() = default; CaptureModeSession::~CaptureModeSession() {
Shell::Get()->RemovePreTargetHandler(this);
SetMouseWarpEnabled(old_mouse_warp_status_);
}
void CaptureModeSession::OnCaptureSourceChanged(CaptureModeSource new_source) { void CaptureModeSession::OnCaptureSourceChanged(CaptureModeSource new_source) {
capture_mode_bar_view_->OnCaptureSourceChanged(new_source); capture_mode_bar_view_->OnCaptureSourceChanged(new_source);
SetMouseWarpEnabled(new_source != CaptureModeSource::kRegion);
layer()->SchedulePaint(layer()->bounds());
} }
void CaptureModeSession::OnCaptureTypeChanged(CaptureModeType new_type) { void CaptureModeSession::OnCaptureTypeChanged(CaptureModeType new_type) {
capture_mode_bar_view_->OnCaptureTypeChanged(new_type); capture_mode_bar_view_->OnCaptureTypeChanged(new_type);
} }
void CaptureModeSession::OnPaintLayer(const ui::PaintContext& context) {
ui::PaintRecorder recorder(context, layer()->size());
auto* color_provider = AshColorProvider::Get();
const SkColor dimming_color = color_provider->GetShieldLayerColor(
AshColorProvider::ShieldLayerType::kShield40,
AshColorProvider::AshColorMode::kDark);
recorder.canvas()->DrawColor(dimming_color);
PaintCaptureRegion(recorder.canvas());
}
void CaptureModeSession::OnKeyEvent(ui::KeyEvent* event) {
if (event->type() != ui::ET_KEY_PRESSED)
return;
if (event->key_code() == ui::VKEY_ESCAPE) {
event->StopPropagation();
controller_->Stop(); // |this| is destroyed here.
return;
}
if (event->key_code() == ui::VKEY_RETURN) {
event->StopPropagation();
controller_->PerformCapture(); // |this| is destroyed here.
return;
}
}
void CaptureModeSession::OnMouseEvent(ui::MouseEvent* event) {
// TODO(afakhry): Fill in here.
}
void CaptureModeSession::OnTouchEvent(ui::TouchEvent* event) {
// TODO(afakhry): Fill in here.
}
gfx::Rect CaptureModeSession::GetSelectedWindowBounds() const {
// Note that the capture bar widget is activatable, so we can't use
// window_util::GetActiveWindow(). Instead, we use the MRU window tracker and
// get the top-most window if any.
auto mru_windows =
Shell::Get()->mru_window_tracker()->BuildMruWindowList(kActiveDesk);
if (!mru_windows.empty())
return mru_windows[0]->bounds();
return gfx::Rect();
}
void CaptureModeSession::RefreshStackingOrder(aura::Window* parent_container) {
DCHECK(parent_container);
auto* widget_layer = capture_mode_bar_widget_.GetNativeWindow()->layer();
auto* overlay_layer = layer();
auto* parent_container_layer = parent_container->layer();
DCHECK_EQ(parent_container_layer, overlay_layer->parent());
DCHECK_EQ(parent_container_layer, widget_layer->parent());
parent_container_layer->StackAtTop(overlay_layer);
parent_container_layer->StackAtTop(widget_layer);
}
void CaptureModeSession::PaintCaptureRegion(gfx::Canvas* canvas) {
gfx::Rect region;
bool adjustable_region = false;
switch (controller_->source()) {
case CaptureModeSource::kFullscreen:
region = current_root_->bounds();
break;
case CaptureModeSource::kWindow:
region = GetSelectedWindowBounds();
break;
case CaptureModeSource::kRegion:
region = controller_->user_capture_region();
adjustable_region = true;
break;
}
if (region.IsEmpty())
return;
gfx::ScopedCanvas scoped_canvas(canvas);
const float dsf = canvas->UndoDeviceScaleFactor();
region = gfx::ScaleToEnclosingRect(region, dsf);
canvas->FillRect(region, SK_ColorBLACK, SkBlendMode::kClear);
canvas->FillRect(region, kCaptureRegionColor);
if (!adjustable_region)
return;
// TODO(afakhry): For adjustable regions, we may change the colors. Also,
// paint the drag points at the corners.
region.Inset(-kBorderStrokePx, -kBorderStrokePx);
cc::PaintFlags flags;
flags.setAntiAlias(true);
flags.setStyle(cc::PaintFlags::kStroke_Style);
// TODO(afakhry): Update to match the specs.
flags.setColor(gfx::kGoogleBlue200);
flags.setStrokeWidth(SkIntToScalar(kBorderStrokePx));
canvas->DrawRect(region, flags);
}
} // namespace ash } // namespace ash
...@@ -6,22 +6,37 @@ ...@@ -6,22 +6,37 @@
#define ASH_CAPTURE_MODE_CAPTURE_MODE_SESSION_H_ #define ASH_CAPTURE_MODE_CAPTURE_MODE_SESSION_H_
#include "ash/ash_export.h" #include "ash/ash_export.h"
#include "ash/capture_mode/capture_mode_bar_view.h"
#include "ash/capture_mode/capture_mode_types.h" #include "ash/capture_mode/capture_mode_types.h"
#include "ui/compositor/layer_delegate.h"
#include "ui/compositor/layer_owner.h"
#include "ui/events/event_handler.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
namespace gfx {
class Canvas;
} // namespace gfx
namespace ash { namespace ash {
class CaptureModeBarView;
class CaptureModeController;
// Encapsulates an active capture mode session (i.e. an instance of this class // Encapsulates an active capture mode session (i.e. an instance of this class
// lives as long as capture mode is active). It creates and owns the capture // lives as long as capture mode is active). It creates and owns the capture
// mode bar widget. // mode bar widget.
class ASH_EXPORT CaptureModeSession { // The CaptureModeSession is a LayerOwner that owns a texture layer placed right
// beneath the layer of the bar widget. This layer is used to paint a dimming
// shield of the areas that won't be captured, and another bright region showing
// the one that will be.
class ASH_EXPORT CaptureModeSession : public ui::LayerOwner,
public ui::LayerDelegate,
public ui::EventHandler {
public: public:
// Creates the bar widget on the given |root| window. // Creates the bar widget on the given |root| window.
explicit CaptureModeSession(aura::Window* root); CaptureModeSession(CaptureModeController* controller, aura::Window* root);
CaptureModeSession(const CaptureModeSession&) = delete; CaptureModeSession(const CaptureModeSession&) = delete;
CaptureModeSession& operator=(const CaptureModeSession&) = delete; CaptureModeSession& operator=(const CaptureModeSession&) = delete;
~CaptureModeSession(); ~CaptureModeSession() override;
CaptureModeBarView* capture_mode_bar_view() const { CaptureModeBarView* capture_mode_bar_view() const {
return capture_mode_bar_view_; return capture_mode_bar_view_;
...@@ -31,11 +46,42 @@ class ASH_EXPORT CaptureModeSession { ...@@ -31,11 +46,42 @@ class ASH_EXPORT CaptureModeSession {
void OnCaptureSourceChanged(CaptureModeSource new_source); void OnCaptureSourceChanged(CaptureModeSource new_source);
void OnCaptureTypeChanged(CaptureModeType new_type); void OnCaptureTypeChanged(CaptureModeType new_type);
// ui::LayerDelegate:
void OnPaintLayer(const ui::PaintContext& context) override;
void OnDeviceScaleFactorChanged(float old_device_scale_factor,
float new_device_scale_factor) override {}
// ui::EventHandler:
void OnKeyEvent(ui::KeyEvent* event) override;
void OnMouseEvent(ui::MouseEvent* event) override;
void OnTouchEvent(ui::TouchEvent* event) override;
private: private:
// Gets the current window selected for |kWindow| capture source.
gfx::Rect GetSelectedWindowBounds() const;
// Ensures that the bar widget is on top of everything, and the overlay (which
// is the |layer()| of this class that paints the capture region) is stacked
// right below the bar.
void RefreshStackingOrder(aura::Window* parent_container);
// Paints the current capture region depending on the current capture source.
void PaintCaptureRegion(gfx::Canvas* canvas);
CaptureModeController* const controller_;
// The current root window on which the capture session is active, which may
// change if the user warps the cursor to another display in some situations.
aura::Window* current_root_;
views::Widget capture_mode_bar_widget_; views::Widget capture_mode_bar_widget_;
// The content view of the above widget and owned by its views hierarchy. // The content view of the above widget and owned by its views hierarchy.
CaptureModeBarView* capture_mode_bar_view_; CaptureModeBarView* capture_mode_bar_view_;
// Caches the old status of mouse warping before the session started to be
// restored at the end.
bool old_mouse_warp_status_;
}; };
} // namespace ash } // namespace ash
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "ash/capture_mode/capture_mode_bar_view.h"
#include "ash/capture_mode/capture_mode_close_button.h" #include "ash/capture_mode/capture_mode_close_button.h"
#include "ash/capture_mode/capture_mode_controller.h" #include "ash/capture_mode/capture_mode_controller.h"
#include "ash/capture_mode/capture_mode_session.h" #include "ash/capture_mode/capture_mode_session.h"
......
...@@ -32,6 +32,7 @@ class ASH_EXPORT MouseCursorEventFilter ...@@ -32,6 +32,7 @@ class ASH_EXPORT MouseCursorEventFilter
MouseCursorEventFilter(); MouseCursorEventFilter();
~MouseCursorEventFilter() override; ~MouseCursorEventFilter() override;
bool mouse_warp_enabled() const { return mouse_warp_enabled_; }
void set_mouse_warp_enabled(bool enabled) { mouse_warp_enabled_ = enabled; } void set_mouse_warp_enabled(bool enabled) { mouse_warp_enabled_ = enabled; }
// Shows/Hide the indicator for window dragging. The |from| // Shows/Hide the indicator for window dragging. The |from|
......
...@@ -617,6 +617,10 @@ Shell::~Shell() { ...@@ -617,6 +617,10 @@ Shell::~Shell() {
if (window_modality_controller_) if (window_modality_controller_)
window_modality_controller_.reset(); window_modality_controller_.reset();
// We may shutdown while a capture session is active, which is an event
// handler that depends on this shell and some of its members. Destroy early.
capture_mode_controller_.reset();
RemovePreTargetHandler(magnifier_key_scroll_handler_.get()); RemovePreTargetHandler(magnifier_key_scroll_handler_.get());
magnifier_key_scroll_handler_.reset(); magnifier_key_scroll_handler_.reset();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment