Home | History | Annotate | Download | only in browser
      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", &params)) {
    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