1 /*
2  * Copyright (C) 2010-2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h"
32 
33 #include <v8-inspector.h>
34 #include <memory>
35 #include <utility>
36 
37 #include "third_party/blink/public/platform/platform.h"
38 #include "third_party/blink/public/platform/web_float_rect.h"
39 #include "third_party/blink/public/platform/web_rect.h"
40 #include "third_party/blink/public/platform/web_scoped_page_pauser.h"
41 #include "third_party/blink/public/platform/web_string.h"
42 #include "third_party/blink/public/web/web_settings.h"
43 #include "third_party/blink/public/web/web_view_client.h"
44 #include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
45 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
46 #include "third_party/blink/renderer/core/core_initializer.h"
47 #include "third_party/blink/renderer/core/core_probe_sink.h"
48 #include "third_party/blink/renderer/core/events/web_input_event_conversion.h"
49 #include "third_party/blink/renderer/core/exported/web_settings_impl.h"
50 #include "third_party/blink/renderer/core/exported/web_view_impl.h"
51 #include "third_party/blink/renderer/core/frame/local_frame.h"
52 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
53 #include "third_party/blink/renderer/core/frame/settings.h"
54 #include "third_party/blink/renderer/core/frame/web_frame_widget_base.h"
55 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
56 #include "third_party/blink/renderer/core/inspector/dev_tools_emulator.h"
57 #include "third_party/blink/renderer/core/inspector/devtools_agent.h"
58 #include "third_party/blink/renderer/core/inspector/devtools_session.h"
59 #include "third_party/blink/renderer/core/inspector/inspected_frames.h"
60 #include "third_party/blink/renderer/core/inspector/inspector_animation_agent.h"
61 #include "third_party/blink/renderer/core/inspector/inspector_application_cache_agent.h"
62 #include "third_party/blink/renderer/core/inspector/inspector_audits_agent.h"
63 #include "third_party/blink/renderer/core/inspector/inspector_css_agent.h"
64 #include "third_party/blink/renderer/core/inspector/inspector_dom_agent.h"
65 #include "third_party/blink/renderer/core/inspector/inspector_dom_debugger_agent.h"
66 #include "third_party/blink/renderer/core/inspector/inspector_dom_snapshot_agent.h"
67 #include "third_party/blink/renderer/core/inspector/inspector_emulation_agent.h"
68 #include "third_party/blink/renderer/core/inspector/inspector_io_agent.h"
69 #include "third_party/blink/renderer/core/inspector/inspector_layer_tree_agent.h"
70 #include "third_party/blink/renderer/core/inspector/inspector_log_agent.h"
71 #include "third_party/blink/renderer/core/inspector/inspector_media_agent.h"
72 #include "third_party/blink/renderer/core/inspector/inspector_memory_agent.h"
73 #include "third_party/blink/renderer/core/inspector/inspector_network_agent.h"
74 #include "third_party/blink/renderer/core/inspector/inspector_overlay_agent.h"
75 #include "third_party/blink/renderer/core/inspector/inspector_page_agent.h"
76 #include "third_party/blink/renderer/core/inspector/inspector_performance_agent.h"
77 #include "third_party/blink/renderer/core/inspector/inspector_resource_container.h"
78 #include "third_party/blink/renderer/core/inspector/inspector_resource_content_loader.h"
79 #include "third_party/blink/renderer/core/inspector/inspector_task_runner.h"
80 #include "third_party/blink/renderer/core/inspector/main_thread_debugger.h"
81 #include "third_party/blink/renderer/core/layout/layout_view.h"
82 #include "third_party/blink/renderer/core/page/focus_controller.h"
83 #include "third_party/blink/renderer/core/page/page.h"
84 #include "third_party/blink/renderer/core/probe/core_probes.h"
85 #include "third_party/blink/renderer/platform/graphics/graphics_context.h"
86 #include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
87 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
88 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
89 #include "third_party/blink/renderer/platform/wtf/math_extras.h"
90 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
91 #include "third_party/blink/renderer/platform/wtf/vector.h"
92 
93 namespace blink {
94 
95 namespace {
96 
IsMainFrame(WebLocalFrameImpl * frame)97 bool IsMainFrame(WebLocalFrameImpl* frame) {
98   // TODO(dgozman): sometimes view->mainFrameImpl() does return null, even
99   // though |frame| is meant to be main frame.  See http://crbug.com/526162.
100   return frame->ViewImpl() && !frame->Parent();
101 }
102 
103 }  // namespace
104 
105 class ClientMessageLoopAdapter : public MainThreadDebugger::ClientMessageLoop {
106  public:
~ClientMessageLoopAdapter()107   ~ClientMessageLoopAdapter() override { instance_ = nullptr; }
108 
EnsureMainThreadDebuggerCreated()109   static void EnsureMainThreadDebuggerCreated() {
110     if (instance_)
111       return;
112     std::unique_ptr<ClientMessageLoopAdapter> instance(
113         new ClientMessageLoopAdapter(
114             Platform::Current()->CreateNestedMessageLoopRunner()));
115     instance_ = instance.get();
116     MainThreadDebugger::Instance()->SetClientMessageLoop(std::move(instance));
117   }
118 
ContinueProgram()119   static void ContinueProgram() {
120     // Release render thread if necessary.
121     if (instance_)
122       instance_->QuitNow();
123   }
124 
PauseForPageWait(WebLocalFrameImpl * frame)125   static void PauseForPageWait(WebLocalFrameImpl* frame) {
126     if (instance_)
127       instance_->RunForPageWait(frame);
128   }
129 
130  private:
ClientMessageLoopAdapter(std::unique_ptr<Platform::NestedMessageLoopRunner> message_loop)131   ClientMessageLoopAdapter(
132       std::unique_ptr<Platform::NestedMessageLoopRunner> message_loop)
133       : running_for_debug_break_(false),
134         running_for_page_wait_(false),
135         message_loop_(std::move(message_loop)) {
136     DCHECK(message_loop_.get());
137   }
138 
Run(LocalFrame * frame)139   void Run(LocalFrame* frame) override {
140     if (running_for_debug_break_)
141       return;
142 
143     running_for_debug_break_ = true;
144     if (!running_for_page_wait_)
145       RunLoop(WebLocalFrameImpl::FromFrame(frame));
146   }
147 
RunForPageWait(WebLocalFrameImpl * frame)148   void RunForPageWait(WebLocalFrameImpl* frame) {
149     if (running_for_page_wait_)
150       return;
151 
152     running_for_page_wait_ = true;
153     if (!running_for_debug_break_)
154       RunLoop(frame);
155   }
156 
RunLoop(WebLocalFrameImpl * frame)157   void RunLoop(WebLocalFrameImpl* frame) {
158     // 0. Flush pending frontend messages.
159     WebDevToolsAgentImpl* agent = frame->DevToolsAgentImpl();
160     agent->FlushProtocolNotifications();
161 
162     // 1. Disable input events.
163     WebFrameWidgetBase::SetIgnoreInputEvents(true);
164     for (auto* const view : WebViewImpl::AllInstances())
165       view->GetChromeClient().NotifyPopupOpeningObservers();
166 
167     // 2. Disable active objects
168     page_pauser_ = WebScopedPagePauser::Create();
169 
170     // 3. Process messages until quitNow is called.
171     message_loop_->Run();
172   }
173 
QuitNow()174   void QuitNow() override {
175     if (running_for_debug_break_) {
176       running_for_debug_break_ = false;
177       if (!running_for_page_wait_)
178         DoQuit();
179     }
180   }
181 
RunIfWaitingForDebugger(LocalFrame * frame)182   void RunIfWaitingForDebugger(LocalFrame* frame) override {
183     if (!running_for_page_wait_)
184       return;
185     running_for_page_wait_ = false;
186     if (!running_for_debug_break_)
187       DoQuit();
188   }
189 
DoQuit()190   void DoQuit() {
191     // Undo steps (3), (2) and (1) from above.
192     // NOTE: This code used to be above right after the |mesasge_loop_->Run()|
193     // code, but it is moved here to support browser-side navigation.
194     message_loop_->QuitNow();
195     page_pauser_.reset();
196     WebFrameWidgetBase::SetIgnoreInputEvents(false);
197   }
198 
199   bool running_for_debug_break_;
200   bool running_for_page_wait_;
201   std::unique_ptr<Platform::NestedMessageLoopRunner> message_loop_;
202   std::unique_ptr<WebScopedPagePauser> page_pauser_;
203 
204   static ClientMessageLoopAdapter* instance_;
205 };
206 
207 ClientMessageLoopAdapter* ClientMessageLoopAdapter::instance_ = nullptr;
208 
AttachSession(DevToolsSession * session,bool restore)209 void WebDevToolsAgentImpl::AttachSession(DevToolsSession* session,
210                                          bool restore) {
211   if (!network_agents_.size())
212     Thread::Current()->AddTaskObserver(this);
213 
214   ClientMessageLoopAdapter::EnsureMainThreadDebuggerCreated();
215   MainThreadDebugger* main_thread_debugger = MainThreadDebugger::Instance();
216   v8::Isolate* isolate = V8PerIsolateData::MainThreadIsolate();
217   InspectedFrames* inspected_frames = inspected_frames_.Get();
218 
219   int context_group_id =
220       main_thread_debugger->ContextGroupId(inspected_frames->Root());
221   session->ConnectToV8(main_thread_debugger->GetV8Inspector(),
222                        context_group_id);
223 
224   InspectorDOMAgent* dom_agent = MakeGarbageCollected<InspectorDOMAgent>(
225       isolate, inspected_frames, session->V8Session());
226   session->Append(dom_agent);
227 
228   auto* layer_tree_agent =
229       MakeGarbageCollected<InspectorLayerTreeAgent>(inspected_frames, this);
230   session->Append(layer_tree_agent);
231 
232   InspectorNetworkAgent* network_agent =
233       MakeGarbageCollected<InspectorNetworkAgent>(inspected_frames, nullptr,
234                                                   session->V8Session());
235   session->Append(network_agent);
236 
237   auto* css_agent = MakeGarbageCollected<InspectorCSSAgent>(
238       dom_agent, inspected_frames, network_agent,
239       resource_content_loader_.Get(), resource_container_.Get());
240   session->Append(css_agent);
241 
242   InspectorDOMDebuggerAgent* dom_debugger_agent =
243       MakeGarbageCollected<InspectorDOMDebuggerAgent>(isolate, dom_agent,
244                                                       session->V8Session());
245   session->Append(dom_debugger_agent);
246 
247   InspectorPerformanceAgent* performance_agent =
248       MakeGarbageCollected<InspectorPerformanceAgent>(inspected_frames);
249   session->Append(performance_agent);
250 
251   session->Append(MakeGarbageCollected<InspectorDOMSnapshotAgent>(
252       inspected_frames, dom_debugger_agent));
253 
254   session->Append(MakeGarbageCollected<InspectorAnimationAgent>(
255       inspected_frames, css_agent, session->V8Session()));
256 
257   session->Append(MakeGarbageCollected<InspectorMemoryAgent>(inspected_frames));
258 
259   session->Append(
260       MakeGarbageCollected<InspectorApplicationCacheAgent>(inspected_frames));
261 
262   auto* page_agent = MakeGarbageCollected<InspectorPageAgent>(
263       inspected_frames, this, resource_content_loader_.Get(),
264       session->V8Session());
265   session->Append(page_agent);
266 
267   session->Append(MakeGarbageCollected<InspectorLogAgent>(
268       &inspected_frames->Root()->GetPage()->GetConsoleMessageStorage(),
269       inspected_frames->Root()->GetPerformanceMonitor(), session->V8Session()));
270 
271   InspectorOverlayAgent* overlay_agent =
272       MakeGarbageCollected<InspectorOverlayAgent>(
273           web_local_frame_impl_.Get(), inspected_frames, session->V8Session(),
274           dom_agent);
275   session->Append(overlay_agent);
276 
277   session->Append(
278       MakeGarbageCollected<InspectorIOAgent>(isolate, session->V8Session()));
279 
280   session->Append(MakeGarbageCollected<InspectorAuditsAgent>(
281       network_agent,
282       &inspected_frames->Root()->GetPage()->GetInspectorIssueStorage()));
283 
284   session->Append(MakeGarbageCollected<InspectorMediaAgent>(inspected_frames));
285 
286   // TODO(dgozman): we should actually pass the view instead of frame, but
287   // during remote->local transition we cannot access mainFrameImpl() yet, so
288   // we have to store the frame which will become the main frame later.
289   session->Append(MakeGarbageCollected<InspectorEmulationAgent>(
290       web_local_frame_impl_.Get()));
291 
292   // Call session init callbacks registered from higher layers.
293   CoreInitializer::GetInstance().InitInspectorAgentSession(
294       session, include_view_agents_, dom_agent, inspected_frames,
295       web_local_frame_impl_->ViewImpl()->GetPage());
296 
297   if (node_to_inspect_) {
298     overlay_agent->Inspect(node_to_inspect_);
299     node_to_inspect_ = nullptr;
300   }
301 
302   network_agents_.insert(session, network_agent);
303   page_agents_.insert(session, page_agent);
304   overlay_agents_.insert(session, overlay_agent);
305 }
306 
307 // static
CreateForFrame(WebLocalFrameImpl * frame)308 WebDevToolsAgentImpl* WebDevToolsAgentImpl::CreateForFrame(
309     WebLocalFrameImpl* frame) {
310   return MakeGarbageCollected<WebDevToolsAgentImpl>(frame, IsMainFrame(frame));
311 }
312 
313 // static
CreateForWorker(WebLocalFrameImpl * frame)314 WebDevToolsAgentImpl* WebDevToolsAgentImpl::CreateForWorker(
315     WebLocalFrameImpl* frame) {
316   return MakeGarbageCollected<WebDevToolsAgentImpl>(frame, true);
317 }
318 
WebDevToolsAgentImpl(WebLocalFrameImpl * web_local_frame_impl,bool include_view_agents)319 WebDevToolsAgentImpl::WebDevToolsAgentImpl(
320     WebLocalFrameImpl* web_local_frame_impl,
321     bool include_view_agents)
322     : web_local_frame_impl_(web_local_frame_impl),
323       probe_sink_(web_local_frame_impl_->GetFrame()->GetProbeSink()),
324       resource_content_loader_(
325           MakeGarbageCollected<InspectorResourceContentLoader>(
326               web_local_frame_impl_->GetFrame())),
327       inspected_frames_(MakeGarbageCollected<InspectedFrames>(
328           web_local_frame_impl_->GetFrame())),
329       resource_container_(
330           MakeGarbageCollected<InspectorResourceContainer>(inspected_frames_)),
331       include_view_agents_(include_view_agents) {
332   DCHECK(IsMainThread());
333   agent_ = MakeGarbageCollected<DevToolsAgent>(
334       this, inspected_frames_.Get(), probe_sink_.Get(),
335       web_local_frame_impl_->GetFrame()->GetInspectorTaskRunner(),
336       Platform::Current()->GetIOTaskRunner());
337 }
338 
~WebDevToolsAgentImpl()339 WebDevToolsAgentImpl::~WebDevToolsAgentImpl() {}
340 
Trace(Visitor * visitor)341 void WebDevToolsAgentImpl::Trace(Visitor* visitor) {
342   visitor->Trace(agent_);
343   visitor->Trace(network_agents_);
344   visitor->Trace(page_agents_);
345   visitor->Trace(overlay_agents_);
346   visitor->Trace(web_local_frame_impl_);
347   visitor->Trace(probe_sink_);
348   visitor->Trace(resource_content_loader_);
349   visitor->Trace(inspected_frames_);
350   visitor->Trace(resource_container_);
351   visitor->Trace(node_to_inspect_);
352 }
353 
WillBeDestroyed()354 void WebDevToolsAgentImpl::WillBeDestroyed() {
355   DCHECK(web_local_frame_impl_->GetFrame());
356   DCHECK(inspected_frames_->Root()->View());
357   agent_->Dispose();
358   resource_content_loader_->Dispose();
359 }
360 
BindReceiver(mojo::PendingAssociatedRemote<mojom::blink::DevToolsAgentHost> host_remote,mojo::PendingAssociatedReceiver<mojom::blink::DevToolsAgent> receiver)361 void WebDevToolsAgentImpl::BindReceiver(
362     mojo::PendingAssociatedRemote<mojom::blink::DevToolsAgentHost> host_remote,
363     mojo::PendingAssociatedReceiver<mojom::blink::DevToolsAgent> receiver) {
364   agent_->BindReceiver(
365       std::move(host_remote), std::move(receiver),
366       web_local_frame_impl_->GetTaskRunner(TaskType::kInternalInspector));
367 }
368 
DetachSession(DevToolsSession * session)369 void WebDevToolsAgentImpl::DetachSession(DevToolsSession* session) {
370   network_agents_.erase(session);
371   page_agents_.erase(session);
372   overlay_agents_.erase(session);
373   if (!network_agents_.size())
374     Thread::Current()->RemoveTaskObserver(this);
375 }
376 
InspectElement(const gfx::Point & point_in_local_root)377 void WebDevToolsAgentImpl::InspectElement(
378     const gfx::Point& point_in_local_root) {
379   WebFloatRect rect(point_in_local_root.x(), point_in_local_root.y(), 0, 0);
380   web_local_frame_impl_->FrameWidgetImpl()->Client()->ConvertWindowToViewport(
381       &rect);
382   gfx::PointF point(rect.x, rect.y);
383 
384   HitTestRequest::HitTestRequestType hit_type =
385       HitTestRequest::kMove | HitTestRequest::kReadOnly |
386       HitTestRequest::kAllowChildFrameContent;
387   HitTestRequest request(hit_type);
388   WebMouseEvent dummy_event(WebInputEvent::kMouseDown,
389                             WebInputEvent::kNoModifiers,
390                             base::TimeTicks::Now());
391   dummy_event.SetPositionInWidget(point);
392   IntPoint transformed_point = FlooredIntPoint(
393       TransformWebMouseEvent(web_local_frame_impl_->GetFrameView(), dummy_event)
394           .PositionInRootFrame());
395   HitTestLocation location(
396       web_local_frame_impl_->GetFrameView()->ConvertFromRootFrame(
397           transformed_point));
398   HitTestResult result(request, location);
399   web_local_frame_impl_->GetFrame()->ContentLayoutObject()->HitTest(location,
400                                                                     result);
401   Node* node = result.InnerNode();
402   if (!node && web_local_frame_impl_->GetFrame()->GetDocument())
403     node = web_local_frame_impl_->GetFrame()->GetDocument()->documentElement();
404 
405   if (!overlay_agents_.IsEmpty()) {
406     for (auto& it : overlay_agents_)
407       it.value->Inspect(node);
408   } else {
409     node_to_inspect_ = node;
410   }
411 }
412 
DebuggerTaskStarted()413 void WebDevToolsAgentImpl::DebuggerTaskStarted() {
414   probe::WillStartDebuggerTask(probe_sink_);
415 }
416 
DebuggerTaskFinished()417 void WebDevToolsAgentImpl::DebuggerTaskFinished() {
418   probe::DidFinishDebuggerTask(probe_sink_);
419 }
420 
DidCommitLoadForLocalFrame(LocalFrame * frame)421 void WebDevToolsAgentImpl::DidCommitLoadForLocalFrame(LocalFrame* frame) {
422   resource_container_->DidCommitLoadForLocalFrame(frame);
423   resource_content_loader_->DidCommitLoadForLocalFrame(frame);
424 }
425 
ScreencastEnabled()426 bool WebDevToolsAgentImpl::ScreencastEnabled() {
427   for (auto& it : page_agents_) {
428     if (it.value->ScreencastEnabled())
429       return true;
430   }
431   return false;
432 }
433 
PageLayoutInvalidated(bool resized)434 void WebDevToolsAgentImpl::PageLayoutInvalidated(bool resized) {
435   for (auto& it : overlay_agents_)
436     it.value->PageLayoutInvalidated(resized);
437 }
438 
DidShowNewWindow()439 void WebDevToolsAgentImpl::DidShowNewWindow() {
440   if (!wait_for_debugger_when_shown_)
441     return;
442   wait_for_debugger_when_shown_ = false;
443   WaitForDebugger();
444 }
445 
WaitForDebuggerWhenShown()446 void WebDevToolsAgentImpl::WaitForDebuggerWhenShown() {
447   wait_for_debugger_when_shown_ = true;
448 }
449 
WaitForDebugger()450 void WebDevToolsAgentImpl::WaitForDebugger() {
451   ClientMessageLoopAdapter::PauseForPageWait(web_local_frame_impl_);
452 }
453 
IsInspectorLayer(const cc::Layer * layer)454 bool WebDevToolsAgentImpl::IsInspectorLayer(const cc::Layer* layer) {
455   for (auto& it : overlay_agents_) {
456     if (it.value->IsInspectorLayer(layer))
457       return true;
458   }
459   return false;
460 }
461 
EvaluateInOverlayForTesting(const String & script)462 String WebDevToolsAgentImpl::EvaluateInOverlayForTesting(const String& script) {
463   String result;
464   for (auto& it : overlay_agents_)
465     result = it.value->EvaluateInOverlayForTest(script);
466   return result;
467 }
468 
UpdateOverlaysPrePaint()469 void WebDevToolsAgentImpl::UpdateOverlaysPrePaint() {
470   for (auto& it : overlay_agents_)
471     it.value->UpdatePrePaint();
472 }
473 
PaintOverlays(GraphicsContext & context)474 void WebDevToolsAgentImpl::PaintOverlays(GraphicsContext& context) {
475   DCHECK(RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
476   for (auto& it : overlay_agents_)
477     it.value->PaintOverlay(context);
478 }
479 
DispatchBufferedTouchEvents()480 void WebDevToolsAgentImpl::DispatchBufferedTouchEvents() {
481   for (auto& it : overlay_agents_)
482     it.value->DispatchBufferedTouchEvents();
483 }
484 
HandleInputEvent(const WebInputEvent & event)485 WebInputEventResult WebDevToolsAgentImpl::HandleInputEvent(
486     const WebInputEvent& event) {
487   for (auto& it : overlay_agents_) {
488     auto result = it.value->HandleInputEvent(event);
489     if (result != WebInputEventResult::kNotHandled)
490       return result;
491   }
492   return WebInputEventResult::kNotHandled;
493 }
494 
NavigationInitiatorInfo(LocalFrame * frame)495 String WebDevToolsAgentImpl::NavigationInitiatorInfo(LocalFrame* frame) {
496   for (auto& it : network_agents_) {
497     String initiator = it.value->NavigationInitiatorInfo(frame);
498     if (!initiator.IsNull())
499       return initiator;
500   }
501   return String();
502 }
503 
FlushProtocolNotifications()504 void WebDevToolsAgentImpl::FlushProtocolNotifications() {
505   agent_->FlushProtocolNotifications();
506 }
507 
WillProcessTask(const base::PendingTask & pending_task,bool was_blocked_or_low_priority)508 void WebDevToolsAgentImpl::WillProcessTask(
509     const base::PendingTask& pending_task,
510     bool was_blocked_or_low_priority) {
511   if (network_agents_.IsEmpty())
512     return;
513   ThreadDebugger::IdleFinished(V8PerIsolateData::MainThreadIsolate());
514 }
515 
DidProcessTask(const base::PendingTask & pending_task)516 void WebDevToolsAgentImpl::DidProcessTask(
517     const base::PendingTask& pending_task) {
518   if (network_agents_.IsEmpty())
519     return;
520   ThreadDebugger::IdleStarted(V8PerIsolateData::MainThreadIsolate());
521   FlushProtocolNotifications();
522 }
523 
524 }  // namespace blink
525