910e62b5创建于 1月15日历史提交
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_DEVTOOLS_PROTOCOL_INPUT_HANDLER_H_
#define CONTENT_BROWSER_DEVTOOLS_PROTOCOL_INPUT_HANDLER_H_

#include <memory>
#include <set>
#include <string>
#include <vector>

#include "base/containers/flat_map.h"
#include "base/containers/flat_set.h"
#include "base/containers/unique_ptr_adapters.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/raw_ref.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/devtools/protocol/devtools_domain_handler.h"
#include "content/browser/devtools/protocol/input.h"
#include "content/browser/renderer_host/render_widget_host_view_base.h"
#include "content/common/input/synthetic_gesture.h"
#include "content/common/input/synthetic_pointer_action_list_params.h"
#include "content/common/input/synthetic_smooth_scroll_gesture_params.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/web_contents.h"
#include "third_party/blink/public/common/input/pointer_id.h"
#include "third_party/blink/public/common/input/web_input_event.h"
#include "third_party/blink/public/common/input/web_mouse_event.h"
#include "third_party/blink/public/mojom/page/widget.mojom.h"

namespace content {
class DevToolsAgentHostImpl;
class RenderFrameHostImpl;
class RenderWidgetHostImpl;
class SyntheticPointerDriver;
class WebContentsImpl;

namespace protocol {

template <class BackendCallback>
class FailSafe;

class InputHandler : public DevToolsDomainHandler, public Input::Backend {
 public:
  InputHandler(bool allow_file_access, bool allow_sending_input_to_browser);

  InputHandler(const InputHandler&) = delete;
  InputHandler& operator=(const InputHandler&) = delete;

  ~InputHandler() override;

  static std::vector<InputHandler*> ForAgentHost(DevToolsAgentHostImpl* host);

  void Wire(UberDispatcher* dispatcher) override;
  void SetRenderer(int process_host_id,
                   RenderFrameHostImpl* frame_host) override;

  // StartDragging is used to inform CDP's InputHandler to start dragging. This
  // gets called whenever the renderer tells the content layer to initiate
  // dragging (see RenderWidgetHostImpl::StartDragging)
  void StartDragging(const DropData& drop_data,
                     const blink::mojom::DragData& drag_data,
                     blink::DragOperationsMask drag_operations_mask,
                     bool* intercepted);
  // DragEnded is used to inform CDP's InputHandler when a drag has ended. This
  // gets called whenever the Drag n' Drop APIs that end dragging get called
  // (all of which exist in RenderWidgetHostImpl).
  //
  // This function ensures the drag state of Chromium is in-sync no matter the
  // source of the drag end.
  //
  // In theory, if OS drag gets initiated, then this function gets called when
  // the OS drag ends. This can happen if some starts and ends a drag with the
  // OS manually before starting to use CDP. In practice, this doesn't occur.
  void DragEnded();

  Response Disable() override;

  void DispatchKeyEvent(
      const std::string& type,
      std::optional<int> modifiers,
      std::optional<double> timestamp,
      std::optional<std::string> text,
      std::optional<std::string> unmodified_text,
      std::optional<std::string> key_identifier,
      std::optional<std::string> code,
      std::optional<std::string> key,
      std::optional<int> windows_virtual_key_code,
      std::optional<int> native_virtual_key_code,
      std::optional<bool> auto_repeat,
      std::optional<bool> is_keypad,
      std::optional<bool> is_system_key,
      std::optional<int> location,
      std::unique_ptr<Array<std::string>> commands,
      std::unique_ptr<DispatchKeyEventCallback> callback) override;

  void InsertText(const std::string& text,
                  std::unique_ptr<InsertTextCallback> callback) override;

  void ImeSetComposition(
      const std::string& text,
      int selection_start,
      int selection_end,
      std::optional<int> replacement_start,
      std::optional<int> replacement_end,
      std::unique_ptr<ImeSetCompositionCallback> callback) override;

  void DispatchMouseEvent(
      const std::string& event_type,
      double x,
      double y,
      std::optional<int> modifiers,
      std::optional<double> timestamp,
      std::optional<std::string> button,
      std::optional<int> buttons,
      std::optional<int> click_count,
      std::optional<double> force,
      std::optional<double> tangential_pressure,
      std::optional<double> tilt_x,
      std::optional<double> tilt_y,
      std::optional<int> twist,
      std::optional<double> delta_x,
      std::optional<double> delta_y,
      std::optional<std::string> pointer_type,
      std::unique_ptr<DispatchMouseEventCallback> callback) override;

