1 // Copyright 2018 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 #include "content/public/test/hit_test_region_observer.h"
6 
7 #include <algorithm>
8 
9 #include "base/test/test_timeouts.h"
10 #include "components/viz/host/hit_test/hit_test_query.h"
11 #include "components/viz/host/host_frame_sink_manager.h"
12 #include "content/browser/compositor/surface_utils.h"
13 #include "content/browser/renderer_host/render_frame_host_impl.h"
14 #include "content/browser/renderer_host/render_widget_host_impl.h"
15 #include "content/browser/renderer_host/render_widget_host_view_base.h"
16 #include "content/browser/renderer_host/render_widget_host_view_child_frame.h"
17 #include "content/browser/web_contents/web_contents_impl.h"
18 #include "content/public/browser/render_frame_host.h"
19 #include "content/public/browser/web_contents.h"
20 #include "content/public/test/browser_test_utils.h"
21 
22 namespace content {
23 
WaitForHitTestData(RenderFrameHost * child_frame)24 void WaitForHitTestData(RenderFrameHost* child_frame) {
25   RenderWidgetHostViewBase* child_view =
26       static_cast<RenderFrameHostImpl*>(child_frame)
27           ->GetRenderWidgetHost()
28           ->GetView();
29 
30   HitTestRegionObserver observer(child_view->GetFrameSinkId());
31   observer.WaitForHitTestData();
32 }
33 
WaitForHitTestData(WebContents * guest_web_contents)34 void WaitForHitTestData(WebContents* guest_web_contents) {
35   DCHECK(static_cast<RenderWidgetHostViewBase*>(
36              guest_web_contents->GetRenderWidgetHostView())
37              ->IsRenderWidgetHostViewChildFrame());
38   RenderWidgetHostViewChildFrame* child_view =
39       static_cast<RenderWidgetHostViewChildFrame*>(
40           guest_web_contents->GetRenderWidgetHostView());
41 
42   HitTestRegionObserver observer(child_view->GetFrameSinkId());
43   observer.WaitForHitTestData();
44 }
45 
HitTestRegionObserver(const viz::FrameSinkId & frame_sink_id)46 HitTestRegionObserver::HitTestRegionObserver(
47     const viz::FrameSinkId& frame_sink_id)
48     : frame_sink_id_(frame_sink_id) {
49   CHECK(frame_sink_id.is_valid());
50   GetHostFrameSinkManager()->AddHitTestRegionObserver(this);
51 }
52 
~HitTestRegionObserver()53 HitTestRegionObserver::~HitTestRegionObserver() {
54   GetHostFrameSinkManager()->RemoveHitTestRegionObserver(this);
55 }
56 
WaitForHitTestData()57 void HitTestRegionObserver::WaitForHitTestData() {
58   DCHECK(cached_hit_test_data_.empty());
59 
60   for (auto& it : GetHostFrameSinkManager()->display_hit_test_query()) {
61     if (it.second->ContainsActiveFrameSinkId(frame_sink_id_)) {
62       cached_hit_test_data_ = it.second->GetHitTestData();
63       return;
64     }
65   }
66 
67   run_loop_ = std::make_unique<base::RunLoop>();
68   run_loop_->Run();
69   run_loop_.reset();
70 }
71 
WaitForHitTestDataChange()72 void HitTestRegionObserver::WaitForHitTestDataChange() {
73   DCHECK(!cached_hit_test_data_.empty());
74 
75   for (auto& it : GetHostFrameSinkManager()->display_hit_test_query()) {
76     DCHECK(it.second->ContainsActiveFrameSinkId(frame_sink_id_));
77     if (it.second->GetHitTestData() != cached_hit_test_data_) {
78       cached_hit_test_data_ = it.second->GetHitTestData();
79       return;
80     }
81   }
82 
83   hit_test_data_change_run_loop_ = std::make_unique<base::RunLoop>();
84   hit_test_data_change_run_loop_->Run();
85   hit_test_data_change_run_loop_.reset();
86 }
87 
OnAggregatedHitTestRegionListUpdated(const viz::FrameSinkId & frame_sink_id,const std::vector<viz::AggregatedHitTestRegion> & hit_test_data)88 void HitTestRegionObserver::OnAggregatedHitTestRegionListUpdated(
89     const viz::FrameSinkId& frame_sink_id,
90     const std::vector<viz::AggregatedHitTestRegion>& hit_test_data) {
91   if (hit_test_data_change_run_loop_ &&
92       cached_hit_test_data_ != hit_test_data) {
93     cached_hit_test_data_ = hit_test_data;
94     hit_test_data_change_run_loop_->Quit();
95   }
96 
97   if (!run_loop_)
98     return;
99 
100   for (auto& it : hit_test_data) {
101     if (it.frame_sink_id == frame_sink_id_ &&
102         !(it.flags & viz::HitTestRegionFlags::kHitTestNotActive)) {
103       run_loop_->Quit();
104       return;
105     }
106   }
107 }
108 
109 const std::vector<viz::AggregatedHitTestRegion>&
GetHitTestData()110 HitTestRegionObserver::GetHitTestData() {
111   const auto& hit_test_query_map =
112       GetHostFrameSinkManager()->display_hit_test_query();
113   const auto iter = hit_test_query_map.find(frame_sink_id_);
114   DCHECK(iter != hit_test_query_map.end());
115   return iter->second.get()->GetHitTestData();
116 }
117 
118 }  // namespace content
119