1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_TARGETER_H_ 6 #define CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_TARGETER_H_ 7 8 #include <queue> 9 10 #include "base/memory/weak_ptr.h" 11 #include "base/optional.h" 12 #include "base/time/time.h" 13 #include "components/viz/common/surfaces/frame_sink_id.h" 14 #include "content/browser/renderer_host/render_widget_host_view_base.h" 15 #include "content/common/content_export.h" 16 #include "ui/events/blink/web_input_event_traits.h" 17 #include "ui/latency/latency_info.h" 18 19 namespace blink { 20 class WebInputEvent; 21 } // namespace blink 22 23 namespace gfx { 24 class PointF; 25 } 26 27 namespace content { 28 29 class RenderWidgetHostViewBase; 30 class OneShotTimeoutMonitor; 31 32 // TODO(sunxd): Make |RenderWidgetTargetResult| a class. Merge the booleans into 33 // a mask to reduce the size. Make the constructor take in enums for better 34 // readability. 35 struct CONTENT_EXPORT RenderWidgetTargetResult { 36 RenderWidgetTargetResult(); 37 RenderWidgetTargetResult(const RenderWidgetTargetResult&); 38 RenderWidgetTargetResult(RenderWidgetHostViewBase* view, 39 bool should_query_view, 40 base::Optional<gfx::PointF> location, 41 bool latched_target); 42 ~RenderWidgetTargetResult(); 43 44 RenderWidgetHostViewBase* view = nullptr; 45 bool should_query_view = false; 46 base::Optional<gfx::PointF> target_location = base::nullopt; 47 // When |latched_target| is false, we explicitly hit-tested events instead of 48 // using a known target. 49 bool latched_target = false; 50 }; 51 52 class TracingUmaTracker; 53 54 class RenderWidgetTargeter { 55 public: 56 using RenderWidgetHostAtPointCallback = 57 base::OnceCallback<void(base::WeakPtr<RenderWidgetHostViewBase>, 58 base::Optional<gfx::PointF>)>; 59 60 class Delegate { 61 public: ~Delegate()62 virtual ~Delegate() {} 63 64 virtual RenderWidgetTargetResult FindTargetSynchronouslyAtPoint( 65 RenderWidgetHostViewBase* root_view, 66 const gfx::PointF& location) = 0; 67 68 virtual RenderWidgetTargetResult FindTargetSynchronously( 69 RenderWidgetHostViewBase* root_view, 70 const blink::WebInputEvent& event) = 0; 71 72 // |event| must be non-null, and is in |root_view|'s coordinate space. 73 virtual void DispatchEventToTarget( 74 RenderWidgetHostViewBase* root_view, 75 RenderWidgetHostViewBase* target, 76 blink::WebInputEvent* event, 77 const ui::LatencyInfo& latency, 78 const base::Optional<gfx::PointF>& target_location) = 0; 79 80 virtual void SetEventsBeingFlushed(bool events_being_flushed) = 0; 81 82 virtual RenderWidgetHostViewBase* FindViewFromFrameSinkId( 83 const viz::FrameSinkId& frame_sink_id) const = 0; 84 85 // Returns true if a further asynchronous query should be sent to the 86 // candidate RenderWidgetHostView. 87 virtual bool ShouldContinueHitTesting( 88 RenderWidgetHostViewBase* target_view) const = 0; 89 }; 90 91 enum class HitTestResultsMatch { 92 kDoNotMatch = 0, 93 kMatch = 1, 94 kHitTestResultChanged = 2, 95 kHitTestDataOutdated = 3, 96 kMaxValue = kHitTestDataOutdated, 97 }; 98 99 // The delegate must outlive this targeter. 100 explicit RenderWidgetTargeter(Delegate* delegate); 101 ~RenderWidgetTargeter(); 102 103 // Finds the appropriate target inside |root_view| for |event|, and dispatches 104 // it through the delegate. |event| is in the coord-space of |root_view|. 105 void FindTargetAndDispatch(RenderWidgetHostViewBase* root_view, 106 const blink::WebInputEvent& event, 107 const ui::LatencyInfo& latency); 108 109 // Finds the appropriate target inside |root_view| for |point|, and passes the 110 // target along with the transformed coordinates of the point with respect to 111 // the target's coordinates. 112 void FindTargetAndCallback(RenderWidgetHostViewBase* root_view, 113 const gfx::PointF& point, 114 RenderWidgetHostAtPointCallback callback); 115 116 void ViewWillBeDestroyed(RenderWidgetHostViewBase* view); 117 118 bool HasEventsPendingDispatch() const; 119 set_async_hit_test_timeout_delay_for_testing(const base::TimeDelta & delay)120 void set_async_hit_test_timeout_delay_for_testing( 121 const base::TimeDelta& delay) { 122 async_hit_test_timeout_delay_ = delay; 123 } 124 num_requests_in_queue_for_testing()125 size_t num_requests_in_queue_for_testing() { return requests_.size(); } is_request_in_flight_for_testing()126 bool is_request_in_flight_for_testing() { 127 return request_in_flight_.has_value(); 128 } 129 130 void SetIsAutoScrollInProgress(bool autoscroll_in_progress); 131 is_auto_scroll_in_progress()132 bool is_auto_scroll_in_progress() const { return is_autoscroll_in_progress_; } 133 134 private: 135 class TargetingRequest { 136 public: 137 TargetingRequest(base::WeakPtr<RenderWidgetHostViewBase>, 138 const blink::WebInputEvent&, 139 const ui::LatencyInfo&); 140 TargetingRequest(base::WeakPtr<RenderWidgetHostViewBase>, 141 const gfx::PointF&, 142 RenderWidgetHostAtPointCallback); 143 TargetingRequest(TargetingRequest&& request); 144 TargetingRequest& operator=(TargetingRequest&& other); 145 ~TargetingRequest(); 146 147 void RunCallback(RenderWidgetHostViewBase* target, 148 base::Optional<gfx::PointF> point); 149 150 bool MergeEventIfPossible(const blink::WebInputEvent& event); 151 bool IsWebInputEventRequest() const; 152 blink::WebInputEvent* GetEvent(); 153 RenderWidgetHostViewBase* GetRootView() const; 154 gfx::PointF GetLocation() const; 155 const ui::LatencyInfo& GetLatency() const; 156 157 private: 158 base::WeakPtr<RenderWidgetHostViewBase> root_view; 159 160 RenderWidgetHostAtPointCallback callback; 161 162 // |location| is in the coordinate space of |root_view| which is 163 // either set directly when event is null or calculated from the event. 164 gfx::PointF location; 165 // |event| if set is in the coordinate space of |root_view|. 166 ui::WebScopedInputEvent event; 167 ui::LatencyInfo latency; 168 169 DISALLOW_COPY_AND_ASSIGN(TargetingRequest); 170 }; 171 172 void ResolveTargetingRequest(TargetingRequest); 173 174 // Attempts to target and dispatch all events in the queue. It stops if it has 175 // to query a client, or if the queue becomes empty. 176 void FlushEventQueue(); 177 178 // Queries |target| to find the correct target for |request|. 179 // |target_location| is the location in |target|'s coordinate space. 180 // |last_request_target| and |last_target_location| provide a fallback target 181 // in the case that the query times out. These should be null values when 182 // querying the root view, and the target's immediate parent view otherwise. 183 void QueryClient(RenderWidgetHostViewBase* target, 184 const gfx::PointF& target_location, 185 RenderWidgetHostViewBase* last_request_target, 186 const gfx::PointF& last_target_location, 187 TargetingRequest request); 188 189 // |target_location|, if 190 // set, is the location in |target|'s coordinate space. 191 // |target| is the current target that will be queried using its 192 // InputTargetClient interface. 193 // |frame_sink_id| is returned from the InputTargetClient to indicate where 194 // the event should be routed, and |transformed_location| is the point in 195 // that new target's coordinate space. 196 void FoundFrameSinkId(base::WeakPtr<RenderWidgetHostViewBase> target, 197 uint32_t request_id, 198 const gfx::PointF& target_location, 199 TracingUmaTracker tracker, 200 const viz::FrameSinkId& frame_sink_id, 201 const gfx::PointF& transformed_location); 202 203 // |target_location|, if 204 // set, is the location in |target|'s coordinate space. If |latched_target| is 205 // false, we explicitly did hit-testing for this event, instead of using a 206 // known target. 207 void FoundTarget(RenderWidgetHostViewBase* target, 208 const base::Optional<gfx::PointF>& target_location, 209 bool latched_target, 210 TargetingRequest* request); 211 212 // Callback when the hit testing timer fires, to resume event processing 213 // without further waiting for a response to the last targeting request. 214 void AsyncHitTestTimedOut( 215 base::WeakPtr<RenderWidgetHostViewBase> current_request_target, 216 const gfx::PointF& current_target_location, 217 base::WeakPtr<RenderWidgetHostViewBase> last_request_target, 218 const gfx::PointF& last_target_location); 219 220 void OnInputTargetDisconnect(base::WeakPtr<RenderWidgetHostViewBase> target, 221 const gfx::PointF& location); 222 223 HitTestResultsMatch GetHitTestResultsMatchBucket( 224 RenderWidgetHostViewBase* target, 225 TargetingRequest* request) const; 226 async_hit_test_timeout_delay()227 base::TimeDelta async_hit_test_timeout_delay() { 228 return async_hit_test_timeout_delay_; 229 } 230 231 base::Optional<TargetingRequest> request_in_flight_; 232 uint32_t last_request_id_ = 0; 233 std::queue<TargetingRequest> requests_; 234 235 std::unordered_set<RenderWidgetHostViewBase*> unresponsive_views_; 236 237 // This value keeps track of the number of clients we have asked in order to 238 // do async hit-testing. 239 uint32_t async_depth_ = 0; 240 241 // Target to send events to if autoscroll is in progress 242 RenderWidgetTargetResult middle_click_result_; 243 244 // True when the user middle click's mouse for autoscroll 245 bool is_autoscroll_in_progress_ = false; 246 247 // This value limits how long to wait for a response from the renderer 248 // process before giving up and resuming event processing. 249 base::TimeDelta async_hit_test_timeout_delay_; 250 251 std::unique_ptr<OneShotTimeoutMonitor> async_hit_test_timeout_; 252 253 uint64_t trace_id_; 254 255 const bool is_viz_hit_testing_debug_enabled_; 256 // Stores SurfaceIds for regions that were async queried if hit-test debugging 257 // is enabled. This allows us to send the queried regions in batches. 258 std::vector<viz::FrameSinkId> hit_test_async_queried_debug_queue_; 259 260 Delegate* const delegate_; 261 base::WeakPtrFactory<RenderWidgetTargeter> weak_ptr_factory_{this}; 262 263 DISALLOW_COPY_AND_ASSIGN(RenderWidgetTargeter); 264 }; 265 266 } // namespace content 267 268 #endif // CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_TARGETER_H_ 269