  void DispatchDragEvent(
      const std::string& event_type,
      double x,
      double y,
      std::unique_ptr<Input::DragData> data,
      std::optional<int> modifiers,
      std::unique_ptr<DispatchDragEventCallback> callback) override;

  void DispatchTouchEvent(
      const std::string& type,
      std::unique_ptr<Array<Input::TouchPoint>> touch_points,
      std::optional<int> modifiers,
      std::optional<double> timestamp,
      std::unique_ptr<DispatchTouchEventCallback> callback) override;

  void CancelDragging(
      std::unique_ptr<CancelDraggingCallback> callback) override;

  Response EmulateTouchFromMouseEvent(const std::string& type,
                                      int x,
                                      int y,
                                      const std::string& button,
                                      std::optional<double> timestamp,
                                      std::optional<double> delta_x,
                                      std::optional<double> delta_y,
                                      std::optional<int> modifiers,
                                      std::optional<int> click_count) override;

  Response SetIgnoreInputEvents(bool ignore) override;
  Response SetInterceptDrags(bool enabled) override;

  void SynthesizePinchGesture(
      double x,
      double y,
      double scale_factor,
      std::optional<int> relative_speed,
      std::optional<std::string> gesture_source_type,
      std::unique_ptr<SynthesizePinchGestureCallback> callback) override;

  void SynthesizeScrollGesture(
      double x,
      double y,
      std::optional<double> x_distance,
      std::optional<double> y_distance,
      std::optional<double> x_overscroll,
      std::optional<double> y_overscroll,
      std::optional<bool> prevent_fling,
      std::optional<int> speed,
      std::optional<std::string> gesture_source_type,
      std::optional<int> repeat_count,
      std::optional<int> repeat_delay_ms,
      std::optional<std::string> interaction_marker_name,
      std::unique_ptr<SynthesizeScrollGestureCallback> callback) override;

  void SynthesizeTapGesture(
      double x,
      double y,
      std::optional<int> duration,
      std::optional<int> tap_count,
      std::optional<std::string> gesture_source_type,
      std::unique_ptr<SynthesizeTapGestureCallback> callback) override;

 private:
  class InputInjector;
  class DragController {
   public:
    // `handler` must live as long as the drag controller.
    explicit DragController(InputHandler& handler);
    ~DragController();

    DragController(const DragController&) = delete;
    DragController& operator=(const DragController&) = delete;

    // Returns `true` if the drag controller handles the mouse event. All
    // arguments will be moved in this case.
    bool HandleMouseEvent(
        RenderWidgetHostImpl& host,
        const blink::WebMouseEvent& event,
        std::unique_ptr<DispatchMouseEventCallback>& callback);

    // You should call this whenever dragging needs to be cancelled (perhaps an
    // invalid state or desired by the user).
    void CancelDragging(base::OnceClosure callback);

    // Returns `true` if we are currently dragging.
    bool IsDragging() { return !!drag_state_; }

   private:
    struct DragState;
    struct InitialState;

    friend void InputHandler::StartDragging(
        const DropData& drop_data,
        const blink::mojom::DragData& drag_data,
        blink::DragOperationsMask drag_operations_mask,
        bool* intercepted);
    friend void InputHandler::DragEnded();

    void EnsureDraggingEntered(RenderWidgetHostImpl& host,
                               const blink::WebMouseEvent& event);

    // Called by the input handler to start a dragging session.
    void StartDragging(const content::DropData& drop_data,
                       blink::DragOperationsMask drag_operations_mask);

    // Updates the drag with the given mouse event.
    //
    // `callback` may be null.
    void UpdateDragging(
        RenderWidgetHostImpl& host,
        std::unique_ptr<blink::WebMouseEvent> event,
        std::unique_ptr<FailSafe<DispatchMouseEventCallback>> callback);
    void DragUpdated(
        std::unique_ptr<blink::WebMouseEvent> event,
        std::unique_ptr<FailSafe<DispatchMouseEventCallback>> callback,
        ui::mojom::DragOperation operation,
        bool document_is_handling_drag);

    // Ends the drag with the given event and host.
    //
    // Note only the modifiers for the event are really used here, so it's
    // expected you've updated the drag with the latest info (e.g. position)
    // excluding modifiers. This ensures the drag event sequence is semantically
    // correct. The event itself is still needed in case dragging suddenly stops
    // for external reasons and we need to reschedule it.
    //
    // Also note the host is only used if there are no updates ongoing.
    // Otherwise, it's a nullptr. This is an optimization.
    void EndDragging(
        RenderWidgetHostImpl* host,
        std::unique_ptr<blink::WebMouseEvent> event,
        std::unique_ptr<FailSafe<DispatchMouseEventCallback>> callback);
    void EndDraggingWithRenderWidgetHostAtPoint(
        std::unique_ptr<blink::WebMouseEvent> event,
        std::unique_ptr<FailSafe<DispatchMouseEventCallback>> callback,
        base::WeakPtr<RenderWidgetHostViewBase> view,
        std::optional<gfx::PointF> maybe_point);

