blob: c2fa006bbc08e74d078c8d2be36a3a2bba4907b0 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_INPUT_RENDER_WIDGET_TARGETER_H_
#define COMPONENTS_INPUT_RENDER_WIDGET_TARGETER_H_
#include <stdint.h>
#include <optional>
#include <queue>
#include "base/component_export.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/input/render_widget_host_view_input.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "ui/events/blink/web_input_event_traits.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/latency/latency_info.h"
namespace blink {
class WebInputEvent;
} // namespace blink
namespace gfx {
class PointF;
}
namespace input {
class RenderWidgetHostViewInput;
struct COMPONENT_EXPORT(INPUT) RenderWidgetTargetResult {
RenderWidgetTargetResult();
RenderWidgetTargetResult(const RenderWidgetTargetResult&);
RenderWidgetTargetResult(RenderWidgetHostViewInput* view,
bool should_query_view,
std::optional<gfx::PointF> location);
~RenderWidgetTargetResult();
raw_ptr<RenderWidgetHostViewInput, DanglingUntriaged> view = nullptr;
bool should_query_view = false;
std::optional<gfx::PointF> target_location = std::nullopt;
};
class RenderWidgetTargeter {
public:
using RenderWidgetHostAtPointCallback =
base::OnceCallback<void(base::WeakPtr<RenderWidgetHostViewInput>,
std::optional<gfx::PointF>)>;
class Delegate {
public:
virtual ~Delegate() = default;
virtual RenderWidgetTargetResult FindTargetSynchronouslyAtPoint(
RenderWidgetHostViewInput* root_view,
const gfx::PointF& location) = 0;
virtual RenderWidgetTargetResult FindTargetSynchronously(
RenderWidgetHostViewInput* root_view,
const blink::WebInputEvent& event) = 0;
// |event| must be non-null, and is in |root_view|'s coordinate space.
virtual void DispatchEventToTarget(
RenderWidgetHostViewInput* root_view,
RenderWidgetHostViewInput* target,
blink::WebInputEvent* event,
const ui::LatencyInfo& latency,
const std::optional<gfx::PointF>& target_location) = 0;
virtual void SetEventsBeingFlushed(bool events_being_flushed) = 0;
virtual RenderWidgetHostViewInput* FindViewFromFrameSinkId(
const viz::FrameSinkId& frame_sink_id) const = 0;
// Returns true if a further asynchronous query should be sent to the
// candidate RenderWidgetHostView.
virtual bool ShouldContinueHitTesting(
RenderWidgetHostViewInput* target_view) const = 0;
};
enum class HitTestResultsMatch {
kDoNotMatch = 0,
kMatch = 1,
kHitTestResultChanged = 2,
kHitTestDataOutdated = 3,
kMaxValue = kHitTestDataOutdated,
};
// The delegate must outlive this targeter.
explicit RenderWidgetTargeter(Delegate* delegate);
RenderWidgetTargeter(const RenderWidgetTargeter&) = delete;
RenderWidgetTargeter& operator=(const RenderWidgetTargeter&) = delete;
~RenderWidgetTargeter();
// Finds the appropriate target inside |root_view| for |event|, and dispatches
// it through the delegate. |event| is in the coord-space of |root_view|.
void FindTargetAndDispatch(RenderWidgetHostViewInput* root_view,
const blink::WebInputEvent& event,
const ui::LatencyInfo& latency);
// Finds the appropriate target inside |root_view| for |point|, and passes the
// target along with the transformed coordinates of the point with respect to
// the target's coordinates.
void FindTargetAndCallback(RenderWidgetHostViewInput* root_view,
const gfx::PointF& point,
RenderWidgetHostAtPointCallback callback);
void ViewWillBeDestroyed(RenderWidgetHostViewInput* view);
bool HasEventsPendingDispatch() const;
void set_async_hit_test_timeout_delay_for_testing(
const base::TimeDelta& delay) {
async_hit_test_timeout_delay_ = delay;
}
size_t num_requests_in_queue_for_testing() { return requests_.size(); }
bool is_request_in_flight_for_testing() {
return request_in_flight_.has_value();
}
void SetIsAutoScrollInProgress(bool autoscroll_in_progress);
bool is_auto_scroll_in_progress() const { return is_autoscroll_in_progress_; }
private:
class TargetingRequest {
public:
TargetingRequest(base::WeakPtr<RenderWidgetHostViewInput>,
const blink::WebInputEvent&,
const ui::LatencyInfo&);
TargetingRequest(base::WeakPtr<RenderWidgetHostViewInput>,
const gfx::PointF&,
RenderWidgetHostAtPointCallback);
TargetingRequest(TargetingRequest&& request);
TargetingRequest& operator=(TargetingRequest&& other);
TargetingRequest(const TargetingRequest&) = delete;
TargetingRequest& operator=(const TargetingRequest&) = delete;
~TargetingRequest();
void RunCallback(RenderWidgetHostViewInput* target,
std::optional<gfx::PointF> point);
bool MergeEventIfPossible(const blink::WebInputEvent& event);
bool IsWebInputEventRequest() const;
blink::WebInputEvent* GetEvent();
RenderWidgetHostViewInput* GetRootView() const;
gfx::PointF GetLocation() const;
const ui::LatencyInfo& GetLatency() const;
private:
base::WeakPtr<RenderWidgetHostViewInput> root_view;
RenderWidgetHostAtPointCallback callback;
// |location| is in the coordinate space of |root_view| which is
// either set directly when event is null or calculated from the event.
gfx::PointF location;
// |event| if set is in the coordinate space of |root_view|.
ui::WebScopedInputEvent event;
ui::LatencyInfo latency;
};
void ResolveTargetingRequest(TargetingRequest);
// Attempts to target and dispatch all events in the queue. It stops if it has
// to query a client, or if the queue becomes empty.
void FlushEventQueue();
// Queries |target| to find the correct target for |request|.
// |target_location| is the location in |target|'s coordinate space.
// |last_request_target| and |last_target_location| provide a fallback target
// in the case that the query times out. These should be null values when
// querying the root view, and the target's immediate parent view otherwise.
void QueryClient(RenderWidgetHostViewInput* target,
const gfx::PointF& target_location,
RenderWidgetHostViewInput* last_request_target,
const gfx::PointF& last_target_location,
TargetingRequest request);
// |target_location|, if
// set, is the location in |target|'s coordinate space.
// |target| is the current target that will be queried using its
// InputTargetClient interface.
// |frame_sink_id| is returned from the InputTargetClient to indicate where
// the event should be routed, and |transformed_location| is the point in
// that new target's coordinate space.
void FoundFrameSinkId(base::WeakPtr<RenderWidgetHostViewInput> target,
uint32_t request_id,
const gfx::PointF& target_location,
const viz::FrameSinkId& frame_sink_id,
const gfx::PointF& transformed_location);
// |target_location|, if
// set, is the location in |target|'s coordinate space.
void FoundTarget(RenderWidgetHostViewInput* target,
const std::optional<gfx::PointF>& target_location,
TargetingRequest* request);
// Callback when the hit testing timer fires, to resume event processing
// without further waiting for a response to the last targeting request.
void AsyncHitTestTimedOut(
base::WeakPtr<RenderWidgetHostViewInput> current_request_target,
const gfx::PointF& current_target_location,
base::WeakPtr<RenderWidgetHostViewInput> last_request_target,
const gfx::PointF& last_target_location);
void OnInputTargetDisconnect(
base::WeakPtr<RenderWidgetHostViewInput> target,
const gfx::PointF& location);
HitTestResultsMatch GetHitTestResultsMatchBucket(
RenderWidgetHostViewInput* target,
TargetingRequest* request) const;
base::TimeDelta async_hit_test_timeout_delay() {
return async_hit_test_timeout_delay_;
}
std::optional<TargetingRequest> request_in_flight_;
uint32_t last_request_id_ = 0;
std::queue<TargetingRequest> requests_;
std::unordered_set<raw_ptr<RenderWidgetHostViewInput, CtnExperimental>>
unresponsive_views_;
// Target to send events to if autoscroll is in progress
RenderWidgetTargetResult middle_click_result_;
// True when the user middle click's mouse for autoscroll
bool is_autoscroll_in_progress_ = false;
// This value limits how long to wait for a response from the renderer
// process before giving up and resuming event processing.
base::TimeDelta async_hit_test_timeout_delay_;
base::OneShotTimer async_hit_test_timeout_;
uint64_t trace_id_;
const raw_ptr<Delegate, DanglingUntriaged> delegate_;
base::WeakPtrFactory<RenderWidgetTargeter> weak_ptr_factory_{this};
};
} // namespace input
#endif // COMPONENTS_INPUT_RENDER_WIDGET_TARGETER_H_