| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "config.h" | |
| 6 | |
| 7 #include <string> | |
| 8 | |
| 9 #include "Document.h" | |
| 10 #include "DOMWindow.h" | |
| 11 #include "Frame.h" | |
| 12 #include "InspectorBackend.h" | |
| 13 #include "InspectorController.h" | |
| 14 #include "Node.h" | |
| 15 #include "Page.h" | |
| 16 #include "PlatformString.h" | |
| 17 #include "SecurityOrigin.h" | |
| 18 #include "Settings.h" | |
| 19 #include "V8Binding.h" | |
| 20 #include "V8CustomBinding.h" | |
| 21 #include "V8Proxy.h" | |
| 22 #include "V8Utilities.h" | |
| 23 #include <wtf/OwnPtr.h> | |
| 24 #include <wtf/Vector.h> | |
| 25 #undef LOG | |
| 26 | |
| 27 #include "base/string_util.h" | |
| 28 #include "webkit/api/public/WebFrame.h" | |
| 29 #include "webkit/api/public/WebScriptSource.h" | |
| 30 #include "webkit/glue/devtools/bound_object.h" | |
| 31 #include "webkit/glue/devtools/debugger_agent.h" | |
| 32 #include "webkit/glue/devtools/devtools_rpc_js.h" | |
| 33 #include "webkit/glue/devtools/tools_agent.h" | |
| 34 #include "webkit/glue/glue_util.h" | |
| 35 #include "webkit/glue/webdevtoolsclient_delegate.h" | |
| 36 #include "webkit/glue/webdevtoolsclient_impl.h" | |
| 37 #include "webkit/glue/webview_impl.h" | |
| 38 | |
| 39 using namespace WebCore; | |
| 40 using WebKit::WebFrame; | |
| 41 using WebKit::WebScriptSource; | |
| 42 using WebKit::WebString; | |
| 43 using WebKit::WebView; | |
| 44 | |
| 45 static v8::Local<v8::String> ToV8String(const String& s) { | |
| 46 if (s.isNull()) | |
| 47 return v8::Local<v8::String>(); | |
| 48 | |
| 49 return v8::String::New(reinterpret_cast<const uint16_t*>(s.characters()), | |
| 50 s.length()); | |
| 51 } | |
| 52 | |
| 53 DEFINE_RPC_JS_BOUND_OBJ(DebuggerAgent, DEBUGGER_AGENT_STRUCT, | |
| 54 DebuggerAgentDelegate, DEBUGGER_AGENT_DELEGATE_STRUCT) | |
| 55 DEFINE_RPC_JS_BOUND_OBJ(ToolsAgent, TOOLS_AGENT_STRUCT, | |
| 56 ToolsAgentDelegate, TOOLS_AGENT_DELEGATE_STRUCT) | |
| 57 | |
| 58 class ToolsAgentNativeDelegateImpl : public ToolsAgentNativeDelegate { | |
| 59 public: | |
| 60 struct ResourceContentRequestData { | |
| 61 String mime_type; | |
| 62 RefPtr<Node> frame; | |
| 63 }; | |
| 64 | |
| 65 ToolsAgentNativeDelegateImpl(WebFrameImpl* frame) : frame_(frame) {} | |
| 66 virtual ~ToolsAgentNativeDelegateImpl() {} | |
| 67 | |
| 68 // ToolsAgentNativeDelegate implementation. | |
| 69 virtual void DidGetResourceContent(int request_id, const String& content) { | |
| 70 if (!resource_content_requests_.contains(request_id)) { | |
| 71 NOTREACHED(); | |
| 72 return; | |
| 73 } | |
| 74 ResourceContentRequestData request = | |
| 75 resource_content_requests_.take(request_id); | |
| 76 | |
| 77 InspectorController* ic = frame_->frame()->page()->inspectorController(); | |
| 78 if (request.frame && request.frame->attached()) { | |
| 79 ic->inspectorBackend()->addSourceToFrame(request.mime_type, | |
| 80 content, | |
| 81 request.frame.get()); | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 bool WaitingForResponse(int resource_id, Node* frame) { | |
| 86 if (resource_content_requests_.contains(resource_id)) { | |
| 87 DCHECK(resource_content_requests_.get(resource_id).frame.get() == frame) | |
| 88 << "Only one frame is expected to display given resource"; | |
| 89 return true; | |
| 90 } | |
| 91 return false; | |
| 92 } | |
| 93 | |
| 94 void RequestSent(int resource_id, String mime_type, Node* frame) { | |
| 95 ResourceContentRequestData data; | |
| 96 data.mime_type = mime_type; | |
| 97 data.frame = frame; | |
| 98 DCHECK(!resource_content_requests_.contains(resource_id)); | |
| 99 resource_content_requests_.set(resource_id, data); | |
| 100 } | |
| 101 | |
| 102 private: | |
| 103 WebFrameImpl* frame_; | |
| 104 HashMap<int, ResourceContentRequestData> resource_content_requests_; | |
| 105 DISALLOW_COPY_AND_ASSIGN(ToolsAgentNativeDelegateImpl); | |
| 106 }; | |
| 107 | |
| 108 // static | |
| 109 WebDevToolsClient* WebDevToolsClient::Create( | |
| 110 WebView* view, | |
| 111 WebDevToolsClientDelegate* delegate, | |
| 112 const WebString& application_locale) { | |
| 113 return new WebDevToolsClientImpl( | |
| 114 static_cast<WebViewImpl*>(view), | |
| 115 delegate, | |
| 116 webkit_glue::WebStringToString(application_locale)); | |
| 117 } | |
| 118 | |
| 119 WebDevToolsClientImpl::WebDevToolsClientImpl( | |
| 120 WebViewImpl* web_view_impl, | |
| 121 WebDevToolsClientDelegate* delegate, | |
| 122 const String& application_locale) | |
| 123 : web_view_impl_(web_view_impl), | |
| 124 delegate_(delegate), | |
| 125 application_locale_(application_locale), | |
| 126 loaded_(false) { | |
| 127 WebFrameImpl* frame = web_view_impl_->main_frame(); | |
| 128 v8::HandleScope scope; | |
| 129 v8::Handle<v8::Context> frame_context = V8Proxy::context(frame->frame()); | |
| 130 | |
| 131 debugger_agent_obj_.set(new JsDebuggerAgentBoundObj( | |
| 132 this, frame_context, "RemoteDebuggerAgent")); | |
| 133 tools_agent_obj_.set( | |
| 134 new JsToolsAgentBoundObj(this, frame_context, "RemoteToolsAgent")); | |
| 135 | |
| 136 // Debugger commands should be sent using special method. | |
| 137 debugger_command_executor_obj_.set( | |
| 138 new BoundObject(frame_context, this, "RemoteDebuggerCommandExecutor")); | |
| 139 debugger_command_executor_obj_->AddProtoFunction( | |
| 140 "DebuggerCommand", | |
| 141 WebDevToolsClientImpl::JsDebuggerCommand); | |
| 142 debugger_command_executor_obj_->Build(); | |
| 143 | |
| 144 dev_tools_host_.set(new BoundObject(frame_context, this, "DevToolsHost")); | |
| 145 dev_tools_host_->AddProtoFunction( | |
| 146 "reset", | |
| 147 WebDevToolsClientImpl::JsReset); | |
| 148 dev_tools_host_->AddProtoFunction( | |
| 149 "addSourceToFrame", | |
| 150 WebDevToolsClientImpl::JsAddSourceToFrame); | |
| 151 dev_tools_host_->AddProtoFunction( | |
| 152 "addResourceSourceToFrame", | |
| 153 WebDevToolsClientImpl::JsAddResourceSourceToFrame); | |
| 154 dev_tools_host_->AddProtoFunction( | |
| 155 "loaded", | |
| 156 WebDevToolsClientImpl::JsLoaded); | |
| 157 dev_tools_host_->AddProtoFunction( | |
| 158 "search", | |
| 159 WebCore::V8Custom::v8InspectorBackendSearchCallback); | |
| 160 dev_tools_host_->AddProtoFunction( | |
| 161 "getPlatform", | |
| 162 WebDevToolsClientImpl::JsGetPlatform); | |
| 163 dev_tools_host_->AddProtoFunction( | |
| 164 "activateWindow", | |
| 165 WebDevToolsClientImpl::JsActivateWindow); | |
| 166 dev_tools_host_->AddProtoFunction( | |
| 167 "closeWindow", | |
| 168 WebDevToolsClientImpl::JsCloseWindow); | |
| 169 dev_tools_host_->AddProtoFunction( | |
| 170 "dockWindow", | |
| 171 WebDevToolsClientImpl::JsDockWindow); | |
| 172 dev_tools_host_->AddProtoFunction( | |
| 173 "undockWindow", | |
| 174 WebDevToolsClientImpl::JsUndockWindow); | |
| 175 dev_tools_host_->AddProtoFunction( | |
| 176 "toggleInspectElementMode", | |
| 177 WebDevToolsClientImpl::JsToggleInspectElementMode); | |
| 178 dev_tools_host_->AddProtoFunction( | |
| 179 "getApplicationLocale", | |
| 180 WebDevToolsClientImpl::JsGetApplicationLocale); | |
| 181 dev_tools_host_->AddProtoFunction( | |
| 182 "hiddenPanels", | |
| 183 WebDevToolsClientImpl::JsHiddenPanels); | |
| 184 dev_tools_host_->Build(); | |
| 185 } | |
| 186 | |
| 187 WebDevToolsClientImpl::~WebDevToolsClientImpl() { | |
| 188 } | |
| 189 | |
| 190 void WebDevToolsClientImpl::DispatchMessageFromAgent( | |
| 191 const WebString& class_name, | |
| 192 const WebString& method_name, | |
| 193 const WebString& param1, | |
| 194 const WebString& param2, | |
| 195 const WebString& param3) { | |
| 196 if (ToolsAgentNativeDelegateDispatch::Dispatch( | |
| 197 tools_agent_native_delegate_impl_.get(), | |
| 198 webkit_glue::WebStringToString(class_name), | |
| 199 webkit_glue::WebStringToString(method_name), | |
| 200 webkit_glue::WebStringToString(param1), | |
| 201 webkit_glue::WebStringToString(param2), | |
| 202 webkit_glue::WebStringToString(param3))) { | |
| 203 return; | |
| 204 } | |
| 205 | |
| 206 Vector<String> v; | |
| 207 v.append(webkit_glue::WebStringToString(class_name)); | |
| 208 v.append(webkit_glue::WebStringToString(method_name)); | |
| 209 v.append(webkit_glue::WebStringToString(param1)); | |
| 210 v.append(webkit_glue::WebStringToString(param2)); | |
| 211 v.append(webkit_glue::WebStringToString(param3)); | |
| 212 if (!loaded_) { | |
| 213 pending_incoming_messages_.append(v); | |
| 214 return; | |
| 215 } | |
| 216 ExecuteScript(v); | |
| 217 } | |
| 218 | |
| 219 void WebDevToolsClientImpl::AddResourceSourceToFrame(int resource_id, | |
| 220 String mime_type, | |
| 221 Node* frame) { | |
| 222 if (tools_agent_native_delegate_impl_->WaitingForResponse(resource_id, | |
| 223 frame)) { | |
| 224 return; | |
| 225 } | |
| 226 tools_agent_obj_->GetResourceContent(resource_id, resource_id); | |
| 227 tools_agent_native_delegate_impl_->RequestSent(resource_id, mime_type, frame); | |
| 228 } | |
| 229 | |
| 230 void WebDevToolsClientImpl::ExecuteScript(const Vector<String>& v) { | |
| 231 WebFrameImpl* frame = web_view_impl_->main_frame(); | |
| 232 v8::HandleScope scope; | |
| 233 v8::Handle<v8::Context> frame_context = V8Proxy::context(frame->frame()); | |
| 234 v8::Context::Scope context_scope(frame_context); | |
| 235 v8::Handle<v8::Value> dispatch_function = | |
| 236 frame_context->Global()->Get(v8::String::New("devtools$$dispatch")); | |
| 237 ASSERT(dispatch_function->IsFunction()); | |
| 238 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(dispatch_fu
nction); | |
| 239 v8::Handle<v8::Value> args[] = { | |
| 240 ToV8String(v.at(0)), | |
| 241 ToV8String(v.at(1)), | |
| 242 ToV8String(v.at(2)), | |
| 243 ToV8String(v.at(3)), | |
| 244 ToV8String(v.at(4)), | |
| 245 }; | |
| 246 function->Call(frame_context->Global(), 5, args); | |
| 247 } | |
| 248 | |
| 249 void WebDevToolsClientImpl::SendRpcMessage(const String& class_name, | |
| 250 const String& method_name, | |
| 251 const String& param1, | |
| 252 const String& param2, | |
| 253 const String& param3) { | |
| 254 delegate_->SendMessageToAgent( | |
| 255 webkit_glue::StringToWebString(class_name), | |
| 256 webkit_glue::StringToWebString(method_name), | |
| 257 webkit_glue::StringToWebString(param1), | |
| 258 webkit_glue::StringToWebString(param2), | |
| 259 webkit_glue::StringToWebString(param3)); | |
| 260 } | |
| 261 | |
| 262 // static | |
| 263 v8::Handle<v8::Value> WebDevToolsClientImpl::JsReset( | |
| 264 const v8::Arguments& args) { | |
| 265 WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>( | |
| 266 v8::External::Cast(*args.Data())->Value()); | |
| 267 WebFrameImpl* frame = client->web_view_impl_->main_frame(); | |
| 268 client->tools_agent_native_delegate_impl_.set( | |
| 269 new ToolsAgentNativeDelegateImpl(frame)); | |
| 270 return v8::Undefined(); | |
| 271 } | |
| 272 | |
| 273 // static | |
| 274 v8::Handle<v8::Value> WebDevToolsClientImpl::JsAddSourceToFrame( | |
| 275 const v8::Arguments& args) { | |
| 276 if (args.Length() < 2) { | |
| 277 return v8::Undefined(); | |
| 278 } | |
| 279 | |
| 280 v8::TryCatch exception_catcher; | |
| 281 | |
| 282 String mime_type = WebCore::toWebCoreStringWithNullCheck(args[0]); | |
| 283 if (mime_type.isEmpty() || exception_catcher.HasCaught()) { | |
| 284 return v8::Undefined(); | |
| 285 } | |
| 286 String source_string = WebCore::toWebCoreStringWithNullCheck(args[1]); | |
| 287 if (source_string.isEmpty() || exception_catcher.HasCaught()) { | |
| 288 return v8::Undefined(); | |
| 289 } | |
| 290 v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(args[2]); | |
| 291 Node* node = V8DOMWrapper::convertDOMWrapperToNode<Node>(wrapper); | |
| 292 if (!node || !node->attached()) { | |
| 293 return v8::Undefined(); | |
| 294 } | |
| 295 | |
| 296 Page* page = V8Proxy::retrieveFrameForEnteredContext()->page(); | |
| 297 InspectorController* inspectorController = page->inspectorController(); | |
| 298 return WebCore::v8Boolean(inspectorController->inspectorBackend()-> | |
| 299 addSourceToFrame(mime_type, source_string, node)); | |
| 300 } | |
| 301 | |
| 302 // static | |
| 303 v8::Handle<v8::Value> WebDevToolsClientImpl::JsAddResourceSourceToFrame( | |
| 304 const v8::Arguments& args) { | |
| 305 int resource_id = static_cast<int>(args[0]->NumberValue()); | |
| 306 String mime_type = WebCore::toWebCoreStringWithNullCheck(args[1]); | |
| 307 if (mime_type.isEmpty()) { | |
| 308 return v8::Undefined(); | |
| 309 } | |
| 310 v8::Handle<v8::Object> wrapper = v8::Handle<v8::Object>::Cast(args[2]); | |
| 311 Node* node = V8DOMWrapper::convertDOMWrapperToNode<Node>(wrapper); | |
| 312 WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>( | |
| 313 v8::External::Cast(*args.Data())->Value()); | |
| 314 client->AddResourceSourceToFrame(resource_id, mime_type, node); | |
| 315 return v8::Undefined(); | |
| 316 } | |
| 317 | |
| 318 // static | |
| 319 v8::Handle<v8::Value> WebDevToolsClientImpl::JsLoaded( | |
| 320 const v8::Arguments& args) { | |
| 321 WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>( | |
| 322 v8::External::Cast(*args.Data())->Value()); | |
| 323 client->loaded_ = true; | |
| 324 | |
| 325 // Grant the devtools page the ability to have source view iframes. | |
| 326 Page* page = V8Proxy::retrieveFrameForEnteredContext()->page(); | |
| 327 SecurityOrigin* origin = page->mainFrame()->domWindow()->securityOrigin(); | |
| 328 origin->grantUniversalAccess(); | |
| 329 | |
| 330 for (Vector<Vector<String> >::iterator it = | |
| 331 client->pending_incoming_messages_.begin(); | |
| 332 it != client->pending_incoming_messages_.end(); | |
| 333 ++it) { | |
| 334 client->ExecuteScript(*it); | |
| 335 } | |
| 336 client->pending_incoming_messages_.clear(); | |
| 337 return v8::Undefined(); | |
| 338 } | |
| 339 | |
| 340 // static | |
| 341 v8::Handle<v8::Value> WebDevToolsClientImpl::JsGetPlatform( | |
| 342 const v8::Arguments& args) { | |
| 343 #if defined OS_MACOSX | |
| 344 return v8String("mac-leopard"); | |
| 345 #elif defined OS_LINUX | |
| 346 return v8String("linux"); | |
| 347 #else | |
| 348 return v8String("windows"); | |
| 349 #endif | |
| 350 } | |
| 351 | |
| 352 // static | |
| 353 v8::Handle<v8::Value> WebDevToolsClientImpl::JsActivateWindow( | |
| 354 const v8::Arguments& args) { | |
| 355 WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>( | |
| 356 v8::External::Cast(*args.Data())->Value()); | |
| 357 client->delegate_->ActivateWindow(); | |
| 358 return v8::Undefined(); | |
| 359 } | |
| 360 | |
| 361 // static | |
| 362 v8::Handle<v8::Value> WebDevToolsClientImpl::JsCloseWindow( | |
| 363 const v8::Arguments& args) { | |
| 364 WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>( | |
| 365 v8::External::Cast(*args.Data())->Value()); | |
| 366 client->delegate_->CloseWindow(); | |
| 367 return v8::Undefined(); | |
| 368 } | |
| 369 | |
| 370 // static | |
| 371 v8::Handle<v8::Value> WebDevToolsClientImpl::JsDockWindow( | |
| 372 const v8::Arguments& args) { | |
| 373 WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>( | |
| 374 v8::External::Cast(*args.Data())->Value()); | |
| 375 client->delegate_->DockWindow(); | |
| 376 return v8::Undefined(); | |
| 377 } | |
| 378 | |
| 379 // static | |
| 380 v8::Handle<v8::Value> WebDevToolsClientImpl::JsUndockWindow( | |
| 381 const v8::Arguments& args) { | |
| 382 WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>( | |
| 383 v8::External::Cast(*args.Data())->Value()); | |
| 384 client->delegate_->UndockWindow(); | |
| 385 return v8::Undefined(); | |
| 386 } | |
| 387 | |
| 388 // static | |
| 389 v8::Handle<v8::Value> WebDevToolsClientImpl::JsToggleInspectElementMode( | |
| 390 const v8::Arguments& args) { | |
| 391 WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>( | |
| 392 v8::External::Cast(*args.Data())->Value()); | |
| 393 int enabled = static_cast<int>(args[0]->BooleanValue()); | |
| 394 client->delegate_->ToggleInspectElementMode(enabled); | |
| 395 return v8::Undefined(); | |
| 396 } | |
| 397 | |
| 398 // static | |
| 399 v8::Handle<v8::Value> WebDevToolsClientImpl::JsGetApplicationLocale( | |
| 400 const v8::Arguments& args) { | |
| 401 WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>( | |
| 402 v8::External::Cast(*args.Data())->Value()); | |
| 403 return v8String(client->application_locale_); | |
| 404 } | |
| 405 | |
| 406 // static | |
| 407 v8::Handle<v8::Value> WebDevToolsClientImpl::JsHiddenPanels( | |
| 408 const v8::Arguments& args) { | |
| 409 Page* page = V8Proxy::retrieveFrameForEnteredContext()->page(); | |
| 410 return v8String(page->settings()->databasesEnabled() ? "" : "databases"); | |
| 411 } | |
| 412 | |
| 413 // static | |
| 414 v8::Handle<v8::Value> WebDevToolsClientImpl::JsDebuggerCommand( | |
| 415 const v8::Arguments& args) { | |
| 416 WebDevToolsClientImpl* client = static_cast<WebDevToolsClientImpl*>( | |
| 417 v8::External::Cast(*args.Data())->Value()); | |
| 418 String command = WebCore::toWebCoreStringWithNullCheck(args[0]); | |
| 419 WebString std_command = webkit_glue::StringToWebString(command); | |
| 420 client->delegate_->SendDebuggerCommandToAgent(std_command); | |
| 421 return v8::Undefined(); | |
| 422 } | |
| OLD | NEW |