Home | History | Annotate | Download | only in src
      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 "InspectorController.h"
     42 #include "InspectorFrontend.h"
     43 #include "InspectorResource.h"
     44 #include "Node.h"
     45 #include "Page.h"
     46 #include "PlatformString.h"
     47 #include "ProfilerAgentImpl.h"
     48 #include "ResourceError.h"
     49 #include "ResourceRequest.h"
     50 #include "ResourceResponse.h"
     51 #include "ScriptObject.h"
     52 #include "ScriptState.h"
     53 #include "ScriptValue.h"
     54 #include "V8Binding.h"
     55 #include "V8InspectorBackend.h"
     56 #include "V8Proxy.h"
     57 #include "V8Utilities.h"
     58 #include "WebDataSource.h"
     59 #include "WebDevToolsAgentClient.h"
     60 #include "WebDevToolsMessageData.h"
     61 #include "WebFrameImpl.h"
     62 #include "WebString.h"
     63 #include "WebURL.h"
     64 #include "WebURLError.h"
     65 #include "WebURLRequest.h"
     66 #include "WebURLResponse.h"
     67 #include "WebViewImpl.h"
     68 #include <wtf/Noncopyable.h>
     69 #include <wtf/OwnPtr.h>
     70 
     71 using WebCore::Document;
     72 using WebCore::DocumentLoader;
     73 using WebCore::FrameLoader;
     74 using WebCore::InjectedScriptHost;
     75 using WebCore::InspectorBackend;
     76 using WebCore::InspectorController;
     77 using WebCore::InspectorFrontend;
     78 using WebCore::InspectorResource;
     79 using WebCore::Node;
     80 using WebCore::Page;
     81 using WebCore::ResourceError;
     82 using WebCore::ResourceRequest;
     83 using WebCore::ResourceResponse;
     84 using WebCore::SafeAllocation;
     85 using WebCore::ScriptObject;
     86 using WebCore::ScriptState;
     87 using WebCore::ScriptValue;
     88 using WebCore::String;
     89 using WebCore::V8ClassIndex;
     90 using WebCore::V8DOMWrapper;
     91 using WebCore::V8InspectorBackend;
     92 using WebCore::V8Proxy;
     93 
     94 namespace WebKit {
     95 
     96 namespace {
     97 
     98 void InspectorBackendWeakReferenceCallback(v8::Persistent<v8::Value> object, void* parameter)
     99 {
    100     InspectorBackend* backend = static_cast<InspectorBackend*>(parameter);
    101     backend->deref();
    102     object.Dispose();
    103 }
    104 
    105 void SetApuAgentEnabledInUtilityContext(v8::Handle<v8::Context> context, bool enabled)
    106 {
    107     v8::HandleScope handleScope;
    108     v8::Context::Scope contextScope(context);
    109     v8::Handle<v8::Object> dispatcher = v8::Local<v8::Object>::Cast(
    110         context->Global()->Get(v8::String::New("ApuAgentDispatcher")));
    111     if (dispatcher.IsEmpty())
    112         return;
    113     dispatcher->Set(v8::String::New("enabled"), v8::Boolean::New(enabled));
    114 }
    115 
    116 // TODO(pfeldman): Make this public in WebDevToolsAgent API.
    117 static const char kApuAgentFeatureName[] = "apu-agent";
    118 
    119 // Keep these in sync with the ones in inject_dispatch.js.
    120 static const char kTimelineFeatureName[] = "timeline-profiler";
    121 static const char kResourceTrackingFeatureName[] = "resource-tracking";
    122 
    123 class IORPCDelegate : public DevToolsRPC::Delegate, public Noncopyable {
    124 public:
    125     IORPCDelegate() { }
    126     virtual ~IORPCDelegate() { }
    127     virtual void sendRpcMessage(const WebDevToolsMessageData& data)
    128     {
    129         WebDevToolsAgentClient::sendMessageToFrontendOnIOThread(data);
    130     }
    131 };
    132 
    133 } //  namespace
    134 
    135 WebDevToolsAgentImpl::WebDevToolsAgentImpl(
    136     WebViewImpl* webViewImpl,
    137     WebDevToolsAgentClient* client)
    138     : m_hostId(client->hostIdentifier())
    139     , m_client(client)
    140     , m_webViewImpl(webViewImpl)
    141     , m_apuAgentEnabled(false)
    142     , m_resourceTrackingWasEnabled(false)
    143     , m_attached(false)
    144 {
    145     m_debuggerAgentDelegateStub.set(new DebuggerAgentDelegateStub(this));
    146     m_toolsAgentDelegateStub.set(new ToolsAgentDelegateStub(this));
    147     m_apuAgentDelegateStub.set(new ApuAgentDelegateStub(this));
    148 }
    149 
    150 WebDevToolsAgentImpl::~WebDevToolsAgentImpl()
    151 {
    152     DebuggerAgentManager::onWebViewClosed(m_webViewImpl);
    153     disposeUtilityContext();
    154 }
    155 
    156 void WebDevToolsAgentImpl::disposeUtilityContext()
    157 {
    158     if (!m_utilityContext.IsEmpty()) {
    159         m_utilityContext.Dispose();
    160         m_utilityContext.Clear();
    161     }
    162 }
    163 
    164 void WebDevToolsAgentImpl::unhideResourcesPanelIfNecessary()
    165 {
    166     InspectorController* ic = m_webViewImpl->page()->inspectorController();
    167     ic->ensureResourceTrackingSettingsLoaded();
    168     String command = String::format("[\"setResourcesPanelEnabled\", %s]",
    169         ic->resourceTrackingEnabled() ? "true" : "false");
    170     m_toolsAgentDelegateStub->dispatchOnClient(command);
    171 }
    172 
    173 void WebDevToolsAgentImpl::attach()
    174 {
    175     if (m_attached)
    176         return;
    177     m_debuggerAgentImpl.set(
    178         new DebuggerAgentImpl(m_webViewImpl,
    179                               m_debuggerAgentDelegateStub.get(),
    180                               this));
    181     resetInspectorFrontendProxy();
    182     unhideResourcesPanelIfNecessary();
    183     // Allow controller to send messages to the frontend.
    184     InspectorController* ic = inspectorController();
    185 
    186     { // TODO(yurys): the source should have already been pushed by the frontend.
    187         v8::HandleScope scope;
    188         v8::Context::Scope contextScope(m_utilityContext);
    189         v8::Handle<v8::Value> constructorValue = m_utilityContext->Global()->Get(
    190             v8::String::New("injectedScriptConstructor"));
    191         if (constructorValue->IsFunction()) {
    192             String source = WebCore::toWebCoreString(constructorValue);
    193             ic->injectedScriptHost()->setInjectedScriptSource("(" + source + ")");
    194         }
    195     }
    196 
    197     ic->setWindowVisible(true, false);
    198     m_attached = true;
    199 }
    200 
    201 void WebDevToolsAgentImpl::detach()
    202 {
    203     // Prevent controller from sending messages to the frontend.
    204     InspectorController* ic = m_webViewImpl->page()->inspectorController();
    205     ic->hideHighlight();
    206     ic->close();
    207     disposeUtilityContext();
    208     m_debuggerAgentImpl.set(0);
    209     m_attached = false;
    210     m_apuAgentEnabled = false;
    211 }
    212 
    213 void WebDevToolsAgentImpl::didNavigate()
    214 {
    215     DebuggerAgentManager::onNavigate();
    216 }
    217 
    218 void WebDevToolsAgentImpl::didCommitProvisionalLoad(WebFrameImpl* webframe, bool isNewNavigation)
    219 {
    220     if (!m_attached)
    221         return;
    222     WebDataSource* ds = webframe->dataSource();
    223     const WebURLRequest& request = ds->request();
    224     WebURL url = ds->hasUnreachableURL() ?
    225         ds->unreachableURL() :
    226         request.url();
    227     if (!webframe->parent()) {
    228         resetInspectorFrontendProxy();
    229         m_toolsAgentDelegateStub->frameNavigate(WebCore::KURL(url).string());
    230         SetApuAgentEnabledInUtilityContext(m_utilityContext, m_apuAgentEnabled);
    231         unhideResourcesPanelIfNecessary();
    232     }
    233 }
    234 
    235 void WebDevToolsAgentImpl::didClearWindowObject(WebFrameImpl* webframe)
    236 {
    237     DebuggerAgentManager::setHostId(webframe, m_hostId);
    238     if (m_attached) {
    239         // Push context id into the client if it is already attached.
    240         m_debuggerAgentDelegateStub->setContextId(m_hostId);
    241     }
    242 }
    243 
    244 void WebDevToolsAgentImpl::forceRepaint()
    245 {
    246     m_client->forceRepaint();
    247 }
    248 
    249 void WebDevToolsAgentImpl::dispatchOnInspectorController(int callId, const String& functionName, const String& jsonArgs)
    250 {
    251     String result;
    252     String exception;
    253     result = m_debuggerAgentImpl->executeUtilityFunction(m_utilityContext, callId,
    254         "InspectorControllerDispatcher", functionName, jsonArgs, false /* is sync */, &exception);
    255     m_toolsAgentDelegateStub->didDispatchOn(callId, result, exception);
    256 }
    257 
    258 void WebDevToolsAgentImpl::dispatchOnInjectedScript(int callId, int injectedScriptId, const String& functionName, const String& jsonArgs, bool async)
    259 {
    260     inspectorController()->inspectorBackend()->dispatchOnInjectedScript(
    261         callId,
    262         injectedScriptId,
    263         functionName,
    264         jsonArgs,
    265         async);
    266 }
    267 
    268 void WebDevToolsAgentImpl::dispatchMessageFromFrontend(const WebDevToolsMessageData& data)
    269 {
    270     if (ToolsAgentDispatch::dispatch(this, data))
    271         return;
    272 
    273     if (!m_attached)
    274         return;
    275 
    276     if (m_debuggerAgentImpl.get() && DebuggerAgentDispatch::dispatch(m_debuggerAgentImpl.get(), data))
    277         return;
    278 }
    279 
    280 void WebDevToolsAgentImpl::inspectElementAt(const WebPoint& point)
    281 {
    282     m_webViewImpl->inspectElementAt(point);
    283 }
    284 
    285 void WebDevToolsAgentImpl::setRuntimeFeatureEnabled(const WebString& feature, bool enabled)
    286 {
    287     if (feature == kApuAgentFeatureName)
    288         setApuAgentEnabled(enabled);
    289     else if (feature == kTimelineFeatureName)
    290         setTimelineProfilingEnabled(enabled);
    291     else if (feature == kResourceTrackingFeatureName) {
    292         InspectorController* ic = m_webViewImpl->page()->inspectorController();
    293         if (enabled)
    294           ic->enableResourceTracking(false /* not sticky */, false /* no reload */);
    295         else
    296           ic->disableResourceTracking(false /* not sticky */);
    297     }
    298 }
    299 
    300 void WebDevToolsAgentImpl::sendRpcMessage(const WebDevToolsMessageData& data)
    301 {
    302     m_client->sendMessageToFrontend(data);
    303 }
    304 
    305 void WebDevToolsAgentImpl::compileUtilityScripts()
    306 {
    307     v8::HandleScope handleScope;
    308     v8::Context::Scope contextScope(m_utilityContext);
    309     // Inject javascript into the context.
    310     WebCString injectedScriptJs = m_client->injectedScriptSource();
    311     v8::Script::Compile(v8::String::New(
    312         injectedScriptJs.data(),
    313         injectedScriptJs.length()))->Run();
    314     WebCString injectDispatchJs = m_client->injectedScriptDispatcherSource();
    315     v8::Script::Compile(v8::String::New(
    316         injectDispatchJs.data(),
    317         injectDispatchJs.length()))->Run();
    318 }
    319 
    320 void WebDevToolsAgentImpl::initDevToolsAgentHost()
    321 {
    322     BoundObject devtoolsAgentHost(m_utilityContext, this, "DevToolsAgentHost");
    323     devtoolsAgentHost.addProtoFunction(
    324         "dispatch",
    325         WebDevToolsAgentImpl::jsDispatchOnClient);
    326     devtoolsAgentHost.addProtoFunction(
    327         "dispatchToApu",
    328         WebDevToolsAgentImpl::jsDispatchToApu);
    329     devtoolsAgentHost.addProtoFunction(
    330         "evaluateOnSelf",
    331         WebDevToolsAgentImpl::jsEvaluateOnSelf);
    332     devtoolsAgentHost.addProtoFunction(
    333         "runtimeFeatureStateChanged",
    334         WebDevToolsAgentImpl::jsOnRuntimeFeatureStateChanged);
    335     devtoolsAgentHost.build();
    336 
    337     v8::HandleScope scope;
    338     v8::Context::Scope utilityScope(m_utilityContext);
    339     // Call custom code to create inspector backend wrapper in the utility context
    340     // instead of calling V8DOMWrapper::convertToV8Object that would create the
    341     // wrapper in the Page main frame context.
    342     v8::Handle<v8::Object> backendWrapper = createInspectorBackendV8Wrapper();
    343     if (backendWrapper.IsEmpty())
    344         return;
    345     m_utilityContext->Global()->Set(v8::String::New("InspectorBackend"), backendWrapper);
    346 }
    347 
    348 v8::Local<v8::Object> WebDevToolsAgentImpl::createInspectorBackendV8Wrapper()
    349 {
    350     V8ClassIndex::V8WrapperType descriptorType = V8ClassIndex::INSPECTORBACKEND;
    351     v8::Handle<v8::Function> function = V8InspectorBackend::GetTemplate()->GetFunction();
    352     if (function.IsEmpty()) {
    353         // Return if allocation failed.
    354         return v8::Local<v8::Object>();
    355     }
    356     v8::Local<v8::Object> instance = SafeAllocation::newInstance(function);
    357     if (instance.IsEmpty()) {
    358         // Avoid setting the wrapper if allocation failed.
    359         return v8::Local<v8::Object>();
    360     }
    361     InspectorBackend* backend = m_webViewImpl->page()->inspectorController()->inspectorBackend();
    362     V8DOMWrapper::setDOMWrapper(instance, V8ClassIndex::ToInt(descriptorType), backend);
    363     // Create a weak reference to the v8 wrapper of InspectorBackend to deref
    364     // InspectorBackend when the wrapper is garbage collected.
    365     backend->ref();
    366     v8::Persistent<v8::Object> weakHandle = v8::Persistent<v8::Object>::New(instance);
    367     weakHandle.MakeWeak(backend, &InspectorBackendWeakReferenceCallback);
    368     return instance;
    369 }
    370 
    371 void WebDevToolsAgentImpl::resetInspectorFrontendProxy()
    372 {
    373     disposeUtilityContext();
    374     m_debuggerAgentImpl->createUtilityContext(m_webViewImpl->page()->mainFrame(), &m_utilityContext);
    375     compileUtilityScripts();
    376     initDevToolsAgentHost();
    377 
    378     v8::HandleScope scope;
    379     v8::Context::Scope contextScope(m_utilityContext);
    380     ScriptState* state = ScriptState::forContext(
    381         v8::Local<v8::Context>::New(m_utilityContext));
    382     InspectorController* ic = inspectorController();
    383     ic->setFrontendProxyObject(state, ScriptObject(state, m_utilityContext->Global()));
    384 }
    385 
    386 void WebDevToolsAgentImpl::setApuAgentEnabled(bool enabled)
    387 {
    388     m_apuAgentEnabled = enabled;
    389     SetApuAgentEnabledInUtilityContext(m_utilityContext, enabled);
    390     InspectorController* ic = m_webViewImpl->page()->inspectorController();
    391     if (enabled) {
    392         m_resourceTrackingWasEnabled = ic->resourceTrackingEnabled();
    393         ic->startTimelineProfiler();
    394         if (!m_resourceTrackingWasEnabled) {
    395             // TODO(knorton): Introduce some kind of agents dependency here so that
    396             // user could turn off resource tracking while apu agent is on.
    397             ic->enableResourceTracking(false, false);
    398         }
    399         m_debuggerAgentImpl->setAutoContinueOnException(true);
    400     } else {
    401       ic->stopTimelineProfiler();
    402       if (!m_resourceTrackingWasEnabled)
    403           ic->disableResourceTracking(false);
    404       m_resourceTrackingWasEnabled = false;
    405     }
    406     m_client->runtimeFeatureStateChanged(
    407         kApuAgentFeatureName,
    408         enabled);
    409 }
    410 
    411 // static
    412 v8::Handle<v8::Value> WebDevToolsAgentImpl::jsDispatchOnClient(const v8::Arguments& args)
    413 {
    414     v8::TryCatch exceptionCatcher;
    415     String message = WebCore::toWebCoreStringWithNullCheck(args[0]);
    416     if (message.isEmpty() || exceptionCatcher.HasCaught())
    417         return v8::Undefined();
    418     WebDevToolsAgentImpl* agent = static_cast<WebDevToolsAgentImpl*>(v8::External::Cast(*args.Data())->Value());
    419     agent->m_toolsAgentDelegateStub->dispatchOnClient(message);
    420     return v8::Undefined();
    421 }
    422 
    423 // static
    424 v8::Handle<v8::Value> WebDevToolsAgentImpl::jsDispatchToApu(const v8::Arguments& args)
    425 {
    426     v8::TryCatch exceptionCatcher;
    427     String message = WebCore::toWebCoreStringWithNullCheck(args[0]);
    428     if (message.isEmpty() || exceptionCatcher.HasCaught())
    429         return v8::Undefined();
    430     WebDevToolsAgentImpl* agent = static_cast<WebDevToolsAgentImpl*>(
    431         v8::External::Cast(*args.Data())->Value());
    432     agent->m_apuAgentDelegateStub->dispatchToApu(message);
    433     return v8::Undefined();
    434 }
    435 
    436 // static
    437 v8::Handle<v8::Value> WebDevToolsAgentImpl::jsEvaluateOnSelf(const v8::Arguments& args)
    438 {
    439     String code;
    440     {
    441         v8::TryCatch exceptionCatcher;
    442         code = WebCore::toWebCoreStringWithNullCheck(args[0]);
    443         if (code.isEmpty() || exceptionCatcher.HasCaught())
    444             return v8::Undefined();
    445     }
    446     WebDevToolsAgentImpl* agent = static_cast<WebDevToolsAgentImpl*>(v8::External::Cast(*args.Data())->Value());
    447     v8::Context::Scope(agent->m_utilityContext);
    448     V8Proxy* proxy = V8Proxy::retrieve(agent->m_webViewImpl->page()->mainFrame());
    449     v8::Local<v8::Value> result = proxy->runScript(v8::Script::Compile(v8::String::New(code.utf8().data())), true);
    450     return result;
    451 }
    452 
    453 // static
    454 v8::Handle<v8::Value> WebDevToolsAgentImpl::jsOnRuntimeFeatureStateChanged(const v8::Arguments& args)
    455 {
    456     v8::TryCatch exceptionCatcher;
    457     String feature = WebCore::toWebCoreStringWithNullCheck(args[0]);
    458     bool enabled = args[1]->ToBoolean()->Value();
    459     if (feature.isEmpty() || exceptionCatcher.HasCaught())
    460         return v8::Undefined();
    461     WebDevToolsAgentImpl* agent = static_cast<WebDevToolsAgentImpl*>(v8::External::Cast(*args.Data())->Value());
    462     agent->m_client->runtimeFeatureStateChanged(feature, enabled);
    463     return v8::Undefined();
    464 }
    465 
    466 
    467 WebCore::InspectorController* WebDevToolsAgentImpl::inspectorController()
    468 {
    469     if (Page* page = m_webViewImpl->page())
    470         return page->inspectorController();
    471     return 0;
    472 }
    473 
    474 
    475 //------- plugin resource load notifications ---------------
    476 void WebDevToolsAgentImpl::identifierForInitialRequest(
    477     unsigned long resourceId,
    478     WebFrame* frame,
    479     const WebURLRequest& request)
    480 {
    481     if (InspectorController* ic = inspectorController()) {
    482         WebFrameImpl* webFrameImpl = static_cast<WebFrameImpl*>(frame);
    483         FrameLoader* frameLoader = webFrameImpl->frame()->loader();
    484         DocumentLoader* loader = frameLoader->activeDocumentLoader();
    485         ic->identifierForInitialRequest(resourceId, loader, request.toResourceRequest());
    486     }
    487 }
    488 
    489 void WebDevToolsAgentImpl::willSendRequest(unsigned long resourceId, const WebURLRequest& request)
    490 {
    491     if (InspectorController* ic = inspectorController())
    492         ic->willSendRequest(resourceId, request.toResourceRequest(), ResourceResponse());
    493 }
    494 
    495 void WebDevToolsAgentImpl::didReceiveData(unsigned long resourceId, int length)
    496 {
    497     if (InspectorController* ic = inspectorController())
    498         ic->didReceiveContentLength(resourceId, length);
    499 }
    500 
    501 void WebDevToolsAgentImpl::didReceiveResponse(unsigned long resourceId, const WebURLResponse& response)
    502 {
    503     if (InspectorController* ic = inspectorController())
    504         ic->didReceiveResponse(resourceId, response.toResourceResponse());
    505 }
    506 
    507 void WebDevToolsAgentImpl::didFinishLoading(unsigned long resourceId)
    508 {
    509     if (InspectorController* ic = inspectorController())
    510         ic->didFinishLoading(resourceId);
    511 }
    512 
    513 void WebDevToolsAgentImpl::didFailLoading(unsigned long resourceId, const WebURLError& error)
    514 {
    515     ResourceError resourceError;
    516     if (InspectorController* ic = inspectorController())
    517         ic->didFailLoading(resourceId, resourceError);
    518 }
    519 
    520 void WebDevToolsAgentImpl::evaluateInWebInspector(long callId, const WebString& script)
    521 {
    522     InspectorController* ic = inspectorController();
    523     ic->evaluateForTestInFrontend(callId, script);
    524 }
    525 
    526 void WebDevToolsAgentImpl::setTimelineProfilingEnabled(bool enabled)
    527 {
    528     InspectorController* ic = inspectorController();
    529     if (enabled)
    530         ic->startTimelineProfiler();
    531     else
    532         ic->stopTimelineProfiler();
    533 }
    534 
    535 WebDevToolsAgent* WebDevToolsAgent::create(WebView* webview, WebDevToolsAgentClient* client)
    536 {
    537     return new WebDevToolsAgentImpl(static_cast<WebViewImpl*>(webview), client);
    538 }
    539 
    540 void WebDevToolsAgent::executeDebuggerCommand(const WebString& command, int callerId)
    541 {
    542     DebuggerAgentManager::executeDebuggerCommand(command, callerId);
    543 }
    544 
    545 void WebDevToolsAgent::debuggerPauseScript()
    546 {
    547     DebuggerAgentManager::pauseScript();
    548 }
    549 
    550 void WebDevToolsAgent::setMessageLoopDispatchHandler(MessageLoopDispatchHandler handler)
    551 {
    552     DebuggerAgentManager::setMessageLoopDispatchHandler(handler);
    553 }
    554 
    555 bool WebDevToolsAgent::dispatchMessageFromFrontendOnIOThread(const WebDevToolsMessageData& data)
    556 {
    557     IORPCDelegate transport;
    558     ProfilerAgentDelegateStub stub(&transport);
    559     ProfilerAgentImpl agent(&stub);
    560     return ProfilerAgentDispatch::dispatch(&agent, data);
    561 }
    562 
    563 } // namespace WebKit
    564