3d79e0c61c8752cebc49deb651cad759b8f04231
[WebKit-https.git] / WebKit / chromium / src / WebDevToolsAgentImpl.cpp
1 /*
2  * Copyright (C) 2010 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 "config.h"
32 #include "WebDevToolsAgentImpl.h"
33
34 #include "BoundObject.h"
35 #include "DebuggerAgentImpl.h"
36 #include "DebuggerAgentManager.h"
37 #include "Document.h"
38 #include "EventListener.h"
39 #include "InjectedScriptHost.h"
40 #include "InspectorBackend.h"
41 #include "InspectorBackendDispatcher.h"
42 #include "InspectorController.h"
43 #include "InspectorFrontend.h"
44 #include "InspectorResource.h"
45 #include "Node.h"
46 #include "Page.h"
47 #include "PageGroup.h"
48 #include "PlatformString.h"
49 #include "ProfilerAgentImpl.h"
50 #include "ResourceError.h"
51 #include "ResourceRequest.h"
52 #include "ResourceResponse.h"
53 #include "ScriptDebugServer.h"
54 #include "ScriptObject.h"
55 #include "ScriptState.h"
56 #include "ScriptValue.h"
57 #include "V8Binding.h"
58 #include "V8InspectorBackend.h"
59 #include "V8Proxy.h"
60 #include "V8Utilities.h"
61 #include "WebDataSource.h"
62 #include "WebDevToolsAgentClient.h"
63 #include "WebDevToolsMessageData.h"
64 #include "WebDevToolsMessageTransport.h"
65 #include "WebFrameImpl.h"
66 #include "WebRect.h"
67 #include "WebString.h"
68 #include "WebURL.h"
69 #include "WebURLError.h"
70 #include "WebURLRequest.h"
71 #include "WebURLResponse.h"
72 #include "WebViewClient.h"
73 #include "WebViewImpl.h"
74 #include <wtf/Noncopyable.h>
75 #include <wtf/OwnPtr.h>
76
77 using WebCore::Document;
78 using WebCore::DocumentLoader;
79 using WebCore::FrameLoader;
80 using WebCore::InjectedScriptHost;
81 using WebCore::InspectorBackend;
82 using WebCore::InspectorController;
83 using WebCore::InspectorFrontend;
84 using WebCore::InspectorResource;
85 using WebCore::Node;
86 using WebCore::Page;
87 using WebCore::ResourceError;
88 using WebCore::ResourceRequest;
89 using WebCore::ResourceResponse;
90 using WebCore::SafeAllocation;
91 using WebCore::ScriptObject;
92 using WebCore::ScriptState;
93 using WebCore::ScriptValue;
94 using WebCore::String;
95 using WebCore::V8DOMWrapper;
96 using WebCore::V8InspectorBackend;
97 using WebCore::V8Proxy;
98
99 namespace WebKit {
100
101 namespace {
102
103 void InspectorBackendWeakReferenceCallback(v8::Persistent<v8::Value> object, void* parameter)
104 {
105     InspectorBackend* backend = static_cast<InspectorBackend*>(parameter);
106     backend->deref();
107     object.Dispose();
108 }
109
110 static const char kResourceTrackingFeatureName[] = "resource-tracking";
111 static const char kTimelineFeatureName[] = "timeline-profiler";
112 static const char kApuAgentFeatureName[] = "apu-agent";
113
114 class IORPCDelegate : public DevToolsRPC::Delegate, public Noncopyable {
115 public:
116     IORPCDelegate() : m_transport(0) { }
117     explicit IORPCDelegate(WebDevToolsMessageTransport* transport) : m_transport(transport) { }
118     virtual ~IORPCDelegate() { }
119     virtual void sendRpcMessage(const WebDevToolsMessageData& data)
120     {
121         if (m_transport)
122             m_transport->sendMessageToFrontendOnIOThread(data);
123     }
124
125 private:
126     WebDevToolsMessageTransport* m_transport;
127 };
128
129 class ClientMessageLoopAdapter : public WebCore::ScriptDebugServer::ClientMessageLoop {
130 public:
131     static void ensureClientMessageLoopCreated(WebDevToolsAgentClient* client)
132     {
133         if (s_instance)
134             return;
135         s_instance = new ClientMessageLoopAdapter(client->createClientMessageLoop());
136         WebCore::ScriptDebugServer::shared().setClientMessageLoop(s_instance);
137     }
138
139     static void inspectedViewClosed(WebViewImpl* view)
140     {
141         if (s_instance)
142             s_instance->m_frozenViews.remove(view);
143     }
144
145     static void didNavigate()
146     {
147         // Release render thread if necessary.
148         if (s_instance && s_instance->m_running)
149             WebCore::ScriptDebugServer::shared().continueProgram();
150     }
151
152 private:
153     ClientMessageLoopAdapter(PassOwnPtr<WebKit::WebDevToolsAgentClient::WebKitClientMessageLoop> messageLoop)
154         : m_running(false)
155         , m_messageLoop(messageLoop) { }
156
157
158     virtual void run(Page* page)
159     {
160         if (m_running)
161             return;
162         m_running = true;
163
164         Vector<WebViewImpl*> views;
165
166         // 1. Disable input events.
167         HashSet<Page*>::const_iterator end =  page->group().pages().end();
168         for (HashSet<Page*>::const_iterator it =  page->group().pages().begin(); it != end; ++it) {
169             WebViewImpl* view = WebViewImpl::fromPage(*it);
170             m_frozenViews.add(view);
171             views.append(view);
172             view->setIgnoreInputEvents(true);
173         }
174
175         // 2. Disable active objects
176         WebView::willEnterModalLoop();
177
178         // 3. Process messages until quitNow is called.
179         m_messageLoop->run();
180
181         // 4. Resume active objects
182         WebView::didExitModalLoop();
183
184         // 5. Resume input events.
185         for (Vector<WebViewImpl*>::iterator it = views.begin(); it != views.end(); ++it) {
186             if (m_frozenViews.contains(*it)) {
187                 // The view was not closed during the dispatch.
188                 (*it)->setIgnoreInputEvents(false);
189             }
190         }
191
192         // 6. All views have been resumed, clear the set.
193         m_frozenViews.clear();
194
195         m_running = false;
196     }
197
198     virtual void quitNow()
199     {
200         m_messageLoop->quitNow();
201     }
202
203     bool m_running;
204     OwnPtr<WebKit::WebDevToolsAgentClient::WebKitClientMessageLoop> m_messageLoop;
205     typedef HashSet<WebViewImpl*> FrozenViewsSet;
206     FrozenViewsSet m_frozenViews;
207     static ClientMessageLoopAdapter* s_instance;
208
209 };
210
211 ClientMessageLoopAdapter* ClientMessageLoopAdapter::s_instance = 0;
212
213 } //  namespace
214
215 WebDevToolsAgentImpl::WebDevToolsAgentImpl(
216     WebViewImpl* webViewImpl,
217     WebDevToolsAgentClient* client)
218     : m_hostId(client->hostIdentifier())
219     , m_client(client)
220     , m_webViewImpl(webViewImpl)
221     , m_apuAgentEnabled(false)
222     , m_resourceTrackingWasEnabled(false)
223     , m_attached(false)
224 {
225     DebuggerAgentManager::setExposeV8DebuggerProtocol(
226         client->exposeV8DebuggerProtocol());
227     m_debuggerAgentDelegateStub.set(new DebuggerAgentDelegateStub(this));
228     m_toolsAgentDelegateStub.set(new ToolsAgentDelegateStub(this));
229     m_apuAgentDelegateStub.set(new ApuAgentDelegateStub(this));
230 }
231
232 WebDevToolsAgentImpl::~WebDevToolsAgentImpl()
233 {
234     DebuggerAgentManager::onWebViewClosed(m_webViewImpl);
235     ClientMessageLoopAdapter::inspectedViewClosed(m_webViewImpl);
236     disposeUtilityContext();
237 }
238
239 void WebDevToolsAgentImpl::disposeUtilityContext()
240 {
241     if (!m_utilityContext.IsEmpty()) {
242         m_utilityContext.Dispose();
243         m_utilityContext.Clear();
244     }
245 }
246
247 void WebDevToolsAgentImpl::attach()
248 {
249     if (m_attached)
250         return;
251
252     if (!m_client->exposeV8DebuggerProtocol())
253         ClientMessageLoopAdapter::ensureClientMessageLoopCreated(m_client);
254
255     m_debuggerAgentImpl.set(
256         new DebuggerAgentImpl(m_webViewImpl,
257                               m_debuggerAgentDelegateStub.get(),
258                               this));
259     createInspectorFrontendProxy();
260
261     // Allow controller to send messages to the frontend.
262     InspectorController* ic = inspectorController();
263
264     { // TODO(yurys): the source should have already been pushed by the frontend.
265         v8::HandleScope scope;
266         v8::Context::Scope contextScope(m_utilityContext);
267         v8::Handle<v8::Value> constructorValue = m_utilityContext->Global()->Get(
268             v8::String::New("injectedScriptConstructor"));
269         if (constructorValue->IsFunction()) {
270             String source = WebCore::toWebCoreString(constructorValue);
271             ic->injectedScriptHost()->setInjectedScriptSource("(" + source + ")");
272         }
273     }
274
275     setInspectorFrontendProxyToInspectorController();
276     m_attached = true;
277 }
278
279 void WebDevToolsAgentImpl::detach()
280 {
281     // Prevent controller from sending messages to the frontend.
282     InspectorController* ic = m_webViewImpl->page()->inspectorController();
283     ic->disconnectFrontend();
284     ic->hideHighlight();
285     ic->close();
286     disposeUtilityContext();
287     m_debuggerAgentImpl.set(0);
288     m_attached = false;
289     m_apuAgentEnabled = false;
290 }
291
292 void WebDevToolsAgentImpl::didNavigate()
293 {
294     ClientMessageLoopAdapter::didNavigate();
295     DebuggerAgentManager::onNavigate();
296 }
297
298 void WebDevToolsAgentImpl::didClearWindowObject(WebFrameImpl* webframe)
299 {
300     DebuggerAgentManager::setHostId(webframe, m_hostId);
301     if (m_attached) {
302         // Push context id into the client if it is already attached.
303         m_debuggerAgentDelegateStub->setContextId(m_hostId);
304     }
305 }
306
307 void WebDevToolsAgentImpl::forceRepaint()
308 {
309     m_client->forceRepaint();
310 }
311
312 void WebDevToolsAgentImpl::dispatchOnInspectorController(int callId, const String& message)
313 {
314     String exception;
315     inspectorController()->inspectorBackendDispatcher()->dispatch(message, &exception);
316     m_toolsAgentDelegateStub->didDispatchOn(callId, "", exception);
317 }
318
319 void WebDevToolsAgentImpl::dispatchMessageFromFrontend(const WebDevToolsMessageData& data)
320 {
321     if (ToolsAgentDispatch::dispatch(this, data))
322         return;
323
324     if (!m_attached)
325         return;
326
327     if (m_debuggerAgentImpl.get() && DebuggerAgentDispatch::dispatch(m_debuggerAgentImpl.get(), data))
328         return;
329 }
330
331 void WebDevToolsAgentImpl::inspectElementAt(const WebPoint& point)
332 {
333     m_webViewImpl->inspectElementAt(point);
334 }
335
336 void WebDevToolsAgentImpl::setRuntimeFeatureEnabled(const WebString& feature, bool enabled)
337 {
338     if (feature == kApuAgentFeatureName)
339         setApuAgentEnabled(enabled);
340     else if (feature == kTimelineFeatureName)
341         setTimelineProfilingEnabled(enabled);
342     else if (feature == kResourceTrackingFeatureName) {
343         InspectorController* ic = m_webViewImpl->page()->inspectorController();
344         if (enabled)
345           ic->enableResourceTracking(false /* not sticky */, false /* no reload */);
346         else
347           ic->disableResourceTracking(false /* not sticky */);
348     }
349 }
350
351 void WebDevToolsAgentImpl::sendRpcMessage(const WebDevToolsMessageData& data)
352 {
353     m_client->sendMessageToFrontend(data);
354 }
355
356 void WebDevToolsAgentImpl::compileUtilityScripts()
357 {
358     v8::HandleScope handleScope;
359     v8::Context::Scope contextScope(m_utilityContext);
360     // Inject javascript into the context.
361     WebCString injectedScriptJs = m_client->injectedScriptSource();
362     v8::Script::Compile(v8::String::New(
363         injectedScriptJs.data(),
364         injectedScriptJs.length()))->Run();
365     WebCString injectDispatchJs = m_client->injectedScriptDispatcherSource();
366     v8::Script::Compile(v8::String::New(
367         injectDispatchJs.data(),
368         injectDispatchJs.length()))->Run();
369 }
370
371 void WebDevToolsAgentImpl::initDevToolsAgentHost()
372 {
373     BoundObject devtoolsAgentHost(m_utilityContext, this, "DevToolsAgentHost");
374     devtoolsAgentHost.addProtoFunction(
375         "dispatch",
376         WebDevToolsAgentImpl::jsDispatchOnClient);
377     devtoolsAgentHost.build();
378
379     v8::HandleScope scope;
380     v8::Context::Scope utilityScope(m_utilityContext);
381     // Call custom code to create inspector backend wrapper in the utility context
382     // instead of calling V8DOMWrapper::convertToV8Object that would create the
383     // wrapper in the Page main frame context.
384     v8::Handle<v8::Object> backendWrapper = createInspectorBackendV8Wrapper();
385     if (backendWrapper.IsEmpty())
386         return;
387     m_utilityContext->Global()->Set(v8::String::New("InspectorBackend"), backendWrapper);
388 }
389
390 v8::Local<v8::Object> WebDevToolsAgentImpl::createInspectorBackendV8Wrapper()
391 {
392     v8::Handle<v8::Function> function = V8InspectorBackend::GetTemplate()->GetFunction();
393     if (function.IsEmpty()) {
394         // Return if allocation failed.
395         return v8::Local<v8::Object>();
396     }
397     v8::Local<v8::Object> instance = SafeAllocation::newInstance(function);
398     if (instance.IsEmpty()) {
399         // Avoid setting the wrapper if allocation failed.
400         return v8::Local<v8::Object>();
401     }
402     InspectorBackend* backend = m_webViewImpl->page()->inspectorController()->inspectorBackend();
403     V8DOMWrapper::setDOMWrapper(instance, &V8InspectorBackend::info, backend);
404     // Create a weak reference to the v8 wrapper of InspectorBackend to deref
405     // InspectorBackend when the wrapper is garbage collected.
406     backend->ref();
407     v8::Persistent<v8::Object> weakHandle = v8::Persistent<v8::Object>::New(instance);
408     weakHandle.MakeWeak(backend, &InspectorBackendWeakReferenceCallback);
409     return instance;
410 }
411
412 void WebDevToolsAgentImpl::createInspectorFrontendProxy()
413 {
414     disposeUtilityContext();
415     m_utilityContext = v8::Context::New();
416     compileUtilityScripts();
417     initDevToolsAgentHost();
418     WebCString debuggerScriptJs = m_client->debuggerScriptSource();
419     WebCore::ScriptDebugServer::shared().setDebuggerScriptSource(
420         WebCore::String(debuggerScriptJs.data(), debuggerScriptJs.length()));
421 }
422
423 void WebDevToolsAgentImpl::setInspectorFrontendProxyToInspectorController()
424 {
425     v8::HandleScope scope;
426     ScriptState* state = ScriptState::forContext(
427         v8::Local<v8::Context>::New(m_utilityContext));
428     InspectorController* ic = inspectorController();
429     ic->connectFrontend(ScriptObject(state, m_utilityContext->Global()));
430 }
431
432 void WebDevToolsAgentImpl::setApuAgentEnabled(bool enabled)
433 {
434     m_apuAgentEnabled = enabled;
435     InspectorController* ic = m_webViewImpl->page()->inspectorController();
436     if (enabled) {
437         m_resourceTrackingWasEnabled = ic->resourceTrackingEnabled();
438         ic->startTimelineProfiler();
439         if (!m_resourceTrackingWasEnabled) {
440             // TODO(knorton): Introduce some kind of agents dependency here so that
441             // user could turn off resource tracking while apu agent is on.
442             ic->enableResourceTracking(false, false);
443         }
444         m_debuggerAgentImpl->setAutoContinueOnException(true);
445     } else {
446       ic->stopTimelineProfiler();
447       if (!m_resourceTrackingWasEnabled)
448           ic->disableResourceTracking(false);
449       m_resourceTrackingWasEnabled = false;
450     }
451     m_client->runtimeFeatureStateChanged(
452         kApuAgentFeatureName,
453         enabled);
454 }
455
456 // static
457 v8::Handle<v8::Value> WebDevToolsAgentImpl::jsDispatchOnClient(const v8::Arguments& args)
458 {
459     v8::TryCatch exceptionCatcher;
460     String message = WebCore::toWebCoreStringWithNullCheck(args[0]);
461     if (message.isEmpty() || exceptionCatcher.HasCaught())
462         return v8::Undefined();
463
464     WebDevToolsAgentImpl* agent = static_cast<WebDevToolsAgentImpl*>(v8::External::Cast(*args.Data())->Value());
465
466     if (!agent->m_apuAgentEnabled) {
467         agent->m_toolsAgentDelegateStub->dispatchOnClient(message);
468         return v8::Undefined();
469     }
470
471     String method = WebCore::toWebCoreStringWithNullCheck(args[1]);
472     if (method.isEmpty() || exceptionCatcher.HasCaught())
473         return v8::Undefined();
474
475     if (method != "addRecordToTimeline" && method != "updateResource" && method != "addResource")
476         return v8::Undefined();
477
478     agent->m_apuAgentDelegateStub->dispatchToApu(message);
479     return v8::Undefined();
480 }
481
482 WebCore::InspectorController* WebDevToolsAgentImpl::inspectorController()
483 {
484     if (Page* page = m_webViewImpl->page())
485         return page->inspectorController();
486     return 0;
487 }
488
489
490 //------- plugin resource load notifications ---------------
491 void WebDevToolsAgentImpl::identifierForInitialRequest(
492     unsigned long resourceId,
493     WebFrame* frame,
494     const WebURLRequest& request)
495 {
496     if (InspectorController* ic = inspectorController()) {
497         WebFrameImpl* webFrameImpl = static_cast<WebFrameImpl*>(frame);
498         FrameLoader* frameLoader = webFrameImpl->frame()->loader();
499         DocumentLoader* loader = frameLoader->activeDocumentLoader();
500         ic->identifierForInitialRequest(resourceId, loader, request.toResourceRequest());
501     }
502 }
503
504 void WebDevToolsAgentImpl::willSendRequest(unsigned long resourceId, WebURLRequest& request)
505 {
506     if (InspectorController* ic = inspectorController())
507         ic->willSendRequest(resourceId, request.toMutableResourceRequest(), ResourceResponse());
508 }
509
510 void WebDevToolsAgentImpl::didReceiveData(unsigned long resourceId, int length)
511 {
512     if (InspectorController* ic = inspectorController())
513         ic->didReceiveContentLength(resourceId, length);
514 }
515
516 void WebDevToolsAgentImpl::didReceiveResponse(unsigned long resourceId, const WebURLResponse& response)
517 {
518     if (InspectorController* ic = inspectorController())
519         ic->didReceiveResponse(resourceId, response.toResourceResponse());
520 }
521
522 void WebDevToolsAgentImpl::didFinishLoading(unsigned long resourceId)
523 {
524     if (InspectorController* ic = inspectorController())
525         ic->didFinishLoading(resourceId);
526 }
527
528 void WebDevToolsAgentImpl::didFailLoading(unsigned long resourceId, const WebURLError& error)
529 {
530     ResourceError resourceError;
531     if (InspectorController* ic = inspectorController())
532         ic->didFailLoading(resourceId, resourceError);
533 }
534
535 void WebDevToolsAgentImpl::inspectorDestroyed()
536 {
537     // Our lifetime is bound to the WebViewImpl.
538 }
539
540 void WebDevToolsAgentImpl::openInspectorFrontend(InspectorController*)
541 {
542 }
543
544 void WebDevToolsAgentImpl::highlight(Node* node)
545 {
546     // InspectorController does the actuall tracking of the highlighted node
547     // and the drawing of the highlight. Here we just make sure to invalidate
548     // the rects of the old and new nodes.
549     hideHighlight();
550 }
551
552 void WebDevToolsAgentImpl::hideHighlight()
553 {
554     // FIXME: able to invalidate a smaller rect.
555     // FIXME: Is it important to just invalidate the rect of the node region
556     // given that this is not on a critical codepath?  In order to do so, we'd
557     // have to take scrolling into account.
558     const WebSize& size = m_webViewImpl->size();
559     WebRect damagedRect(0, 0, size.width, size.height);
560     if (m_webViewImpl->client())
561         m_webViewImpl->client()->didInvalidateRect(damagedRect);
562 }
563
564 void WebDevToolsAgentImpl::populateSetting(const String& key, String* value)
565 {
566     WebString string;
567     m_webViewImpl->inspectorSetting(key, &string);
568     *value = string;
569 }
570
571 void WebDevToolsAgentImpl::storeSetting(const String& key, const String& value)
572 {
573     m_webViewImpl->setInspectorSetting(key, value);
574 }
575
576 bool WebDevToolsAgentImpl::sendMessageToFrontend(const WebCore::String& message)
577 {
578     WebDevToolsAgentImpl* devToolsAgent = static_cast<WebDevToolsAgentImpl*>(m_webViewImpl->devToolsAgent());
579     if (!devToolsAgent)
580         return false;
581
582     if (devToolsAgent->m_apuAgentEnabled && devToolsAgent->m_apuAgentDelegateStub) {
583         devToolsAgent->m_apuAgentDelegateStub->dispatchToApu(message);
584         return true;
585     }
586
587     WebVector<WebString> arguments(size_t(1));
588     arguments[0] = message;
589     WebDevToolsMessageData data;
590     data.className = "ToolsAgentDelegate";
591     data.methodName = "dispatchOnClient";
592     data.arguments.swap(arguments);
593     devToolsAgent->sendRpcMessage(data);
594     return true;
595 }
596
597 void WebDevToolsAgentImpl::resourceTrackingWasEnabled()
598 {
599     m_client->runtimeFeatureStateChanged(kResourceTrackingFeatureName, true);
600 }
601
602 void WebDevToolsAgentImpl::resourceTrackingWasDisabled()
603 {
604     m_client->runtimeFeatureStateChanged(kResourceTrackingFeatureName, false);
605 }
606
607 void WebDevToolsAgentImpl::timelineProfilerWasStarted()
608 {
609     m_client->runtimeFeatureStateChanged(kTimelineFeatureName, true);
610 }
611
612 void WebDevToolsAgentImpl::timelineProfilerWasStopped()
613 {
614     m_client->runtimeFeatureStateChanged(kTimelineFeatureName, false);
615 }
616
617 void WebDevToolsAgentImpl::evaluateInWebInspector(long callId, const WebString& script)
618 {
619     InspectorController* ic = inspectorController();
620     ic->evaluateForTestInFrontend(callId, script);
621 }
622
623 void WebDevToolsAgentImpl::setTimelineProfilingEnabled(bool enabled)
624 {
625     InspectorController* ic = inspectorController();
626     if (enabled)
627         ic->startTimelineProfiler();
628     else
629         ic->stopTimelineProfiler();
630 }
631
632 void WebDevToolsAgent::executeDebuggerCommand(const WebString& command, int callerId)
633 {
634     DebuggerAgentManager::executeDebuggerCommand(command, callerId);
635 }
636
637 void WebDevToolsAgent::debuggerPauseScript()
638 {
639     DebuggerAgentManager::pauseScript();
640 }
641
642 void WebDevToolsAgent::setMessageLoopDispatchHandler(MessageLoopDispatchHandler handler)
643 {
644     DebuggerAgentManager::setMessageLoopDispatchHandler(handler);
645 }
646
647 bool WebDevToolsAgent::dispatchMessageFromFrontendOnIOThread(WebDevToolsMessageTransport* transport, const WebDevToolsMessageData& data)
648 {
649     IORPCDelegate delegate(transport);
650     ProfilerAgentDelegateStub stub(&delegate);
651     ProfilerAgentImpl agent(&stub);
652     return ProfilerAgentDispatch::dispatch(&agent, data);
653 }
654
655 } // namespace WebKit