// 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 #include #include "Document.h" #include "Page.h" #include "V8Binding.h" #include "V8DOMWindow.h" #include "V8Index.h" #include "V8Proxy.h" #undef LOG #include "base/string_piece.h" #include "grit/webkit_resources.h" #include "webkit/glue/devtools/debugger_agent_impl.h" #include "webkit/glue/devtools/debugger_agent_manager.h" #include "webkit/glue/glue_util.h" #include "webkit/glue/webdevtoolsagent_impl.h" #include "webkit/glue/webkit_glue.h" #include "webkit/glue/webview_impl.h" using WebCore::DOMWindow; using WebCore::Document; using WebCore::Frame; using WebCore::Page; using WebCore::String; using WebCore::V8ClassIndex; using WebCore::V8Custom; using WebCore::V8DOMWindow; using WebCore::V8DOMWrapper;; using WebCore::V8Proxy; DebuggerAgentImpl::DebuggerAgentImpl( WebViewImpl* web_view_impl, DebuggerAgentDelegate* delegate, WebDevToolsAgentImpl* webdevtools_agent) : web_view_impl_(web_view_impl), delegate_(delegate), webdevtools_agent_(webdevtools_agent), profiler_log_position_(0) { DebuggerAgentManager::DebugAttach(this); } DebuggerAgentImpl::~DebuggerAgentImpl() { DebuggerAgentManager::DebugDetach(this); } void DebuggerAgentImpl::DebugBreak() { DebuggerAgentManager::DebugBreak(this); } void DebuggerAgentImpl::GetContextId() { delegate_->SetContextId(webdevtools_agent_->host_id()); } void DebuggerAgentImpl::StartProfiling(int flags) { v8::HandleScope scope; WebCore::Frame* frame = GetPage()->mainFrame(); DCHECK(V8Proxy::retrieve(GetPage()->mainFrame())->isContextInitialized()); v8::Context::Scope context_scope(V8Proxy::context(frame)); v8::V8::ResumeProfilerEx(flags); } void DebuggerAgentImpl::StopProfiling(int flags) { v8::V8::PauseProfilerEx(flags); } void DebuggerAgentImpl::GetActiveProfilerModules() { delegate_->DidGetActiveProfilerModules(v8::V8::GetActiveProfilerModules()); } void DebuggerAgentImpl::GetNextLogLines() { static char buffer[65536]; int read_size = v8::V8::GetLogLines( profiler_log_position_, buffer, sizeof(buffer) - 1); profiler_log_position_ += read_size; buffer[read_size] = '\0'; delegate_->DidGetNextLogLines(buffer); } void DebuggerAgentImpl::DebuggerOutput(const std::string& command) { delegate_->DebuggerOutput(command); webdevtools_agent_->ForceRepaint(); } // static void DebuggerAgentImpl::ResetUtilityContext( Document* document, v8::Persistent* context) { if (!context->IsEmpty()) { context->Dispose(); context->Clear(); } v8::HandleScope scope; // TODO(pfeldman): Validate against Soeren. // Set up the DOM window as the prototype of the new global object. v8::Handle window_context = V8Proxy::context(document->frame()); v8::Handle window_global = window_context->Global(); v8::Handle window_wrapper = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, window_global); ASSERT(V8DOMWrapper::convertDOMWrapperToNative(window_wrapper) == document->frame()->domWindow()); // Create a new environment using an empty template for the shadow // object. Reuse the global object if one has been created earlier. v8::Handle global_template = V8DOMWindow::GetShadowObjectTemplate(); // Install a security handler with V8. global_template->SetAccessCheckCallbacks( V8Custom::v8DOMWindowNamedSecurityCheck, V8Custom::v8DOMWindowIndexedSecurityCheck, v8::Integer::New(V8ClassIndex::DOMWINDOW)); *context = v8::Context::New( NULL /* no extensions */, global_template, v8::Handle()); v8::Context::Scope context_scope(*context); v8::Handle global = (*context)->Global(); v8::Handle implicit_proto_string = v8::String::New("__proto__"); global->Set(implicit_proto_string, window_wrapper); // Give the code running in the new context a way to get access to the // original context. global->Set(v8::String::New("contentWindow"), window_global); // Inject javascript into the context. StringPiece basejs = webkit_glue::GetDataResource(IDR_DEVTOOLS_BASE_JS); v8::Script::Compile(v8::String::New(basejs.as_string().c_str()))->Run(); StringPiece injectjs_webkit = webkit_glue::GetDataResource(IDR_DEVTOOLS_INJECT_WEBKIT_JS); v8::Script::Compile( v8::String::New(injectjs_webkit.as_string().c_str()))->Run(); StringPiece injectjs = webkit_glue::GetDataResource(IDR_DEVTOOLS_INJECT_JS); v8::Script::Compile(v8::String::New(injectjs.as_string().c_str()))->Run(); StringPiece inject_dispatchjs = webkit_glue::GetDataResource( IDR_DEVTOOLS_INJECT_DISPATCH_JS); v8::Script::Compile(v8::String::New( inject_dispatchjs.as_string().c_str()))->Run(); } String DebuggerAgentImpl::ExecuteUtilityFunction( v8::Handle context, const String &function_name, const String& json_args, String* exception) { v8::HandleScope scope; ASSERT(!context.IsEmpty()); if (context.IsEmpty()) { *exception = "No window context."; return ""; } v8::Context::Scope context_scope(context); DebuggerAgentManager::UtilityContextScope utility_scope; v8::Handle function = v8::Local::Cast( context->Global()->Get(v8::String::New("devtools$$dispatch"))); v8::Handle function_name_wrapper = v8::Handle( v8::String::New(function_name.utf8().data())); v8::Handle json_args_wrapper = v8::Handle( v8::String::New(json_args.utf8().data())); v8::Handle args[] = { function_name_wrapper, json_args_wrapper }; v8::TryCatch try_catch; v8::Handle res_obj = function->Call(context->Global(), 2, args); if (try_catch.HasCaught()) { *exception = WebCore::toWebCoreString(try_catch.Message()->Get()); return ""; } else { return WebCore::toWebCoreStringWithNullCheck(res_obj); } } String DebuggerAgentImpl::EvaluateJavaScript( v8::Handle utility_context, const String& source, String* exception) { v8::HandleScope scope; ASSERT(!utility_context.IsEmpty()); if (utility_context.IsEmpty()) { *exception = "No window utility context."; return ""; } v8::Handle res_obj; { // Do evaluate. DebuggerAgentManager::UtilityContextScope utility_scope; v8::Handle v8Context = V8Proxy::context(GetPage()->mainFrame()); if (v8Context.IsEmpty()) { *exception = "No window context."; return ""; } V8Proxy* proxy = V8Proxy::retrieve(GetPage()->mainFrame()); v8::Context::Scope context_scope(v8Context); v8::TryCatch try_catch; v8::Handle script = proxy->compileScript( v8ExternalString(source), String(), // url 0); // source start res_obj = proxy->runScript(script, true); if (try_catch.HasCaught()) { v8::Handle msg = try_catch.Message()->Get(); if (!msg.IsEmpty()) { *exception = WebCore::toWebCoreString(msg); } else { *exception = "Failed to evaluate."; } return ""; } DCHECK(!res_obj.IsEmpty()); } { // Wrap the result. v8::Context::Scope context_scope(utility_context); v8::Handle devtools = v8::Local::Cast( utility_context->Global()->Get(v8::String::New("devtools$$obj"))); v8::Handle function = v8::Local::Cast( devtools->Get(v8::String::New("serializeConsoleObject"))); v8::Handle args[] = { res_obj }; res_obj = function->Call(devtools, 1, args); return WebCore::toWebCoreStringWithNullCheck(res_obj); } } WebCore::Page* DebuggerAgentImpl::GetPage() { return web_view_impl_->page(); }