diff options
Diffstat (limited to 'WebKit/chromium/src/WebDevToolsAgentImpl.cpp')
| -rw-r--r-- | WebKit/chromium/src/WebDevToolsAgentImpl.cpp | 382 |
1 files changed, 219 insertions, 163 deletions
diff --git a/WebKit/chromium/src/WebDevToolsAgentImpl.cpp b/WebKit/chromium/src/WebDevToolsAgentImpl.cpp index 9ce35b4..1a65bfe 100644 --- a/WebKit/chromium/src/WebDevToolsAgentImpl.cpp +++ b/WebKit/chromium/src/WebDevToolsAgentImpl.cpp @@ -38,32 +38,37 @@ #include "EventListener.h" #include "InjectedScriptHost.h" #include "InspectorBackend.h" +#include "InspectorBackendDispatcher.h" #include "InspectorController.h" #include "InspectorFrontend.h" #include "InspectorResource.h" #include "Node.h" #include "Page.h" +#include "PageGroup.h" #include "PlatformString.h" #include "ProfilerAgentImpl.h" #include "ResourceError.h" #include "ResourceRequest.h" #include "ResourceResponse.h" +#include "ScriptDebugServer.h" #include "ScriptObject.h" #include "ScriptState.h" #include "ScriptValue.h" #include "V8Binding.h" -#include "V8InspectorBackend.h" #include "V8Proxy.h" #include "V8Utilities.h" #include "WebDataSource.h" #include "WebDevToolsAgentClient.h" #include "WebDevToolsMessageData.h" +#include "WebDevToolsMessageTransport.h" #include "WebFrameImpl.h" +#include "WebRect.h" #include "WebString.h" #include "WebURL.h" #include "WebURLError.h" #include "WebURLRequest.h" #include "WebURLResponse.h" +#include "WebViewClient.h" #include "WebViewImpl.h" #include <wtf/Noncopyable.h> #include <wtf/OwnPtr.h> @@ -86,9 +91,7 @@ using WebCore::ScriptObject; using WebCore::ScriptState; using WebCore::ScriptValue; using WebCore::String; -using WebCore::V8ClassIndex; using WebCore::V8DOMWrapper; -using WebCore::V8InspectorBackend; using WebCore::V8Proxy; namespace WebKit { @@ -102,34 +105,109 @@ void InspectorBackendWeakReferenceCallback(v8::Persistent<v8::Value> object, voi object.Dispose(); } -void SetApuAgentEnabledInUtilityContext(v8::Handle<v8::Context> context, bool enabled) -{ - v8::HandleScope handleScope; - v8::Context::Scope contextScope(context); - v8::Handle<v8::Object> dispatcher = v8::Local<v8::Object>::Cast( - context->Global()->Get(v8::String::New("ApuAgentDispatcher"))); - if (dispatcher.IsEmpty()) - return; - dispatcher->Set(v8::String::New("enabled"), v8::Boolean::New(enabled)); -} - -// TODO(pfeldman): Make this public in WebDevToolsAgent API. -static const char kApuAgentFeatureName[] = "apu-agent"; - -// Keep these in sync with the ones in inject_dispatch.js. -static const char kTimelineFeatureName[] = "timeline-profiler"; static const char kResourceTrackingFeatureName[] = "resource-tracking"; +static const char kTimelineFeatureName[] = "timeline-profiler"; +static const char kApuAgentFeatureName[] = "apu-agent"; class IORPCDelegate : public DevToolsRPC::Delegate, public Noncopyable { public: - IORPCDelegate() { } + IORPCDelegate() : m_transport(0) { } + explicit IORPCDelegate(WebDevToolsMessageTransport* transport) : m_transport(transport) { } virtual ~IORPCDelegate() { } virtual void sendRpcMessage(const WebDevToolsMessageData& data) { - WebDevToolsAgentClient::sendMessageToFrontendOnIOThread(data); + if (m_transport) + m_transport->sendMessageToFrontendOnIOThread(data); + } + +private: + WebDevToolsMessageTransport* m_transport; +}; + +class ClientMessageLoopAdapter : public WebCore::ScriptDebugServer::ClientMessageLoop { +public: + static void ensureClientMessageLoopCreated(WebDevToolsAgentClient* client) + { + if (s_instance) + return; + s_instance = new ClientMessageLoopAdapter(client->createClientMessageLoop()); + WebCore::ScriptDebugServer::shared().setClientMessageLoop(s_instance); + } + + static void inspectedViewClosed(WebViewImpl* view) + { + if (s_instance) + s_instance->m_frozenViews.remove(view); + } + + static void didNavigate() + { + // Release render thread if necessary. + if (s_instance && s_instance->m_running) + WebCore::ScriptDebugServer::shared().continueProgram(); + } + +private: + ClientMessageLoopAdapter(PassOwnPtr<WebKit::WebDevToolsAgentClient::WebKitClientMessageLoop> messageLoop) + : m_running(false) + , m_messageLoop(messageLoop) { } + + + virtual void run(Page* page) + { + if (m_running) + return; + m_running = true; + + Vector<WebViewImpl*> views; + + // 1. Disable input events. + HashSet<Page*>::const_iterator end = page->group().pages().end(); + for (HashSet<Page*>::const_iterator it = page->group().pages().begin(); it != end; ++it) { + WebViewImpl* view = WebViewImpl::fromPage(*it); + m_frozenViews.add(view); + views.append(view); + view->setIgnoreInputEvents(true); + } + + // 2. Disable active objects + WebView::willEnterModalLoop(); + + // 3. Process messages until quitNow is called. + m_messageLoop->run(); + + // 4. Resume active objects + WebView::didExitModalLoop(); + + // 5. Resume input events. + for (Vector<WebViewImpl*>::iterator it = views.begin(); it != views.end(); ++it) { + if (m_frozenViews.contains(*it)) { + // The view was not closed during the dispatch. + (*it)->setIgnoreInputEvents(false); + } + } + + // 6. All views have been resumed, clear the set. + m_frozenViews.clear(); + + m_running = false; + } + + virtual void quitNow() + { + m_messageLoop->quitNow(); } + + bool m_running; + OwnPtr<WebKit::WebDevToolsAgentClient::WebKitClientMessageLoop> m_messageLoop; + typedef HashSet<WebViewImpl*> FrozenViewsSet; + FrozenViewsSet m_frozenViews; + static ClientMessageLoopAdapter* s_instance; + }; +ClientMessageLoopAdapter* ClientMessageLoopAdapter::s_instance = 0; + } // namespace WebDevToolsAgentImpl::WebDevToolsAgentImpl( @@ -142,6 +220,8 @@ WebDevToolsAgentImpl::WebDevToolsAgentImpl( , m_resourceTrackingWasEnabled(false) , m_attached(false) { + DebuggerAgentManager::setExposeV8DebuggerProtocol( + client->exposeV8DebuggerProtocol()); m_debuggerAgentDelegateStub.set(new DebuggerAgentDelegateStub(this)); m_toolsAgentDelegateStub.set(new ToolsAgentDelegateStub(this)); m_apuAgentDelegateStub.set(new ApuAgentDelegateStub(this)); @@ -150,6 +230,7 @@ WebDevToolsAgentImpl::WebDevToolsAgentImpl( WebDevToolsAgentImpl::~WebDevToolsAgentImpl() { DebuggerAgentManager::onWebViewClosed(m_webViewImpl); + ClientMessageLoopAdapter::inspectedViewClosed(m_webViewImpl); disposeUtilityContext(); } @@ -161,25 +242,20 @@ void WebDevToolsAgentImpl::disposeUtilityContext() } } -void WebDevToolsAgentImpl::unhideResourcesPanelIfNecessary() -{ - InspectorController* ic = m_webViewImpl->page()->inspectorController(); - ic->ensureResourceTrackingSettingsLoaded(); - String command = String::format("[\"setResourcesPanelEnabled\", %s]", - ic->resourceTrackingEnabled() ? "true" : "false"); - m_toolsAgentDelegateStub->dispatchOnClient(command); -} - void WebDevToolsAgentImpl::attach() { if (m_attached) return; + + if (!m_client->exposeV8DebuggerProtocol()) + ClientMessageLoopAdapter::ensureClientMessageLoopCreated(m_client); + m_debuggerAgentImpl.set( new DebuggerAgentImpl(m_webViewImpl, m_debuggerAgentDelegateStub.get(), this)); - resetInspectorFrontendProxy(); - unhideResourcesPanelIfNecessary(); + createInspectorFrontendProxy(); + // Allow controller to send messages to the frontend. InspectorController* ic = inspectorController(); @@ -194,7 +270,7 @@ void WebDevToolsAgentImpl::attach() } } - ic->setWindowVisible(true, false); + setInspectorFrontendProxyToInspectorController(); m_attached = true; } @@ -202,6 +278,7 @@ void WebDevToolsAgentImpl::detach() { // Prevent controller from sending messages to the frontend. InspectorController* ic = m_webViewImpl->page()->inspectorController(); + ic->disconnectFrontend(); ic->hideHighlight(); ic->close(); disposeUtilityContext(); @@ -212,26 +289,10 @@ void WebDevToolsAgentImpl::detach() void WebDevToolsAgentImpl::didNavigate() { + ClientMessageLoopAdapter::didNavigate(); DebuggerAgentManager::onNavigate(); } -void WebDevToolsAgentImpl::didCommitProvisionalLoad(WebFrameImpl* webframe, bool isNewNavigation) -{ - if (!m_attached) - return; - WebDataSource* ds = webframe->dataSource(); - const WebURLRequest& request = ds->request(); - WebURL url = ds->hasUnreachableURL() ? - ds->unreachableURL() : - request.url(); - if (!webframe->parent()) { - resetInspectorFrontendProxy(); - m_toolsAgentDelegateStub->frameNavigate(WebCore::KURL(url).string()); - SetApuAgentEnabledInUtilityContext(m_utilityContext, m_apuAgentEnabled); - unhideResourcesPanelIfNecessary(); - } -} - void WebDevToolsAgentImpl::didClearWindowObject(WebFrameImpl* webframe) { DebuggerAgentManager::setHostId(webframe, m_hostId); @@ -246,23 +307,9 @@ void WebDevToolsAgentImpl::forceRepaint() m_client->forceRepaint(); } -void WebDevToolsAgentImpl::dispatchOnInspectorController(int callId, const String& functionName, const String& jsonArgs) +void WebDevToolsAgentImpl::dispatchOnInspectorController(const String& message) { - String result; - String exception; - result = m_debuggerAgentImpl->executeUtilityFunction(m_utilityContext, callId, - "InspectorControllerDispatcher", functionName, jsonArgs, false /* is sync */, &exception); - m_toolsAgentDelegateStub->didDispatchOn(callId, result, exception); -} - -void WebDevToolsAgentImpl::dispatchOnInjectedScript(int callId, int injectedScriptId, const String& functionName, const String& jsonArgs, bool async) -{ - inspectorController()->inspectorBackend()->dispatchOnInjectedScript( - callId, - injectedScriptId, - functionName, - jsonArgs, - async); + inspectorController()->inspectorBackendDispatcher()->dispatch(message); } void WebDevToolsAgentImpl::dispatchMessageFromFrontend(const WebDevToolsMessageData& data) @@ -323,70 +370,32 @@ void WebDevToolsAgentImpl::initDevToolsAgentHost() devtoolsAgentHost.addProtoFunction( "dispatch", WebDevToolsAgentImpl::jsDispatchOnClient); - devtoolsAgentHost.addProtoFunction( - "dispatchToApu", - WebDevToolsAgentImpl::jsDispatchToApu); - devtoolsAgentHost.addProtoFunction( - "evaluateOnSelf", - WebDevToolsAgentImpl::jsEvaluateOnSelf); - devtoolsAgentHost.addProtoFunction( - "runtimeFeatureStateChanged", - WebDevToolsAgentImpl::jsOnRuntimeFeatureStateChanged); devtoolsAgentHost.build(); - - v8::HandleScope scope; - v8::Context::Scope utilityScope(m_utilityContext); - // Call custom code to create inspector backend wrapper in the utility context - // instead of calling V8DOMWrapper::convertToV8Object that would create the - // wrapper in the Page main frame context. - v8::Handle<v8::Object> backendWrapper = createInspectorBackendV8Wrapper(); - if (backendWrapper.IsEmpty()) - return; - m_utilityContext->Global()->Set(v8::String::New("InspectorBackend"), backendWrapper); -} - -v8::Local<v8::Object> WebDevToolsAgentImpl::createInspectorBackendV8Wrapper() -{ - V8ClassIndex::V8WrapperType descriptorType = V8ClassIndex::INSPECTORBACKEND; - v8::Handle<v8::Function> function = V8InspectorBackend::GetTemplate()->GetFunction(); - if (function.IsEmpty()) { - // Return if allocation failed. - return v8::Local<v8::Object>(); - } - v8::Local<v8::Object> instance = SafeAllocation::newInstance(function); - if (instance.IsEmpty()) { - // Avoid setting the wrapper if allocation failed. - return v8::Local<v8::Object>(); - } - InspectorBackend* backend = m_webViewImpl->page()->inspectorController()->inspectorBackend(); - V8DOMWrapper::setDOMWrapper(instance, V8ClassIndex::ToInt(descriptorType), backend); - // Create a weak reference to the v8 wrapper of InspectorBackend to deref - // InspectorBackend when the wrapper is garbage collected. - backend->ref(); - v8::Persistent<v8::Object> weakHandle = v8::Persistent<v8::Object>::New(instance); - weakHandle.MakeWeak(backend, &InspectorBackendWeakReferenceCallback); - return instance; } -void WebDevToolsAgentImpl::resetInspectorFrontendProxy() +void WebDevToolsAgentImpl::createInspectorFrontendProxy() { disposeUtilityContext(); - m_debuggerAgentImpl->createUtilityContext(m_webViewImpl->page()->mainFrame(), &m_utilityContext); + m_utilityContext = v8::Context::New(); compileUtilityScripts(); initDevToolsAgentHost(); + WebCString debuggerScriptJs = m_client->debuggerScriptSource(); + WebCore::ScriptDebugServer::shared().setDebuggerScriptSource( + WebCore::String(debuggerScriptJs.data(), debuggerScriptJs.length())); +} +void WebDevToolsAgentImpl::setInspectorFrontendProxyToInspectorController() +{ v8::HandleScope scope; - v8::Context::Scope contextScope(m_utilityContext); ScriptState* state = ScriptState::forContext( v8::Local<v8::Context>::New(m_utilityContext)); InspectorController* ic = inspectorController(); - ic->setFrontendProxyObject(state, ScriptObject(state, m_utilityContext->Global())); + ic->connectFrontend(ScriptObject(state, m_utilityContext->Global())); } void WebDevToolsAgentImpl::setApuAgentEnabled(bool enabled) { m_apuAgentEnabled = enabled; - SetApuAgentEnabledInUtilityContext(m_utilityContext, enabled); InspectorController* ic = m_webViewImpl->page()->inspectorController(); if (enabled) { m_resourceTrackingWasEnabled = ic->resourceTrackingEnabled(); @@ -415,55 +424,25 @@ v8::Handle<v8::Value> WebDevToolsAgentImpl::jsDispatchOnClient(const v8::Argumen String message = WebCore::toWebCoreStringWithNullCheck(args[0]); if (message.isEmpty() || exceptionCatcher.HasCaught()) return v8::Undefined(); + WebDevToolsAgentImpl* agent = static_cast<WebDevToolsAgentImpl*>(v8::External::Cast(*args.Data())->Value()); - agent->m_toolsAgentDelegateStub->dispatchOnClient(message); - return v8::Undefined(); -} -// static -v8::Handle<v8::Value> WebDevToolsAgentImpl::jsDispatchToApu(const v8::Arguments& args) -{ - v8::TryCatch exceptionCatcher; - String message = WebCore::toWebCoreStringWithNullCheck(args[0]); - if (message.isEmpty() || exceptionCatcher.HasCaught()) + if (!agent->m_apuAgentEnabled) { + agent->m_toolsAgentDelegateStub->dispatchOnClient(message); return v8::Undefined(); - WebDevToolsAgentImpl* agent = static_cast<WebDevToolsAgentImpl*>( - v8::External::Cast(*args.Data())->Value()); - agent->m_apuAgentDelegateStub->dispatchToApu(message); - return v8::Undefined(); -} - -// static -v8::Handle<v8::Value> WebDevToolsAgentImpl::jsEvaluateOnSelf(const v8::Arguments& args) -{ - String code; - { - v8::TryCatch exceptionCatcher; - code = WebCore::toWebCoreStringWithNullCheck(args[0]); - if (code.isEmpty() || exceptionCatcher.HasCaught()) - return v8::Undefined(); } - WebDevToolsAgentImpl* agent = static_cast<WebDevToolsAgentImpl*>(v8::External::Cast(*args.Data())->Value()); - v8::Context::Scope(agent->m_utilityContext); - V8Proxy* proxy = V8Proxy::retrieve(agent->m_webViewImpl->page()->mainFrame()); - v8::Local<v8::Value> result = proxy->runScript(v8::Script::Compile(v8::String::New(code.utf8().data())), true); - return result; -} -// static -v8::Handle<v8::Value> WebDevToolsAgentImpl::jsOnRuntimeFeatureStateChanged(const v8::Arguments& args) -{ - v8::TryCatch exceptionCatcher; - String feature = WebCore::toWebCoreStringWithNullCheck(args[0]); - bool enabled = args[1]->ToBoolean()->Value(); - if (feature.isEmpty() || exceptionCatcher.HasCaught()) + String method = WebCore::toWebCoreStringWithNullCheck(args[1]); + if (method.isEmpty() || exceptionCatcher.HasCaught()) return v8::Undefined(); - WebDevToolsAgentImpl* agent = static_cast<WebDevToolsAgentImpl*>(v8::External::Cast(*args.Data())->Value()); - agent->m_client->runtimeFeatureStateChanged(feature, enabled); + + if (method != "addRecordToTimeline" && method != "updateResource" && method != "addResource") + return v8::Undefined(); + + agent->m_apuAgentDelegateStub->dispatchToApu(message); return v8::Undefined(); } - WebCore::InspectorController* WebDevToolsAgentImpl::inspectorController() { if (Page* page = m_webViewImpl->page()) @@ -486,10 +465,10 @@ void WebDevToolsAgentImpl::identifierForInitialRequest( } } -void WebDevToolsAgentImpl::willSendRequest(unsigned long resourceId, const WebURLRequest& request) +void WebDevToolsAgentImpl::willSendRequest(unsigned long resourceId, WebURLRequest& request) { if (InspectorController* ic = inspectorController()) - ic->willSendRequest(resourceId, request.toResourceRequest(), ResourceResponse()); + ic->willSendRequest(resourceId, request.toMutableResourceRequest(), ResourceResponse()); } void WebDevToolsAgentImpl::didReceiveData(unsigned long resourceId, int length) @@ -517,6 +496,88 @@ void WebDevToolsAgentImpl::didFailLoading(unsigned long resourceId, const WebURL ic->didFailLoading(resourceId, resourceError); } +void WebDevToolsAgentImpl::inspectorDestroyed() +{ + // Our lifetime is bound to the WebViewImpl. +} + +void WebDevToolsAgentImpl::openInspectorFrontend(InspectorController*) +{ +} + +void WebDevToolsAgentImpl::highlight(Node* node) +{ + // InspectorController does the actuall tracking of the highlighted node + // and the drawing of the highlight. Here we just make sure to invalidate + // the rects of the old and new nodes. + hideHighlight(); +} + +void WebDevToolsAgentImpl::hideHighlight() +{ + // FIXME: able to invalidate a smaller rect. + // FIXME: Is it important to just invalidate the rect of the node region + // given that this is not on a critical codepath? In order to do so, we'd + // have to take scrolling into account. + const WebSize& size = m_webViewImpl->size(); + WebRect damagedRect(0, 0, size.width, size.height); + if (m_webViewImpl->client()) + m_webViewImpl->client()->didInvalidateRect(damagedRect); +} + +void WebDevToolsAgentImpl::populateSetting(const String& key, String* value) +{ + WebString string; + m_webViewImpl->inspectorSetting(key, &string); + *value = string; +} + +void WebDevToolsAgentImpl::storeSetting(const String& key, const String& value) +{ + m_webViewImpl->setInspectorSetting(key, value); +} + +bool WebDevToolsAgentImpl::sendMessageToFrontend(const WebCore::String& message) +{ + WebDevToolsAgentImpl* devToolsAgent = static_cast<WebDevToolsAgentImpl*>(m_webViewImpl->devToolsAgent()); + if (!devToolsAgent) + return false; + + if (devToolsAgent->m_apuAgentEnabled && devToolsAgent->m_apuAgentDelegateStub) { + devToolsAgent->m_apuAgentDelegateStub->dispatchToApu(message); + return true; + } + + WebVector<WebString> arguments(size_t(1)); + arguments[0] = message; + WebDevToolsMessageData data; + data.className = "ToolsAgentDelegate"; + data.methodName = "dispatchOnClient"; + data.arguments.swap(arguments); + devToolsAgent->sendRpcMessage(data); + return true; +} + +void WebDevToolsAgentImpl::resourceTrackingWasEnabled() +{ + m_client->runtimeFeatureStateChanged(kResourceTrackingFeatureName, true); +} + +void WebDevToolsAgentImpl::resourceTrackingWasDisabled() +{ + m_client->runtimeFeatureStateChanged(kResourceTrackingFeatureName, false); +} + +void WebDevToolsAgentImpl::timelineProfilerWasStarted() +{ + m_client->runtimeFeatureStateChanged(kTimelineFeatureName, true); +} + +void WebDevToolsAgentImpl::timelineProfilerWasStopped() +{ + m_client->runtimeFeatureStateChanged(kTimelineFeatureName, false); +} + void WebDevToolsAgentImpl::evaluateInWebInspector(long callId, const WebString& script) { InspectorController* ic = inspectorController(); @@ -532,11 +593,6 @@ void WebDevToolsAgentImpl::setTimelineProfilingEnabled(bool enabled) ic->stopTimelineProfiler(); } -WebDevToolsAgent* WebDevToolsAgent::create(WebView* webview, WebDevToolsAgentClient* client) -{ - return new WebDevToolsAgentImpl(static_cast<WebViewImpl*>(webview), client); -} - void WebDevToolsAgent::executeDebuggerCommand(const WebString& command, int callerId) { DebuggerAgentManager::executeDebuggerCommand(command, callerId); @@ -552,10 +608,10 @@ void WebDevToolsAgent::setMessageLoopDispatchHandler(MessageLoopDispatchHandler DebuggerAgentManager::setMessageLoopDispatchHandler(handler); } -bool WebDevToolsAgent::dispatchMessageFromFrontendOnIOThread(const WebDevToolsMessageData& data) +bool WebDevToolsAgent::dispatchMessageFromFrontendOnIOThread(WebDevToolsMessageTransport* transport, const WebDevToolsMessageData& data) { - IORPCDelegate transport; - ProfilerAgentDelegateStub stub(&transport); + IORPCDelegate delegate(transport); + ProfilerAgentDelegateStub stub(&delegate); ProfilerAgentImpl agent(&stub); return ProfilerAgentDispatch::dispatch(&agent, data); } |
