diff options
Diffstat (limited to 'content/renderer/devtools')
-rw-r--r-- | content/renderer/devtools/OWNERS | 2 | ||||
-rw-r--r-- | content/renderer/devtools/devtools_agent.cc | 245 | ||||
-rw-r--r-- | content/renderer/devtools/devtools_agent.h | 73 | ||||
-rw-r--r-- | content/renderer/devtools/devtools_agent_filter.cc | 77 | ||||
-rw-r--r-- | content/renderer/devtools/devtools_agent_filter.h | 48 | ||||
-rw-r--r-- | content/renderer/devtools/devtools_client.cc | 97 | ||||
-rw-r--r-- | content/renderer/devtools/devtools_client.h | 63 |
7 files changed, 605 insertions, 0 deletions
diff --git a/content/renderer/devtools/OWNERS b/content/renderer/devtools/OWNERS new file mode 100644 index 0000000..bb6028e --- /dev/null +++ b/content/renderer/devtools/OWNERS @@ -0,0 +1,2 @@ +pfeldman@chromium.org +yurys@chromium.org diff --git a/content/renderer/devtools/devtools_agent.cc b/content/renderer/devtools/devtools_agent.cc new file mode 100644 index 0000000..31269b0 --- /dev/null +++ b/content/renderer/devtools/devtools_agent.cc @@ -0,0 +1,245 @@ +// Copyright (c) 2012 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 "content/renderer/devtools/devtools_agent.h" + +#include <map> + +#include "base/lazy_instance.h" +#include "base/message_loop.h" +#include "base/process.h" +#include "base/string_number_conversions.h" +#include "content/common/devtools_messages.h" +#include "content/common/view_messages.h" +#include "content/renderer/devtools/devtools_agent_filter.h" +#include "content/renderer/devtools/devtools_client.h" +#include "content/renderer/render_view_impl.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebConsoleMessage.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebConsoleMessage.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebDevToolsAgent.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebPoint.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" + +#if defined(USE_TCMALLOC) +#include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" +#endif + +using WebKit::WebConsoleMessage; +using WebKit::WebDevToolsAgent; +using WebKit::WebDevToolsAgentClient; +using WebKit::WebFrame; +using WebKit::WebPoint; +using WebKit::WebString; +using WebKit::WebCString; +using WebKit::WebVector; +using WebKit::WebView; + +namespace content { + +namespace { + +class WebKitClientMessageLoopImpl + : public WebDevToolsAgentClient::WebKitClientMessageLoop { + public: + WebKitClientMessageLoopImpl() : message_loop_(MessageLoop::current()) { } + virtual ~WebKitClientMessageLoopImpl() { + message_loop_ = NULL; + } + virtual void run() { + MessageLoop::ScopedNestableTaskAllower allow(message_loop_); + message_loop_->Run(); + } + virtual void quitNow() { + message_loop_->QuitNow(); + } + private: + MessageLoop* message_loop_; +}; + +typedef std::map<int, DevToolsAgent*> IdToAgentMap; +base::LazyInstance<IdToAgentMap>::Leaky + g_agent_for_routing_id = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +DevToolsAgent::DevToolsAgent(RenderViewImpl* render_view) + : RenderViewObserver(render_view), is_attached_(false) { + g_agent_for_routing_id.Get()[routing_id()] = this; + + render_view->webview()->setDevToolsAgentClient(this); + render_view->webview()->devToolsAgent()->setProcessId( + base::Process::Current().pid()); +} + +DevToolsAgent::~DevToolsAgent() { + g_agent_for_routing_id.Get().erase(routing_id()); +} + +// Called on the Renderer thread. +bool DevToolsAgent::OnMessageReceived(const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(DevToolsAgent, message) + IPC_MESSAGE_HANDLER(DevToolsAgentMsg_Attach, OnAttach) + IPC_MESSAGE_HANDLER(DevToolsAgentMsg_Reattach, OnReattach) + IPC_MESSAGE_HANDLER(DevToolsAgentMsg_Detach, OnDetach) + IPC_MESSAGE_HANDLER(DevToolsAgentMsg_DispatchOnInspectorBackend, + OnDispatchOnInspectorBackend) + IPC_MESSAGE_HANDLER(DevToolsAgentMsg_InspectElement, OnInspectElement) + IPC_MESSAGE_HANDLER(DevToolsAgentMsg_AddMessageToConsole, + OnAddMessageToConsole) + IPC_MESSAGE_HANDLER(DevToolsMsg_SetupDevToolsClient, OnSetupDevToolsClient) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + if (message.type() == ViewMsg_Navigate::ID || + message.type() == ViewMsg_Close::ID) + ContinueProgram(); // Don't want to swallow the message. + + return handled; +} + +void DevToolsAgent::sendMessageToInspectorFrontend( + const WebKit::WebString& message) { + Send(new DevToolsClientMsg_DispatchOnInspectorFrontend(routing_id(), + message.utf8())); +} + +int DevToolsAgent::hostIdentifier() { + return routing_id(); +} + +void DevToolsAgent::saveAgentRuntimeState( + const WebKit::WebString& state) { + Send(new DevToolsHostMsg_SaveAgentRuntimeState(routing_id(), state.utf8())); +} + +WebKit::WebDevToolsAgentClient::WebKitClientMessageLoop* + DevToolsAgent::createClientMessageLoop() { + return new WebKitClientMessageLoopImpl(); +} + +void DevToolsAgent::clearBrowserCache() { + Send(new DevToolsHostMsg_ClearBrowserCache(routing_id())); +} + +void DevToolsAgent::clearBrowserCookies() { + Send(new DevToolsHostMsg_ClearBrowserCookies(routing_id())); +} + +#if defined(USE_TCMALLOC) && !defined(OS_WIN) +static void AllocationVisitor(void* data, const void* ptr) { + typedef WebKit::WebDevToolsAgentClient::AllocatedObjectVisitor Visitor; + Visitor* visitor = reinterpret_cast<Visitor*>(data); + visitor->visitObject(ptr); +} +#endif + +void DevToolsAgent::visitAllocatedObjects(AllocatedObjectVisitor* visitor) { +#if defined(USE_TCMALLOC) && !defined(OS_WIN) + IterateAllocatedObjects(&AllocationVisitor, visitor); +#endif +} + +// static +DevToolsAgent* DevToolsAgent::FromHostId(int host_id) { + IdToAgentMap::iterator it = g_agent_for_routing_id.Get().find(host_id); + if (it != g_agent_for_routing_id.Get().end()) { + return it->second; + } + return NULL; +} + +void DevToolsAgent::OnAttach() { + WebDevToolsAgent* web_agent = GetWebAgent(); + if (web_agent) { + web_agent->attach(); + is_attached_ = true; + } +} + +void DevToolsAgent::OnReattach(const std::string& agent_state) { + WebDevToolsAgent* web_agent = GetWebAgent(); + if (web_agent) { + web_agent->reattach(WebString::fromUTF8(agent_state)); + is_attached_ = true; + } +} + +void DevToolsAgent::OnDetach() { + WebDevToolsAgent* web_agent = GetWebAgent(); + if (web_agent) { + web_agent->detach(); + is_attached_ = false; + } +} + +void DevToolsAgent::OnDispatchOnInspectorBackend(const std::string& message) { + WebDevToolsAgent* web_agent = GetWebAgent(); + if (web_agent) + web_agent->dispatchOnInspectorBackend(WebString::fromUTF8(message)); +} + +void DevToolsAgent::OnInspectElement(int x, int y) { + WebDevToolsAgent* web_agent = GetWebAgent(); + if (web_agent) { + web_agent->attach(); + web_agent->inspectElementAt(WebPoint(x, y)); + } +} + +void DevToolsAgent::OnAddMessageToConsole(ConsoleMessageLevel level, + const std::string& message) { + WebView* web_view = render_view()->GetWebView(); + if (!web_view) + return; + + WebFrame* main_frame = web_view-> mainFrame(); + if (!main_frame) + return; + + WebConsoleMessage::Level target_level = WebConsoleMessage::LevelLog; + switch (level) { + case CONSOLE_MESSAGE_LEVEL_TIP: + target_level = WebConsoleMessage::LevelTip; + break; + case CONSOLE_MESSAGE_LEVEL_LOG: + target_level = WebConsoleMessage::LevelLog; + break; + case CONSOLE_MESSAGE_LEVEL_WARNING: + target_level = WebConsoleMessage::LevelWarning; + break; + case CONSOLE_MESSAGE_LEVEL_ERROR: + target_level = WebConsoleMessage::LevelError; + break; + } + main_frame->addMessageToConsole( + WebConsoleMessage(target_level, WebString::fromUTF8(message))); +} + +void DevToolsAgent::ContinueProgram() { + WebDevToolsAgent* web_agent = GetWebAgent(); + // TODO(pfeldman): rename didNavigate to continueProgram upstream. + // That is in fact the purpose of the signal. + if (web_agent) + web_agent->didNavigate(); +} + +void DevToolsAgent::OnSetupDevToolsClient() { + new DevToolsClient(static_cast<RenderViewImpl*>(render_view())); +} + +WebDevToolsAgent* DevToolsAgent::GetWebAgent() { + WebView* web_view = render_view()->GetWebView(); + if (!web_view) + return NULL; + return web_view->devToolsAgent(); +} + +bool DevToolsAgent::IsAttached() { + return is_attached_; +} + +} // namespace content diff --git a/content/renderer/devtools/devtools_agent.h b/content/renderer/devtools/devtools_agent.h new file mode 100644 index 0000000..9efe05ee --- /dev/null +++ b/content/renderer/devtools/devtools_agent.h @@ -0,0 +1,73 @@ +// Copyright (c) 2012 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. + +#ifndef CONTENT_RENDERER_DEVTOOLS_DEVTOOLS_AGENT_H_ +#define CONTENT_RENDERER_DEVTOOLS_DEVTOOLS_AGENT_H_ + +#include <string> + +#include "base/basictypes.h" +#include "content/public/common/console_message_level.h" +#include "content/public/renderer/render_view_observer.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebDevToolsAgentClient.h" + +namespace WebKit { +class WebDevToolsAgent; +} + +namespace content { +class RenderViewImpl; + +// DevToolsAgent belongs to the inspectable RenderView and provides Glue's +// agents with the communication capabilities. All messages from/to Glue's +// agents infrastructure are flowing through this communication agent. +// There is a corresponding DevToolsClient object on the client side. +class DevToolsAgent : public RenderViewObserver, + public WebKit::WebDevToolsAgentClient { + public: + explicit DevToolsAgent(RenderViewImpl* render_view); + virtual ~DevToolsAgent(); + + // Returns agent instance for its host id. + static DevToolsAgent* FromHostId(int host_id); + + WebKit::WebDevToolsAgent* GetWebAgent(); + + bool IsAttached(); + + private: + friend class DevToolsAgentFilter; + + // RenderView::Observer implementation. + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + // WebDevToolsAgentClient implementation + virtual void sendMessageToInspectorFrontend(const WebKit::WebString& data); + + virtual int hostIdentifier(); + virtual void saveAgentRuntimeState(const WebKit::WebString& state); + virtual WebKit::WebDevToolsAgentClient::WebKitClientMessageLoop* + createClientMessageLoop(); + virtual void clearBrowserCache(); + virtual void clearBrowserCookies(); + virtual void visitAllocatedObjects(AllocatedObjectVisitor* visitor); + + void OnAttach(); + void OnReattach(const std::string& agent_state); + void OnDetach(); + void OnDispatchOnInspectorBackend(const std::string& message); + void OnInspectElement(int x, int y); + void OnAddMessageToConsole(ConsoleMessageLevel level, + const std::string& message); + void ContinueProgram(); + void OnSetupDevToolsClient(); + + bool is_attached_; + + DISALLOW_COPY_AND_ASSIGN(DevToolsAgent); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_DEVTOOLS_DEVTOOLS_AGENT_H_ diff --git a/content/renderer/devtools/devtools_agent_filter.cc b/content/renderer/devtools/devtools_agent_filter.cc new file mode 100644 index 0000000..4aca9ac --- /dev/null +++ b/content/renderer/devtools/devtools_agent_filter.cc @@ -0,0 +1,77 @@ +// Copyright (c) 2012 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 "content/renderer/devtools/devtools_agent_filter.h" + +#include "base/bind.h" +#include "base/message_loop.h" +#include "content/common/devtools_messages.h" +#include "content/renderer/devtools/devtools_agent.h" +#include "content/renderer/plugin_channel_host.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebDevToolsAgent.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" + +using WebKit::WebDevToolsAgent; +using WebKit::WebString; + +namespace content { + +namespace { + +class MessageImpl : public WebDevToolsAgent::MessageDescriptor { + public: + MessageImpl(const std::string& message, int host_id) + : msg(message), + host_id(host_id) { + } + virtual ~MessageImpl() {} + virtual WebDevToolsAgent* agent() { + DevToolsAgent* agent = DevToolsAgent::FromHostId(host_id); + if (!agent) + return 0; + return agent->GetWebAgent(); + } + virtual WebString message() { return WebString::fromUTF8(msg); } + private: + std::string msg; + int host_id; +}; + +} // namespace + +DevToolsAgentFilter::DevToolsAgentFilter() + : message_handled_(false), + render_thread_loop_(MessageLoop::current()), + current_routing_id_(0) { +} + +bool DevToolsAgentFilter::OnMessageReceived(const IPC::Message& message) { + // Dispatch debugger commands directly from IO. + message_handled_ = true; + current_routing_id_ = message.routing_id(); + IPC_BEGIN_MESSAGE_MAP(DevToolsAgentFilter, message) + IPC_MESSAGE_HANDLER(DevToolsAgentMsg_DispatchOnInspectorBackend, + OnDispatchOnInspectorBackend) + IPC_MESSAGE_UNHANDLED(message_handled_ = false) + IPC_END_MESSAGE_MAP() + return message_handled_; +} + +DevToolsAgentFilter::~DevToolsAgentFilter() {} + +void DevToolsAgentFilter::OnDispatchOnInspectorBackend( + const std::string& message) { + if (!WebDevToolsAgent::shouldInterruptForMessage( + WebString::fromUTF8(message))) { + message_handled_ = false; + return; + } + WebDevToolsAgent::interruptAndDispatch( + new MessageImpl(message, current_routing_id_)); + + render_thread_loop_->PostTask( + FROM_HERE, base::Bind(&WebDevToolsAgent::processPendingMessages)); +} + +} // namespace content diff --git a/content/renderer/devtools/devtools_agent_filter.h b/content/renderer/devtools/devtools_agent_filter.h new file mode 100644 index 0000000..9e4f8ae --- /dev/null +++ b/content/renderer/devtools/devtools_agent_filter.h @@ -0,0 +1,48 @@ +// Copyright (c) 2012 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. + +#ifndef CONTENT_RENDERER_DEVTOOLS_DEVTOOLS_AGENT_FILTER_H_ +#define CONTENT_RENDERER_DEVTOOLS_DEVTOOLS_AGENT_FILTER_H_ + +#include <string> + +#include "ipc/ipc_channel_proxy.h" + +class MessageLoop; +struct DevToolsMessageData; + +namespace content { + +// DevToolsAgentFilter is registered as an IPC filter in order to be able to +// dispatch messages while on the IO thread. The reason for that is that while +// debugging, Render thread is being held by the v8 and hence no messages +// are being dispatched there. While holding the thread in a tight loop, +// v8 provides thread-safe Api for controlling debugger. In our case v8's Api +// is being used from this communication agent on the IO thread. +class DevToolsAgentFilter : public IPC::ChannelProxy::MessageFilter { + public: + // There is a single instance of this class instantiated by the RenderThread. + DevToolsAgentFilter(); + + static void SendRpcMessage(const DevToolsMessageData& data); + + // IPC::ChannelProxy::MessageFilter override. Called on IO thread. + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + protected: + virtual ~DevToolsAgentFilter(); + + private: + void OnDispatchOnInspectorBackend(const std::string& message); + + bool message_handled_; + MessageLoop* render_thread_loop_; + int current_routing_id_; + + DISALLOW_COPY_AND_ASSIGN(DevToolsAgentFilter); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_DEVTOOLS_DEVTOOLS_AGENT_FILTER_H_ diff --git a/content/renderer/devtools/devtools_client.cc b/content/renderer/devtools/devtools_client.cc new file mode 100644 index 0000000..09ec506 --- /dev/null +++ b/content/renderer/devtools/devtools_client.cc @@ -0,0 +1,97 @@ +// Copyright (c) 2012 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 "content/renderer/devtools/devtools_client.h" + +#include "base/command_line.h" +#include "base/message_loop.h" +#include "base/utf_string_conversions.h" +#include "content/common/devtools_messages.h" +#include "content/public/common/content_switches.h" +#include "content/renderer/render_thread_impl.h" +#include "content/renderer/render_view_impl.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebDevToolsFrontend.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebFloatPoint.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" +#include "ui/base/ui_base_switches.h" + +using WebKit::WebDevToolsFrontend; +using WebKit::WebString; + +namespace content { + +DevToolsClient::DevToolsClient(RenderViewImpl* render_view) + : RenderViewObserver(render_view) { + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + web_tools_frontend_.reset( + WebDevToolsFrontend::create( + render_view->webview(), + this, + ASCIIToUTF16(command_line.GetSwitchValueASCII(switches::kLang)))); +} + +DevToolsClient::~DevToolsClient() { +} + +bool DevToolsClient::OnMessageReceived(const IPC::Message& message) { + DCHECK(RenderThreadImpl::current()); + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(DevToolsClient, message) + IPC_MESSAGE_HANDLER(DevToolsClientMsg_DispatchOnInspectorFrontend, + OnDispatchOnInspectorFrontend) + IPC_MESSAGE_UNHANDLED(handled = false); + IPC_END_MESSAGE_MAP() + + return handled; +} + +void DevToolsClient::sendMessageToBackend(const WebString& message) { + Send(new DevToolsAgentMsg_DispatchOnInspectorBackend(routing_id(), + message.utf8())); +} + +void DevToolsClient::activateWindow() { + Send(new DevToolsHostMsg_ActivateWindow(routing_id())); +} + +void DevToolsClient::closeWindow() { + Send(new DevToolsHostMsg_CloseWindow(routing_id())); +} + +void DevToolsClient::moveWindowBy(const WebKit::WebFloatPoint& offset) { + Send(new DevToolsHostMsg_MoveWindow(routing_id(), offset.x, offset.y)); +} + +void DevToolsClient::requestSetDockSide(const WebKit::WebString& side) { + Send(new DevToolsHostMsg_RequestSetDockSide(routing_id(), side.utf8())); +} + +void DevToolsClient::openInNewTab(const WebKit::WebString& url) { + Send(new DevToolsHostMsg_OpenInNewTab(routing_id(), + url.utf8())); +} + +void DevToolsClient::save(const WebKit::WebString& url, + const WebKit::WebString& content, + bool save_as) { + Send(new DevToolsHostMsg_Save(routing_id(), + url.utf8(), + content.utf8(), + save_as)); +} + +void DevToolsClient::append(const WebKit::WebString& url, + const WebKit::WebString& content) { + Send(new DevToolsHostMsg_Append(routing_id(), + url.utf8(), + content.utf8())); +} + +void DevToolsClient::OnDispatchOnInspectorFrontend(const std::string& message) { + web_tools_frontend_->dispatchOnInspectorFrontend( + WebString::fromUTF8(message)); +} + +} // namespace content diff --git a/content/renderer/devtools/devtools_client.h b/content/renderer/devtools/devtools_client.h new file mode 100644 index 0000000..f5fa8f0 --- /dev/null +++ b/content/renderer/devtools/devtools_client.h @@ -0,0 +1,63 @@ +// Copyright (c) 2012 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. + +#ifndef CONTENT_RENDERER_DEVTOOLS_DEVTOOLS_CLIENT_H_ +#define CONTENT_RENDERER_DEVTOOLS_DEVTOOLS_CLIENT_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "content/public/renderer/render_view_observer.h" +#include "third_party/WebKit/Source/WebKit/chromium/public/WebDevToolsFrontendClient.h" + +namespace WebKit { +class WebDevToolsFrontend; +class WebString; +} + +namespace content { + +class RenderViewImpl; + +// Developer tools UI end of communication channel between the render process of +// the page being inspected and tools UI renderer process. All messages will +// go through browser process. On the side of the inspected page there's +// corresponding DevToolsAgent object. +// TODO(yurys): now the client is almost empty later it will delegate calls to +// code in glue +class DevToolsClient : public RenderViewObserver, + public WebKit::WebDevToolsFrontendClient { + public: + explicit DevToolsClient(RenderViewImpl* render_view); + virtual ~DevToolsClient(); + + private: + // RenderView::Observer implementation. + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + + // WebDevToolsFrontendClient implementation. + virtual void sendMessageToBackend(const WebKit::WebString&) OVERRIDE; + + virtual void activateWindow() OVERRIDE; + virtual void closeWindow() OVERRIDE; + virtual void moveWindowBy(const WebKit::WebFloatPoint& offset) OVERRIDE; + virtual void requestSetDockSide(const WebKit::WebString& side) OVERRIDE; + virtual void openInNewTab(const WebKit::WebString& side) OVERRIDE; + virtual void save(const WebKit::WebString& url, + const WebKit::WebString& content, + bool save_as) OVERRIDE; + virtual void append(const WebKit::WebString& url, + const WebKit::WebString& content) OVERRIDE; + + void OnDispatchOnInspectorFrontend(const std::string& message); + + scoped_ptr<WebKit::WebDevToolsFrontend> web_tools_frontend_; + + DISALLOW_COPY_AND_ASSIGN(DevToolsClient); +}; + +} // namespace content + +#endif // CONTENT_RENDERER_DEVTOOLS_DEVTOOLS_CLIENT_H_ |