// Copyright (c) 2009 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "config.h" #include #include "Document.h" #include "DOMWindow.h" #include "Frame.h" #include "InspectorController.h" #include "Node.h" #include "Page.h" #include "PlatformString.h" #include "SecurityOrigin.h" #include #include #undef LOG #include "V8Binding.h" #include "v8_custom.h" #include "v8_proxy.h" #include "v8_utility.h" #include "base/string_util.h" #include "base/values.h" #include "webkit/api/public/WebScriptSource.h" #include "webkit/glue/devtools/debugger_agent.h" #include "webkit/glue/devtools/devtools_rpc_js.h" #include "webkit/glue/devtools/dom_agent.h" #include "webkit/glue/devtools/net_agent.h" #include "webkit/glue/devtools/tools_agent.h" #include "webkit/glue/glue_util.h" #include "webkit/glue/webdevtoolsclient_delegate.h" #include "webkit/glue/webdevtoolsclient_impl.h" #include "webkit/glue/webframe.h" #include "webkit/glue/webview_impl.h" using namespace WebCore; using WebKit::WebScriptSource; using WebKit::WebString; DEFINE_RPC_JS_BOUND_OBJ(DebuggerAgent, DEBUGGER_AGENT_STRUCT, DebuggerAgentDelegate, DEBUGGER_AGENT_DELEGATE_STRUCT) DEFINE_RPC_JS_BOUND_OBJ(DomAgent, DOM_AGENT_STRUCT, DomAgentDelegate, DOM_AGENT_DELEGATE_STRUCT) DEFINE_RPC_JS_BOUND_OBJ(NetAgent, NET_AGENT_STRUCT, NetAgentDelegate, NET_AGENT_DELEGATE_STRUCT) DEFINE_RPC_JS_BOUND_OBJ(ToolsAgent, TOOLS_AGENT_STRUCT, ToolsAgentDelegate, TOOLS_AGENT_DELEGATE_STRUCT) namespace { class RemoteDebuggerCommandExecutor : public CppBoundClass { public: RemoteDebuggerCommandExecutor( WebDevToolsClientDelegate* delegate, WebFrame* frame, const std::wstring& classname) : delegate_(delegate) { BindToJavascript(frame, classname); BindMethod("DebuggerCommand", &RemoteDebuggerCommandExecutor::DebuggerCommand); } virtual ~RemoteDebuggerCommandExecutor() {} // The DebuggerCommand() function provided to Javascript. void DebuggerCommand(const CppArgumentList& args, CppVariant* result) { std::string command = args[0].ToString(); result->SetNull(); delegate_->SendDebuggerCommandToAgent(command); } private: WebDevToolsClientDelegate* delegate_; DISALLOW_COPY_AND_ASSIGN(RemoteDebuggerCommandExecutor); }; } // namespace // static WebDevToolsClient* WebDevToolsClient::Create( WebView* view, WebDevToolsClientDelegate* delegate) { return new WebDevToolsClientImpl(static_cast(view), delegate); } WebDevToolsClientImpl::WebDevToolsClientImpl( WebViewImpl* web_view_impl, WebDevToolsClientDelegate* delegate) : web_view_impl_(web_view_impl), delegate_(delegate), loaded_(false) { WebFrameImpl* frame = web_view_impl_->main_frame(); // Debugger commands should be sent using special method. debugger_command_executor_obj_.set(new RemoteDebuggerCommandExecutor( delegate, frame, L"RemoteDebuggerCommandExecutor")); debugger_agent_obj_.set(new JsDebuggerAgentBoundObj( this, frame, L"RemoteDebuggerAgent")); dom_agent_obj_.set(new JsDomAgentBoundObj(this, frame, L"RemoteDomAgent")); net_agent_obj_.set(new JsNetAgentBoundObj(this, frame, L"RemoteNetAgent")); tools_agent_obj_.set( new JsToolsAgentBoundObj(this, frame, L"RemoteToolsAgent")); WebDevToolsClientImpl::InitBoundObject(); v8::HandleScope scope; v8::Handle frame_context = V8Proxy::GetContext(frame->frame()); v8::Context::Scope frame_scope(frame_context); v8::Local constructor = host_template_->GetFunction(); v8::Local host_obj = SafeAllocation::NewInstance(constructor); v8::Handle global = frame_context->Global(); global->Set(v8::String::New("DevToolsHost"), host_obj); } WebDevToolsClientImpl::~WebDevToolsClientImpl() { host_template_.Dispose(); v8_this_.Dispose(); } void WebDevToolsClientImpl::InitBoundObject() { v8::HandleScope scope; v8::Local local_template = v8::FunctionTemplate::New(V8Proxy::CheckNewLegal); host_template_ = v8::Persistent::New(local_template); v8_this_ = v8::Persistent::New(v8::External::New(this)); InitProtoFunction("addSourceToFrame", WebDevToolsClientImpl::JsAddSourceToFrame); InitProtoFunction("loaded", WebDevToolsClientImpl::JsLoaded); InitProtoFunction("search", WebCore::V8Custom::v8InspectorControllerSearchCallback); InitProtoFunction("activateWindow", WebDevToolsClientImpl::JsActivateWindow); host_template_->SetClassName(v8::String::New("DevToolsHost")); } void WebDevToolsClientImpl::InitProtoFunction( const char* name, v8::InvocationCallback callback) { v8::Local signature = v8::Signature::New(host_template_); v8::Local proto = host_template_->PrototypeTemplate(); proto->Set( v8::String::New(name), v8::FunctionTemplate::New( callback, v8_this_, signature), static_cast(v8::DontDelete)); } void WebDevToolsClientImpl::DispatchMessageFromAgent( const std::string& raw_msg) { if (!loaded_) { pending_incoming_messages_.append(raw_msg); return; } std::string expr = StringPrintf("devtools.dispatch(%s)", raw_msg.c_str()); web_view_impl_->GetMainFrame()->ExecuteScript( WebScriptSource(WebString::fromUTF8(expr))); } void WebDevToolsClientImpl::SendRpcMessage(const std::string& raw_msg) { delegate_->SendMessageToAgent(raw_msg); } // static v8::Handle WebDevToolsClientImpl::JsAddSourceToFrame( const v8::Arguments& args) { if (args.Length() < 2) { return v8::Undefined(); } v8::TryCatch exception_catcher; String mime_type = WebCore::toWebCoreStringWithNullCheck(args[0]); if (mime_type.isEmpty() || exception_catcher.HasCaught()) { return v8::Undefined(); } String source_string = WebCore::toWebCoreStringWithNullCheck(args[1]); if (source_string.isEmpty() || exception_catcher.HasCaught()) { return v8::Undefined(); } Node* node = V8Proxy::DOMWrapperToNode(args[2]); if (!node || !node->attached()) { return v8::Undefined(); } Page* page = V8Proxy::retrieveFrameForEnteredContext()->page(); InspectorController* inspectorController = page->inspectorController(); return WebCore::v8Boolean(inspectorController-> addSourceToFrame(mime_type, source_string, node)); } // static v8::Handle WebDevToolsClientImpl::JsLoaded( const v8::Arguments& args) { WebDevToolsClientImpl* client = static_cast( v8::External::Cast(*args.Data())->Value()); client->loaded_ = true; // Grant the devtools page the ability to have source view iframes. Page* page = V8Proxy::retrieveFrameForEnteredContext()->page(); SecurityOrigin* origin = page->mainFrame()->domWindow()->securityOrigin(); origin->grantUniversalAccess(); for (Vector::iterator it = client->pending_incoming_messages_.begin(); it != client->pending_incoming_messages_.end(); ++it) { client->DispatchMessageFromAgent(*it); } client->pending_incoming_messages_.clear(); return v8::Undefined(); } // static v8::Handle WebDevToolsClientImpl::JsActivateWindow( const v8::Arguments& args) { WebDevToolsClientImpl* client = static_cast( v8::External::Cast(*args.Data())->Value()); client->delegate_->ActivateWindow(); return v8::Undefined(); }