    const raw_ref<InputHandler> handler_;

    // These get used for starting a drag.
    std::unique_ptr<InitialState> initial_state_;

    std::unique_ptr<DragState> drag_state_;

    base::WeakPtrFactory<DragController> weak_factory_{this};
  };

  void DispatchWebTouchEvent(
      const std::string& type,
      std::unique_ptr<Array<Input::TouchPoint>> touch_points,
      std::optional<int> modifiers,
      std::optional<double> timestamp,
      std::unique_ptr<DispatchTouchEventCallback> callback);

  void DispatchSyntheticPointerActionTouch(
      const std::string& type,
      std::unique_ptr<Array<Input::TouchPoint>> touch_points,
      std::optional<int> modifiers,
      std::optional<double> timestamp,
      std::unique_ptr<DispatchTouchEventCallback> callback);

  void OnWidgetForDispatchMouseEvent(
      std::unique_ptr<DispatchMouseEventCallback> callback,
      std::unique_ptr<blink::WebMouseEvent> mouse_event,
      base::WeakPtr<RenderWidgetHostViewBase> target,
      std::optional<gfx::PointF> point);

  void OnWidgetForDispatchDragEvent(
      const std::string& event_type,
      double x,
      double y,
      std::unique_ptr<Input::DragData> data,
      std::optional<int> modifiers,
      std::unique_ptr<DispatchDragEventCallback> callback,
      base::WeakPtr<RenderWidgetHostViewBase> target,
      std::optional<gfx::PointF> point);

  void OnWidgetForDispatchWebTouchEvent(
      std::unique_ptr<DispatchTouchEventCallback> callback,
      std::vector<blink::WebTouchEvent> events,
      base::WeakPtr<RenderWidgetHostViewBase> target,
      std::optional<gfx::PointF> point);

  SyntheticPointerActionParams PrepareSyntheticPointerActionParams(
      SyntheticPointerActionParams::PointerActionType pointer_action_type,
      int id,
      double x,
      double y,
      int key_modifiers,
      float radius_x = 1.f,
      float radius_y = 1.f,
      float rotation_angle = 0.f,
      float force = 1.f);

  void SynthesizeRepeatingScroll(
      SyntheticSmoothScrollGestureParams gesture_params,
      int repeat_count,
      base::TimeDelta repeat_delay,
      std::string interaction_marker_name,
      int id,
      std::unique_ptr<SynthesizeScrollGestureCallback> callback);

  void OnScrollFinished(
      SyntheticSmoothScrollGestureParams gesture_params,
      int repeat_count,
      base::TimeDelta repeat_delay,
      std::string interaction_marker_name,
      int id,
      std::unique_ptr<SynthesizeScrollGestureCallback> callback,
      SyntheticGesture::Result result);

  void HandleMouseEvent(std::unique_ptr<blink::WebMouseEvent> event,
                        std::unique_ptr<DispatchMouseEventCallback> callback);

  void ClearInputState();
  bool PointIsWithinContents(gfx::PointF point) const;
  InputInjector* EnsureInjector(RenderWidgetHostImpl* widget_host);

  RenderWidgetHostViewBase* GetRootView();

  float ScaleFactor();

  raw_ptr<RenderFrameHostImpl> host_ = nullptr;
  // WebContents associated with the |host_|.
  raw_ptr<WebContentsImpl> web_contents_ = nullptr;
  std::unique_ptr<Input::Frontend> frontend_;
  base::flat_set<std::unique_ptr<InputInjector>, base::UniquePtrComparator>
      injectors_;
  int last_id_ = 0;
  bool ignore_input_events_ = false;
  std::optional<content::WebContents::ScopedIgnoreInputEvents>
      scoped_ignore_input_events_;
  bool intercept_drags_ = false;
  DragController drag_controller_;
  const bool allow_file_access_;
  const bool allow_sending_input_to_browser_ = false;
  std::set<int> pointer_ids_;
  std::unique_ptr<SyntheticPointerDriver> synthetic_pointer_driver_;
  base::flat_map<blink::PointerId, blink::WebTouchPoint> touch_points_;
  base::WeakPtrFactory<InputHandler> weak_factory_{this};
};

}  // namespace protocol
}  // namespace content

#endif  // CONTENT_BROWSER_DEVTOOLS_PROTOCOL_INPUT_HANDLER_H_