blob: 64409bd5b016a12c9b39a0af4120509f3dae9246 [file] [log] [blame]
// Copyright (c) 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_MEDIA_CAPTURE_CURSOR_RENDERER_H_
#define CONTENT_BROWSER_MEDIA_CAPTURE_CURSOR_RENDERER_H_
#include <atomic>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/synchronization/lock.h"
#include "base/timer/timer.h"
#include "content/common/content_export.h"
#include "media/base/video_frame.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/cursor/cursor.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_widget_types.h"
namespace content {
class CursorRendererUndoer;
// CursorRenderer is an abstract base class that handles all the
// non-platform-specific common cursor rendering functionality. In order to
// track the cursor, the platform-specific implementation will listen to
// mouse events and this base class will process them.
//
// All parts of this class are meant to run on the UI BrowserThread, except for
// RenderOnVideoFrame() and IsUserInteractingWithView(), which may be called
// from any thread. It is up to the client code to ensure the CursorRenderer's
// lifetime while in use across multiple threads.
class CONTENT_EXPORT CursorRenderer {
public:
// Setting to control cursor display based on either mouse movement or always
// forced to be enabled.
enum CursorDisplaySetting {
CURSOR_DISPLAYED_ALWAYS,
CURSOR_DISPLAYED_ON_MOUSE_MOVEMENT,
};
static std::unique_ptr<CursorRenderer> Create(CursorDisplaySetting display);
virtual ~CursorRenderer();
// Sets a new target view to monitor for mouse cursor updates.
virtual void SetTargetView(gfx::NativeView view) = 0;
// Renders cursor on the given video frame within the content region,
// returning true if |frame| was modified. |undoer| is optional: If provided,
// it will be updated with state necessary for later undoing the cursor
// rendering.
bool RenderOnVideoFrame(media::VideoFrame* frame,
const gfx::Rect& region_in_frame,
CursorRendererUndoer* undoer);
// Sets a callback that will be run whenever RenderOnVideoFrame() should be
// called soon, to update the mouse cursor location or image in the video.
void SetNeedsRedrawCallback(base::RepeatingClosure callback);
// Returns true if the user has recently interacted with the view.
bool IsUserInteractingWithView() const;
// Returns a weak pointer.
base::WeakPtr<CursorRenderer> GetWeakPtr();
protected:
enum {
// Minium movement before cursor has been considered intentionally moved by
// the user.
MIN_MOVEMENT_PIXELS = 15,
// Amount of time to elapse with no mouse activity before the cursor should
// stop showing in the video. Does not apply to CURSOR_DISPLAYED_ALWAYS
// mode, of course.
IDLE_TIMEOUT_SECONDS = 2
};
explicit CursorRenderer(CursorDisplaySetting display);
// Returns true if the captured view is a part of an active application
// window.
virtual bool IsCapturedViewActive() = 0;
// Returns the size of the captured view (view coordinates).
virtual gfx::Size GetCapturedViewSize() = 0;
// Returns the cursor's position within the captured view (view coordinates).
virtual gfx::Point GetCursorPositionInView() = 0;
// Returns the last-known mouse cursor.
virtual gfx::NativeCursor GetLastKnownCursor() = 0;
// Returns the image of the last-known mouse cursor and its hotspot.
virtual SkBitmap GetLastKnownCursorImage(gfx::Point* hot_point) = 0;
// Called by subclasses to report mouse events within the captured view.
void OnMouseMoved(const gfx::Point& location);
void OnMouseClicked(const gfx::Point& location);
// Called by the |mouse_activity_ended_timer_| once no mouse events have
// occurred for IDLE_TIMEOUT_SECONDS. Also, called by subclasses when changing
// the target view.
void OnMouseHasGoneIdle();
private:
friend class CursorRendererAuraTest;
friend class CursorRendererMacTest;
enum MouseMoveBehavior {
NOT_MOVING, // Mouse has not moved recently.
STARTING_TO_MOVE, // Mouse has moved, but not significantly.
RECENTLY_MOVED_OR_CLICKED, // Sufficient mouse activity present.
};
// Accessors for |mouse_move_behavior_atomic_|. See comments below.
MouseMoveBehavior mouse_move_behavior() const {
return mouse_move_behavior_atomic_.load(std::memory_order_relaxed);
}
void set_mouse_move_behavior(MouseMoveBehavior behavior) {
mouse_move_behavior_atomic_.store(behavior, std::memory_order_relaxed);
}
// Takes a snapshot of the current mouse cursor state, for use by
// RenderOnVideoFrame().
void SnapshotCursorState();
// Controls whether cursor is displayed based on active mouse movement.
const CursorDisplaySetting cursor_display_setting_;
// Protects members shared by RenderOnVideoFrame() and the rest of the class.
base::Lock lock_;
// These are updated by SnapshotCursorState(), then later read within
// RenderOnVideoFrame(). Access is protected by |lock_|.
gfx::Size view_size_; // Empty means "do not show mouse cursor."
gfx::Point cursor_position_;
gfx::NativeCursor cursor_;
gfx::Point cursor_hot_point_;
SkBitmap cursor_image_;
// Flag set to invalidate |scaled_cursor_bitmap_|.
bool update_scaled_cursor_bitmap_;
// A cache of the current scaled cursor bitmap. This is only accessed by the
// thread calling RenderOnVideoFrame().
SkBitmap scaled_cursor_bitmap_;
// Updated in the mouse event handlers and used to decide whether the user is
// interacting with the view and whether to run the |needs_redraw_callback_|.
// These do not need to be protected by |lock_| since they are only accessed
// on the UI BrowserThread.
gfx::Point mouse_move_start_location_;
base::OneShotTimer mouse_activity_ended_timer_;
// Updated in the mouse event handlers (on the UI BrowserThread) and read from
// by IsUserInteractingWithView() (on any thread). This is not protected by
// |lock_| since strict memory ordering semantics are not necessary, just
// atomicity between threads. All code should use the accessors to read or set
// this value.
std::atomic<MouseMoveBehavior> mouse_move_behavior_atomic_;
// Run whenever the mouse cursor would be rendered differently than when it
// was rendered in the last video frame.
base::RepeatingClosure needs_redraw_callback_;
// Everything except the constructor and RenderOnVideoFrame() must be called
// on the UI BrowserThread.
SEQUENCE_CHECKER(ui_sequence_checker_);
// RenderOnVideoFrame() must be called on the same thread each time.
SEQUENCE_CHECKER(render_sequence_checker_);
base::WeakPtrFactory<CursorRenderer> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(CursorRenderer);
};
// Restores the original content of a VideoFrame, to the point before cursor
// rendering modified it. See CursorRenderer::RenderOnVideoFrame().
class CONTENT_EXPORT CursorRendererUndoer {
public:
CursorRendererUndoer();
~CursorRendererUndoer();
CursorRendererUndoer(CursorRendererUndoer&& other) noexcept;
CursorRendererUndoer& operator=(CursorRendererUndoer&& other) noexcept;
void TakeSnapshot(const media::VideoFrame& frame, const gfx::Rect& rect);
// Restores the frame content to the point where TakeSnapshot() was last
// called.
void Undo(media::VideoFrame* frame) const;
private:
gfx::Rect rect_;
std::vector<uint8_t> snapshot_;
};
} // namespace content
#endif // CONTENT_BROWSER_MEDIA_CAPTURE_CURSOR_RENDERER_H_