1bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor// Copyright 2013 The Chromium Authors. All rights reserved.
21d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert// Use of this source code is governed by a BSD-style license that can be
3bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor// found in the LICENSE file.
4bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
5bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "content/shell/browser/shell_devtools_frontend.h"
6bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
7bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "base/command_line.h"
8bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "base/json/json_reader.h"
9bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "base/path_service.h"
10bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "base/strings/string_number_conversions.h"
11bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "base/strings/stringprintf.h"
12bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "base/strings/utf_string_conversions.h"
13bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "content/public/browser/devtools_http_handler.h"
14bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "content/public/browser/render_frame_host.h"
15bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "content/public/browser/render_view_host.h"
16bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "content/public/browser/web_contents.h"
17bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "content/public/common/content_client.h"
18bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "content/shell/browser/shell.h"
191d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "content/shell/browser/shell_browser_context.h"
201d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert#include "content/shell/browser/shell_browser_main_parts.h"
21bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "content/shell/browser/shell_content_browser_client.h"
22bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "content/shell/browser/shell_devtools_delegate.h"
23bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "content/shell/browser/webkit_test_controller.h"
24bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "content/shell/common/shell_switches.h"
25bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#include "net/base/filename_util.h"
26bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
27bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnornamespace content {
28bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
29bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor// DevTools frontend path for inspector LayoutTests.
301d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn BringertGURL GetDevToolsPathAsURL(const std::string& settings,
31bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor                          const std::string& frontend_url) {
321d580d0f6ee4f21eb309ba7b509d2c6d671c4044Bjorn Bringert  if (!frontend_url.empty())
33bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    return GURL(frontend_url);
34bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  base::FilePath dir_exe;
35bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  if (!PathService::Get(base::DIR_EXE, &dir_exe)) {
36bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    NOTREACHED();
37bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor    return GURL();
38bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  }
39bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#if defined(OS_MACOSX)
40bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  // On Mac, the executable is in
41bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  // out/Release/Content Shell.app/Contents/MacOS/Content Shell.
42bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  // We need to go up 3 directories to get to out/Release.
43bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  dir_exe = dir_exe.AppendASCII("../../..");
44bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor#endif
45bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  base::FilePath dev_tools_path = dir_exe.AppendASCII(
46bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor      "resources/inspector/devtools.html");
47bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor
48bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  GURL result = net::FilePathToFileURL(dev_tools_path);
49bfe2dd089341dcb4c1fb65a5b6b077ad0ebbf6dcDan Egnor  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
57ShellDevToolsFrontend* ShellDevToolsFrontend::Show(
58    WebContents* inspected_contents) {
59  return ShellDevToolsFrontend::Show(inspected_contents, "", "");
60}
61
62// static
63ShellDevToolsFrontend* 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
88void ShellDevToolsFrontend::Activate() {
89  frontend_shell_->ActivateContents(web_contents());
90}
91
92void ShellDevToolsFrontend::Focus() {
93  web_contents()->Focus();
94}
95
96void ShellDevToolsFrontend::InspectElementAt(int x, int y) {
97  agent_host_->InspectElement(x, y);
98}
99
100void ShellDevToolsFrontend::Close() {
101  frontend_shell_->Close();
102}
103
104ShellDevToolsFrontend::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
111ShellDevToolsFrontend::~ShellDevToolsFrontend() {
112}
113
114void 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
122void ShellDevToolsFrontend::DocumentOnLoadCompletedInMainFrame() {
123  web_contents()->GetMainFrame()->ExecuteJavaScript(
124      base::ASCIIToUTF16("InspectorFrontendAPI.setUseSoftMenu(true);"));
125}
126
127void ShellDevToolsFrontend::WebContentsDestroyed() {
128  agent_host_->DetachClient();
129  delete this;
130}
131
132void ShellDevToolsFrontend::RenderProcessGone(base::TerminationStatus status) {
133  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
134    WebKitTestController::Get()->DevToolsProcessCrashed();
135}
136
137void 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
170void ShellDevToolsFrontend::HandleMessageFromDevToolsFrontendToBackend(
171    const std::string& message) {
172  agent_host_->DispatchProtocolMessage(message);
173}
174
175void 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
182void ShellDevToolsFrontend::AgentHostClosed(
183    DevToolsAgentHost* agent_host, bool replaced) {
184  frontend_shell_->Close();
185}
186
187}  // namespace content
188