1 // Copyright 2013 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 "content/shell/browser/shell_devtools_frontend.h" 6 7 #include "base/command_line.h" 8 #include "base/json/json_reader.h" 9 #include "base/path_service.h" 10 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/stringprintf.h" 12 #include "base/strings/utf_string_conversions.h" 13 #include "content/public/browser/devtools_http_handler.h" 14 #include "content/public/browser/render_frame_host.h" 15 #include "content/public/browser/render_view_host.h" 16 #include "content/public/browser/web_contents.h" 17 #include "content/public/common/content_client.h" 18 #include "content/shell/browser/shell.h" 19 #include "content/shell/browser/shell_browser_context.h" 20 #include "content/shell/browser/shell_browser_main_parts.h" 21 #include "content/shell/browser/shell_content_browser_client.h" 22 #include "content/shell/browser/shell_devtools_delegate.h" 23 #include "content/shell/browser/webkit_test_controller.h" 24 #include "content/shell/common/shell_switches.h" 25 #include "net/base/filename_util.h" 26 27 namespace content { 28 29 // DevTools frontend path for inspector LayoutTests. 30 GURL GetDevToolsPathAsURL(const std::string& settings, 31 const std::string& frontend_url) { 32 if (!frontend_url.empty()) 33 return GURL(frontend_url); 34 base::FilePath dir_exe; 35 if (!PathService::Get(base::DIR_EXE, &dir_exe)) { 36 NOTREACHED(); 37 return GURL(); 38 } 39 #if defined(OS_MACOSX) 40 // On Mac, the executable is in 41 // out/Release/Content Shell.app/Contents/MacOS/Content Shell. 42 // We need to go up 3 directories to get to out/Release. 43 dir_exe = dir_exe.AppendASCII("../../.."); 44 #endif 45 base::FilePath dev_tools_path = dir_exe.AppendASCII( 46 "resources/inspector/devtools.html"); 47 48 GURL result = net::FilePathToFileURL(dev_tools_path); 49 if (!settings.empty()) 50 result = GURL(base::StringPrintf("%s?settings=%s&experiments=true", 51 result.spec().c_str(), 52 settings.c_str())); 53 return result; 54 } 55 56 // static 57 ShellDevToolsFrontend* ShellDevToolsFrontend::Show( 58 WebContents* inspected_contents) { 59 return ShellDevToolsFrontend::Show(inspected_contents, "", ""); 60 } 61 62 // static 63 ShellDevToolsFrontend* ShellDevToolsFrontend::Show( 64 WebContents* inspected_contents, 65 const std::string& settings, 66 const std::string& frontend_url) { 67 scoped_refptr<DevToolsAgentHost> agent( 68 DevToolsAgentHost::GetOrCreateFor(inspected_contents)); 69 Shell* shell = Shell::CreateNewWindow(inspected_contents->GetBrowserContext(), 70 GURL(), 71 NULL, 72 MSG_ROUTING_NONE, 73 gfx::Size()); 74 ShellDevToolsFrontend* devtools_frontend = new ShellDevToolsFrontend( 75 shell, 76 agent.get()); 77 78 ShellDevToolsDelegate* delegate = ShellContentBrowserClient::Get()-> 79 shell_browser_main_parts()->devtools_delegate(); 80 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 81 shell->LoadURL(GetDevToolsPathAsURL(settings, frontend_url)); 82 else 83 shell->LoadURL(delegate->devtools_http_handler()->GetFrontendURL()); 84 85 return devtools_frontend; 86 } 87 88 void ShellDevToolsFrontend::Activate() { 89 frontend_shell_->ActivateContents(web_contents()); 90 } 91 92 void ShellDevToolsFrontend::Focus() { 93 web_contents()->Focus(); 94 } 95 96 void ShellDevToolsFrontend::InspectElementAt(int x, int y) { 97 agent_host_->InspectElement(x, y); 98 } 99 100 void ShellDevToolsFrontend::Close() { 101 frontend_shell_->Close(); 102 } 103 104 ShellDevToolsFrontend::ShellDevToolsFrontend(Shell* frontend_shell, 105 DevToolsAgentHost* agent_host) 106 : WebContentsObserver(frontend_shell->web_contents()), 107 frontend_shell_(frontend_shell), 108 agent_host_(agent_host) { 109 } 110 111 ShellDevToolsFrontend::~ShellDevToolsFrontend() { 112 } 113 114 void ShellDevToolsFrontend::RenderViewCreated( 115 RenderViewHost* render_view_host) { 116 if (!frontend_host_) { 117 frontend_host_.reset(DevToolsFrontendHost::Create(render_view_host, this)); 118 agent_host_->AttachClient(this); 119 } 120 } 121 122 void ShellDevToolsFrontend::DocumentOnLoadCompletedInMainFrame() { 123 web_contents()->GetMainFrame()->ExecuteJavaScript( 124 base::ASCIIToUTF16("InspectorFrontendAPI.setUseSoftMenu(true);")); 125 } 126 127 void ShellDevToolsFrontend::WebContentsDestroyed() { 128 agent_host_->DetachClient(); 129 delete this; 130 } 131 132 void ShellDevToolsFrontend::RenderProcessGone(base::TerminationStatus status) { 133 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) 134 WebKitTestController::Get()->DevToolsProcessCrashed(); 135 } 136 137 void ShellDevToolsFrontend::HandleMessageFromDevToolsFrontend( 138 const std::string& message) { 139 std::string method; 140 std::string browser_message; 141 int id = 0; 142 143 base::ListValue* params = NULL; 144 base::DictionaryValue* dict = NULL; 145 scoped_ptr<base::Value> parsed_message(base::JSONReader::Read(message)); 146 if (!parsed_message || 147 !parsed_message->GetAsDictionary(&dict) || 148 !dict->GetString("method", &method) || 149 !dict->GetList("params", ¶ms)) { 150 return; 151 } 152 153 if (method != "sendMessageToBrowser" || 154 params->GetSize() != 1 || 155 !params->GetString(0, &browser_message)) { 156 return; 157 } 158 dict->GetInteger("id", &id); 159 160 agent_host_->DispatchProtocolMessage(browser_message); 161 162 if (id) { 163 std::string code = "InspectorFrontendAPI.embedderMessageAck(" + 164 base::IntToString(id) + ",\"\");"; 165 base::string16 javascript = base::UTF8ToUTF16(code); 166 web_contents()->GetMainFrame()->ExecuteJavaScript(javascript); 167 } 168 } 169 170 void ShellDevToolsFrontend::HandleMessageFromDevToolsFrontendToBackend( 171 const std::string& message) { 172 agent_host_->DispatchProtocolMessage(message); 173 } 174 175 void ShellDevToolsFrontend::DispatchProtocolMessage( 176 DevToolsAgentHost* agent_host, const std::string& message) { 177 std::string code = "InspectorFrontendAPI.dispatchMessage(" + message + ");"; 178 base::string16 javascript = base::UTF8ToUTF16(code); 179 web_contents()->GetMainFrame()->ExecuteJavaScript(javascript); 180 } 181 182 void ShellDevToolsFrontend::AgentHostClosed( 183 DevToolsAgentHost* agent_host, bool replaced) { 184 frontend_shell_->Close(); 185 } 186 187 } // namespace content 188