| // Copyright 2017 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_RENDERER_HOST_RENDER_WIDGET_TARGETER_H_ |
| #define CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_TARGETER_H_ |
| |
| #include <queue> |
| #include <unordered_set> |
| |
| #include "base/memory/weak_ptr.h" |
| #include "base/optional.h" |
| #include "base/time/time.h" |
| #include "components/viz/common/surfaces/frame_sink_id.h" |
| #include "content/common/content_constants_internal.h" |
| #include "content/common/content_export.h" |
| #include "ui/events/blink/web_input_event_traits.h" |
| #include "ui/latency/latency_info.h" |
| |
| namespace blink { |
| class WebInputEvent; |
| } // namespace blink |
| |
| namespace gfx { |
| class PointF; |
| } |
| |
| namespace content { |
| |
| class RenderWidgetHostViewBase; |
| class OneShotTimeoutMonitor; |
| |
| // TODO(sunxd): Make |RenderWidgetTargetResult| a class. Merge the booleans into |
| // a mask to reduce the size. Make the constructor take in enums for better |
| // readability. |
| struct CONTENT_EXPORT RenderWidgetTargetResult { |
| RenderWidgetTargetResult(); |
| RenderWidgetTargetResult(const RenderWidgetTargetResult&); |
| RenderWidgetTargetResult(RenderWidgetHostViewBase* view, |
| bool should_query_view, |
| base::Optional<gfx::PointF> location, |
| bool latched_target, |
| bool should_verify_result); |
| ~RenderWidgetTargetResult(); |
| |
| RenderWidgetHostViewBase* view = nullptr; |
| bool should_query_view = false; |
| base::Optional<gfx::PointF> target_location = base::nullopt; |
| // When |latched_target| is false, we explicitly hit-tested events instead of |
| // using a known target. |
| bool latched_target = false; |
| // When |should_verify_result| is true, RenderWidgetTargeter will do async hit |
| // testing and compare the target with the result of synchronous hit testing. |
| // |should_verify_result| will always be false if we are doing draw quad based |
| // hit testing. |
| bool should_verify_result = false; |
| }; |
| |
| class TracingUmaTracker; |
| |
| class RenderWidgetTargeter { |
| public: |
| class Delegate { |
| public: |
| virtual ~Delegate() {} |
| |
| virtual RenderWidgetTargetResult FindTargetSynchronously( |
| RenderWidgetHostViewBase* root_view, |
| const blink::WebInputEvent& event) = 0; |
| |
| // |event| is in |root_view|'s coordinate space. |
| virtual void DispatchEventToTarget( |
| RenderWidgetHostViewBase* root_view, |
| RenderWidgetHostViewBase* target, |
| const blink::WebInputEvent& event, |
| const ui::LatencyInfo& latency, |
| const base::Optional<gfx::PointF>& target_location) = 0; |
| |
| virtual void SetEventsBeingFlushed(bool events_being_flushed) = 0; |
| |
| virtual RenderWidgetHostViewBase* 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( |
| RenderWidgetHostViewBase* target_view) const = 0; |
| }; |
| |
| // The delegate must outlive this targeter. |
| explicit RenderWidgetTargeter(Delegate* delegate); |
| ~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(RenderWidgetHostViewBase* root_view, |
| const blink::WebInputEvent& event, |
| const ui::LatencyInfo& latency); |
| |
| void ViewWillBeDestroyed(RenderWidgetHostViewBase* view); |
| |
| void set_async_hit_test_timeout_delay_for_testing( |
| const base::TimeDelta& delay) { |
| async_hit_test_timeout_delay_ = delay; |
| } |
| |
| unsigned num_requests_in_queue_for_testing() { return requests_.size(); } |
| bool is_request_in_flight_for_testing() { return request_in_flight_; } |
| |
| private: |
| // 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(bool is_verifying); |
| |
| // Queries |target| to find the correct target for |event|. |
| // |event| is in the coordinate space of |root_view|. |
| // |target_location|, if set, is the location in |target|'s coordinate space. |
| // |last_request_target| and |last_target_location| provide a fallback target |
| // 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. |
| // |expected_frame_sink_id| is temporarily added for v2 viz hit testing. |
| // V2 uses cc generated hit test data and we need to verify its correctness. |
| // The variable is the target frame sink id v2 finds in synchronous hit |
| // testing. It should be the same as the async hit testing target if v2 works |
| // correctly. |
| // TODO(sunxd): Remove |expected_frame_sink_id| after verifying synchronous |
| // hit testing correctness. See https://crbug.com/871996. |
| void QueryClientInternal(RenderWidgetHostViewBase* root_view, |
| RenderWidgetHostViewBase* target, |
| const blink::WebInputEvent& event, |
| const ui::LatencyInfo& latency, |
| const gfx::PointF& target_location, |
| RenderWidgetHostViewBase* last_request_target, |
| const gfx::PointF& last_target_location, |
| const viz::FrameSinkId& expected_frame_sink_id); |
| |
| void QueryClient(RenderWidgetHostViewBase* root_view, |
| RenderWidgetHostViewBase* target, |
| const blink::WebInputEvent& event, |
| const ui::LatencyInfo& latency, |
| const gfx::PointF& target_location, |
| RenderWidgetHostViewBase* last_request_target, |
| const gfx::PointF& last_target_location); |
| |
| void QueryAndVerifyClient(RenderWidgetHostViewBase* root_view, |
| RenderWidgetHostViewBase* target, |
| const blink::WebInputEvent& event, |
| const ui::LatencyInfo& latency, |
| const gfx::PointF& target_location, |
| RenderWidgetHostViewBase* last_request_target, |
| const gfx::PointF& last_target_location, |
| const viz::FrameSinkId& expected_frame_sink_id); |
| |
| // |event| is in the coordinate space of |root_view|. |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. |
| // |expected_frame_sink_id| is the expected hit test result based on |
| // synchronous event targeting with cc generated data. |
| void FoundFrameSinkId(base::WeakPtr<RenderWidgetHostViewBase> root_view, |
| base::WeakPtr<RenderWidgetHostViewBase> target, |
| ui::WebScopedInputEvent event, |
| const ui::LatencyInfo& latency, |
| uint32_t request_id, |
| const gfx::PointF& target_location, |
| TracingUmaTracker tracker, |
| const viz::FrameSinkId& expected_frame_sink_id, |
| const viz::FrameSinkId& frame_sink_id, |
| const gfx::PointF& transformed_location); |
| |
| // |event| is in the coordinate space of |root_view|. |target_location|, if |
| // set, is the location in |target|'s coordinate space. If |latched_target| is |
| // false, we explicitly did hit-testing for this event, instead of using a |
| // known target. |
| void FoundTarget(RenderWidgetHostViewBase* root_view, |
| RenderWidgetHostViewBase* target, |
| const blink::WebInputEvent& event, |
| const ui::LatencyInfo& latency, |
| const base::Optional<gfx::PointF>& target_location, |
| bool latched_target, |
| const viz::FrameSinkId& expected_frame_sink_id); |
| |
| // 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<RenderWidgetHostViewBase> current_request_root_view, |
| base::WeakPtr<RenderWidgetHostViewBase> current_request_target, |
| const gfx::PointF& current_target_location, |
| base::WeakPtr<RenderWidgetHostViewBase> last_request_target, |
| const gfx::PointF& last_target_location, |
| ui::WebScopedInputEvent event, |
| const ui::LatencyInfo& latency, |
| const viz::FrameSinkId& expected_frame_sink_id); |
| |
| base::TimeDelta async_hit_test_timeout_delay() { |
| return async_hit_test_timeout_delay_; |
| } |
| |
| struct TargetingRequest { |
| TargetingRequest(); |
| TargetingRequest(TargetingRequest&& request); |
| TargetingRequest& operator=(TargetingRequest&& other); |
| ~TargetingRequest(); |
| |
| base::WeakPtr<RenderWidgetHostViewBase> root_view; |
| ui::WebScopedInputEvent event; |
| ui::LatencyInfo latency; |
| viz::FrameSinkId expected_frame_sink_id; |
| std::unique_ptr<TracingUmaTracker> tracker; |
| }; |
| |
| bool request_in_flight_ = false; |
| uint32_t last_request_id_ = 0; |
| std::queue<TargetingRequest> requests_; |
| |
| // With viz-hit-testing-surface-layer being enabled, we do async hit testing |
| // for already dispatched events for verification. These verification requests |
| // should not block normal hit testing requests. |
| bool verify_request_in_flight_ = false; |
| uint32_t last_verify_request_id_ = 0; |
| std::queue<TargetingRequest> verify_requests_; |
| |
| std::unordered_set<RenderWidgetHostViewBase*> unresponsive_views_; |
| |
| // This value keeps track of the number of clients we have asked in order to |
| // do async hit-testing. |
| uint32_t async_depth_ = 0; |
| |
| // 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::TimeDelta::FromMilliseconds(kAsyncHitTestTimeoutMs); |
| |
| std::unique_ptr<OneShotTimeoutMonitor> async_hit_test_timeout_; |
| std::unique_ptr<OneShotTimeoutMonitor> async_verify_hit_test_timeout_; |
| |
| uint64_t trace_id_; |
| |
| const bool is_viz_hit_testing_debug_enabled_; |
| // Stores SurfaceIds for regions that were async queried if hit-test debugging |
| // is enabled. This allows us to send the queried regions in batches. |
| std::vector<viz::FrameSinkId> hit_test_async_queried_debug_queue_; |
| |
| Delegate* const delegate_; |
| base::WeakPtrFactory<RenderWidgetTargeter> weak_ptr_factory_; |
| |
| DISALLOW_COPY_AND_ASSIGN(RenderWidgetTargeter); |
| }; |
| |
| } // namespace content |
| |
| #endif // CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_TARGETER_H_ |