Add InspectableWebContents

This class can be used to create a content::WebContents that can be inspected
by the Chrome Dev Tools. This requires embedding applications to copy
content_shell.pak into their resource bundle.

Right now the dev tools are always docked to the bottom of the view; we don't
yet support undocking or changing the docked side.

Fixes #1.
This commit is contained in:
Adam Roben 2013-03-14 09:03:50 -04:00
parent e1b5e5e1bf
commit b2a79856ef
22 changed files with 601 additions and 5 deletions

View file

@ -23,14 +23,30 @@
'browser/browser_main_parts.cc',
'browser/browser_main_parts.h',
'browser/browser_main_parts_mac.mm',
'browser/devtools_delegate.cc',
'browser/devtools_delegate.h',
'browser/devtools_frontend.cc',
'browser/devtools_frontend.h',
'browser/inspectable_web_contents.cc',
'browser/inspectable_web_contents.h',
'browser/inspectable_web_contents_impl.cc',
'browser/inspectable_web_contents_impl.h',
'browser/inspectable_web_contents_view.h',
'browser/inspectable_web_contents_view_mac.h',
'browser/inspectable_web_contents_view_mac.mm',
'browser/mac/bry_application.h',
'browser/mac/bry_application.mm',
'browser/mac/bry_inspectable_web_contents_view.h',
'browser/mac/bry_inspectable_web_contents_view.mm',
'browser/mac/bry_inspectable_web_contents_view_private.h',
'browser/network_delegate.cc',
'browser/network_delegate.h',
'browser/url_request_context_getter.cc',
'browser/url_request_context_getter.h',
'common/application_name.h',
'common/application_name_mac.mm',
'common/content_client.cc',
'common/content_client.h',
'common/main_delegate.cc',
'common/main_delegate.h',
'common/main_delegate_mac.mm',

View file

@ -2,9 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.
#include "browser_main_parts.h"
#include "browser/browser_main_parts.h"
#include "browser_context.h"
#include "browser/browser_context.h"
#include "browser/devtools_delegate.h"
#include "content/public/browser/devtools_http_handler.h"
#include "net/base/tcp_listen_socket.h"
namespace brightray {
@ -12,10 +16,18 @@ BrowserMainParts::BrowserMainParts() {
}
BrowserMainParts::~BrowserMainParts() {
devtools_http_handler_->Stop();
devtools_http_handler_ = nullptr;
}
void BrowserMainParts::PreMainMessageLoopRun() {
browser_context_.reset(new BrowserContext);
// These two objects are owned by devtools_http_handler_.
auto delegate = new DevToolsDelegate;
auto factory = new net::TCPListenSocketFactory("127.0.0.1", 0);
devtools_http_handler_ = content::DevToolsHttpHandler::Start(factory, std::string(), delegate);
}
}

View file

@ -9,6 +9,10 @@
#include "base/memory/scoped_ptr.h"
#include "content/public/browser/browser_main_parts.h"
namespace content {
class DevToolsHttpHandler;
}
namespace brightray {
class BrowserContext;
@ -19,6 +23,7 @@ public:
~BrowserMainParts();
BrowserContext* browser_context() { return browser_context_.get(); }
content::DevToolsHttpHandler* devtools_http_handler() { return devtools_http_handler_; }
protected:
#if defined(OS_MACOSX)
@ -29,6 +34,7 @@ protected:
private:
scoped_ptr<BrowserContext> browser_context_;
content::DevToolsHttpHandler* devtools_http_handler_;
DISALLOW_COPY_AND_ASSIGN(BrowserMainParts);
};

View file

@ -0,0 +1,39 @@
// 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-CHROMIUM file.
#include "devtools_delegate.h"
namespace brightray {
DevToolsDelegate::DevToolsDelegate() {
}
DevToolsDelegate::~DevToolsDelegate() {
}
std::string DevToolsDelegate::GetDiscoveryPageHTML() {
return std::string();
}
bool DevToolsDelegate::BundlesFrontendResources() {
return true;
}
base::FilePath DevToolsDelegate::GetDebugFrontendDir() {
return base::FilePath();
}
std::string DevToolsDelegate::GetPageThumbnailData(const GURL&) {
return std::string();
}
content::RenderViewHost* DevToolsDelegate::CreateNewTarget() {
return nullptr;
}
content::DevToolsHttpHandlerDelegate::TargetType DevToolsDelegate::GetTargetType(content::RenderViewHost*) {
return kTargetTypeTab;
}
}

View file

@ -0,0 +1,28 @@
// 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-CHROMIUM file.
#ifndef BRIGHTRAY_BROWSER_DEVTOOLS_DELEGATE_H_
#define BRIGHTRAY_BROWSER_DEVTOOLS_DELEGATE_H_
#include "content/public/browser/devtools_http_handler_delegate.h"
namespace brightray {
class DevToolsDelegate : public content::DevToolsHttpHandlerDelegate {
public:
DevToolsDelegate();
~DevToolsDelegate();
private:
virtual std::string GetDiscoveryPageHTML() OVERRIDE;
virtual bool BundlesFrontendResources() OVERRIDE;
virtual base::FilePath GetDebugFrontendDir() OVERRIDE;
virtual std::string GetPageThumbnailData(const GURL&) OVERRIDE;
virtual content::RenderViewHost* CreateNewTarget() OVERRIDE;
virtual TargetType GetTargetType(content::RenderViewHost*) OVERRIDE;
};
}
#endif

View file

@ -0,0 +1,84 @@
// 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-CHROMIUM file.
#include "devtools_frontend.h"
#include "browser/browser_client.h"
#include "browser/browser_main_parts.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/devtools_client_host.h"
#include "content/public/browser/devtools_http_handler.h"
#include "content/public/browser/devtools_manager.h"
#include "content/public/browser/web_contents.h"
namespace brightray {
content::WebContents* DevToolsFrontend::Show(content::WebContents* inspected_contents) {
// frontend will delete itself when the WebContents closes.
auto frontend = new DevToolsFrontend(inspected_contents);
return frontend->web_contents();
}
DevToolsFrontend::DevToolsFrontend(content::WebContents* inspected_contents)
: WebContentsObserver(content::WebContents::Create(content::WebContents::CreateParams(inspected_contents->GetBrowserContext()))),
agent_host_(content::DevToolsAgentHost::GetFor(inspected_contents->GetRenderViewHost())),
frontend_host_(content::DevToolsClientHost::CreateDevToolsFrontendHost(web_contents(), this)) {
auto client = static_cast<BrowserClient*>(content::GetContentClient()->browser());
auto handler = client->browser_main_parts()->devtools_http_handler();
auto url = handler->GetFrontendURL(nullptr);
web_contents()->GetController().LoadURL(url, content::Referrer(), content::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());
}
DevToolsFrontend::~DevToolsFrontend() {
}
void DevToolsFrontend::ActivateWindow() {
}
void DevToolsFrontend::ChangeAttachedWindowHeight(unsigned height) {
}
void DevToolsFrontend::CloseWindow() {
}
void DevToolsFrontend::MoveWindow(int x, int y) {
}
void DevToolsFrontend::SetDockSide(const std::string& side) {
}
void DevToolsFrontend::OpenInNewTab(const std::string& url) {
}
void DevToolsFrontend::SaveToFile(const std::string& url, const std::string& content, bool save_as) {
}
void DevToolsFrontend::AppendToFile(const std::string& url, const std::string& content) {
}
void DevToolsFrontend::RequestFileSystems() {
}
void DevToolsFrontend::AddFileSystem() {
}
void DevToolsFrontend::RemoveFileSystem(const std::string& file_system_path) {
}
void DevToolsFrontend::InspectedContentsClosing() {
}
void DevToolsFrontend::RenderViewCreated(content::RenderViewHost* render_view_host) {
content::DevToolsClientHost::SetupDevToolsFrontendClient(web_contents()->GetRenderViewHost());
content::DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(agent_host_, frontend_host_.get());
}
void DevToolsFrontend::WebContentsDestroyed(content::WebContents*) {
content::DevToolsManager::GetInstance()->ClientHostClosing(frontend_host_.get());
delete this;
}
}

View file

@ -0,0 +1,52 @@
// 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-CHROMIUM file.
#ifndef BRIGHTRAY_BROWSER_DEVTOOLS_FRONTEND_H_
#define BRIGHTRAY_BROWSER_DEVTOOLS_FRONTEND_H_
#include "base/memory/scoped_ptr.h"
#include "content/public/browser/devtools_frontend_host_delegate.h"
#include "content/public/browser/web_contents_observer.h"
namespace content {
class DevToolsAgentHost;
class DevToolsClientHost;
}
namespace brightray {
class DevToolsFrontend : content::DevToolsFrontendHostDelegate, content::WebContentsObserver {
public:
static content::WebContents* Show(content::WebContents* inspected_contents);
private:
DevToolsFrontend(content::WebContents* inspected_contents);
~DevToolsFrontend();
virtual void ActivateWindow() OVERRIDE;
virtual void ChangeAttachedWindowHeight(unsigned height) OVERRIDE;
virtual void CloseWindow() OVERRIDE;
virtual void MoveWindow(int x, int y) OVERRIDE;
virtual void SetDockSide(const std::string& side) OVERRIDE;
virtual void OpenInNewTab(const std::string& url) OVERRIDE;
virtual void SaveToFile(const std::string& url,
const std::string& content,
bool save_as) OVERRIDE;
virtual void AppendToFile(const std::string& url,
const std::string& content) OVERRIDE;
virtual void RequestFileSystems() OVERRIDE;
virtual void AddFileSystem() OVERRIDE;
virtual void RemoveFileSystem(const std::string& file_system_path) OVERRIDE;
virtual void InspectedContentsClosing() OVERRIDE;
virtual void RenderViewCreated(content::RenderViewHost*) OVERRIDE;
virtual void WebContentsDestroyed(content::WebContents*) OVERRIDE;
scoped_refptr<content::DevToolsAgentHost> agent_host_;
scoped_ptr<content::DevToolsClientHost> frontend_host_;
};
}
#endif

View file

@ -0,0 +1,11 @@
#include "browser/inspectable_web_contents.h"
#include "browser/inspectable_web_contents_impl.h"
namespace brightray {
InspectableWebContents* InspectableWebContents::Create(const content::WebContents::CreateParams& create_params) {
return new InspectableWebContentsImpl(create_params);
}
}

View file

@ -0,0 +1,23 @@
#ifndef BRIGHTRAY_INSPECTABLE_WEB_CONTENTS_H_
#define BRIGHTRAY_INSPECTABLE_WEB_CONTENTS_H_
#include "content/public/browser/web_contents.h"
namespace brightray {
class InspectableWebContentsView;
class InspectableWebContents {
public:
static InspectableWebContents* Create(const content::WebContents::CreateParams&);
virtual ~InspectableWebContents() {}
virtual InspectableWebContentsView* GetView() const = 0;
virtual content::WebContents* GetWebContents() const = 0;
virtual void ShowDevTools() = 0;
};
}
#endif

View file

@ -0,0 +1,33 @@
#include "browser/inspectable_web_contents_impl.h"
#include "browser/devtools_frontend.h"
#include "browser/inspectable_web_contents_view.h"
namespace brightray {
// Implemented separately on each platform.
InspectableWebContentsView* CreateInspectableContentsView(InspectableWebContentsImpl*);
InspectableWebContentsImpl::InspectableWebContentsImpl(const content::WebContents::CreateParams& create_params)
: web_contents_(content::WebContents::Create(create_params)) {
view_.reset(CreateInspectableContentsView(this));
}
InspectableWebContentsImpl::~InspectableWebContentsImpl() {
}
InspectableWebContentsView* InspectableWebContentsImpl::GetView() const {
return view_.get();
}
content::WebContents* InspectableWebContentsImpl::GetWebContents() const {
return web_contents_.get();
}
void InspectableWebContentsImpl::ShowDevTools() {
if (!devtools_web_contents_)
devtools_web_contents_.reset(DevToolsFrontend::Show(web_contents_.get()));
view_->ShowDevTools();
}
}

View file

@ -0,0 +1,32 @@
#ifndef BRIGHTRAY_BROWSER_INSPECTABLE_WEB_CONTENTS_IMPL_H_
#define BRIGHTRAY_BROWSER_INSPECTABLE_WEB_CONTENTS_IMPL_H_
#include "browser/inspectable_web_contents.h"
namespace brightray {
class InspectableWebContentsView;
class InspectableWebContentsImpl : public InspectableWebContents {
public:
InspectableWebContentsImpl(const content::WebContents::CreateParams&);
virtual ~InspectableWebContentsImpl() OVERRIDE;
virtual InspectableWebContentsView* GetView() const OVERRIDE;
virtual content::WebContents* GetWebContents() const OVERRIDE;
virtual void ShowDevTools() OVERRIDE;
content::WebContents* devtools_web_contents() { return devtools_web_contents_.get(); }
private:
scoped_ptr<content::WebContents> web_contents_;
scoped_ptr<content::WebContents> devtools_web_contents_;
scoped_ptr<InspectableWebContentsView> view_;
DISALLOW_COPY_AND_ASSIGN(InspectableWebContentsImpl);
};
}
#endif

View file

@ -0,0 +1,19 @@
#ifndef BRIGHTRAY_BROWSER_INSPECTABLE_WEB_CONTENTS_VIEW_H_
#define BRIGHTRAY_BROWSER_INSPECTABLE_WEB_CONTENTS_VIEW_H_
#include "ui/gfx/native_widget_types.h"
namespace brightray {
class InspectableWebContentsView {
public:
virtual ~InspectableWebContentsView() {}
virtual gfx::NativeView GetNativeView() const = 0;
virtual void ShowDevTools() = 0;
};
}
#endif

View file

@ -0,0 +1,34 @@
#ifndef BRIGHTRAY_BROWSER_INSPECTABLE_WEB_CONTENTS_VIEW_MAC_H_
#define BRIGHTRAY_BROWSER_INSPECTABLE_WEB_CONTENTS_VIEW_MAC_H_
#import "browser/inspectable_web_contents_view.h"
#import "base/memory/scoped_nsobject.h"
@class BRYInspectableWebContentsView;
namespace brightray {
class InspectableWebContentsImpl;
class InspectableWebContentsViewMac : public InspectableWebContentsView {
public:
InspectableWebContentsViewMac(InspectableWebContentsImpl*);
virtual gfx::NativeView GetNativeView() const OVERRIDE;
virtual void ShowDevTools() OVERRIDE;
InspectableWebContentsImpl* inspectable_web_contents() { return inspectable_web_contents_; }
private:
// Owns us.
InspectableWebContentsImpl* inspectable_web_contents_;
scoped_nsobject<BRYInspectableWebContentsView> view_;
DISALLOW_COPY_AND_ASSIGN(InspectableWebContentsViewMac);
};
}
#endif

View file

@ -0,0 +1,28 @@
#import "browser/inspectable_web_contents_view_mac.h"
#import "browser/inspectable_web_contents.h"
#import "browser/mac/bry_inspectable_web_contents_view_private.h"
#import "content/public/browser/web_contents_view.h"
#import <AppKit/AppKit.h>
namespace brightray {
InspectableWebContentsView* CreateInspectableContentsView(InspectableWebContentsImpl* inspectable_web_contents) {
return new InspectableWebContentsViewMac(inspectable_web_contents);
}
InspectableWebContentsViewMac::InspectableWebContentsViewMac(InspectableWebContentsImpl* inspectable_web_contents)
: inspectable_web_contents_(inspectable_web_contents),
view_([[BRYInspectableWebContentsView alloc] initWithInspectableWebContentsViewMac:this]) {
}
gfx::NativeView InspectableWebContentsViewMac::GetNativeView() const {
return view_.get();
}
void InspectableWebContentsViewMac::ShowDevTools() {
[view_ setDevToolsVisible:YES];
}
}

View file

@ -0,0 +1,12 @@
#import <AppKit/AppKit.h>
@class BRYInspectableWebContentsViewPrivate;
@interface BRYInspectableWebContentsView : NSView {
@private
BRYInspectableWebContentsViewPrivate *_private;
}
- (IBAction)showDevTools:(id)sender;
@end

View file

@ -0,0 +1,77 @@
#import "browser/mac/bry_inspectable_web_contents_view.h"
#import "browser/inspectable_web_contents_impl.h"
#import "browser/inspectable_web_contents_view_mac.h"
#import "browser/mac/bry_inspectable_web_contents_view_private.h"
#import "content/public/browser/web_contents_view.h"
using namespace brightray;
@interface BRYInspectableWebContentsViewPrivate : NSObject {
@public
InspectableWebContentsViewMac *inspectableWebContentsView;
NSSplitView *splitView;
}
@end
@implementation BRYInspectableWebContentsView
- (instancetype)initWithInspectableWebContentsViewMac:(InspectableWebContentsViewMac *)inspectableWebContentsView {
self = [super init];
if (!self)
return nil;
_private = [[BRYInspectableWebContentsViewPrivate alloc] init];
_private->inspectableWebContentsView = inspectableWebContentsView;
_private->splitView = [[NSSplitView alloc] init];
[self addSubview:_private->splitView];
_private->splitView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
_private->splitView.dividerStyle = NSSplitViewDividerStyleThin;
[_private->splitView addSubview:inspectableWebContentsView->inspectable_web_contents()->GetWebContents()->GetView()->GetNativeView()];
return self;
}
- (void)dealloc {
[_private release];
_private = nil;
[super dealloc];
}
- (IBAction)showDevTools:(id)sender {
_private->inspectableWebContentsView->inspectable_web_contents()->ShowDevTools();
}
- (void)setDevToolsVisible:(BOOL)visible {
BOOL wasVisible = _private->splitView.subviews.count == 2;
if (wasVisible == visible)
return;
auto devToolsWebContents = _private->inspectableWebContentsView->inspectable_web_contents()->devtools_web_contents();
auto devToolsView = devToolsWebContents->GetView()->GetNativeView();
if (visible) {
auto inspectedView = _private->inspectableWebContentsView->inspectable_web_contents()->GetWebContents()->GetView()->GetNativeView();
CGRect frame = NSRectToCGRect(inspectedView.frame);
CGRect inspectedViewFrame;
CGRect devToolsFrame;
CGRectDivide(frame, &inspectedViewFrame, &devToolsFrame, CGRectGetHeight(frame) * 2 / 3, CGRectMaxYEdge);
inspectedView.frame = NSRectFromCGRect(inspectedViewFrame);
devToolsView.frame = NSRectFromCGRect(devToolsFrame);
[_private->splitView addSubview:devToolsView];
} else {
[devToolsView removeFromSuperview];
}
[_private->splitView adjustSubviews];
}
@end
@implementation BRYInspectableWebContentsViewPrivate
@end

View file

@ -0,0 +1,12 @@
#import "browser/mac/bry_inspectable_web_contents_view.h"
namespace brightray {
class InspectableWebContentsViewMac;
}
@interface BRYInspectableWebContentsView (Private)
- (instancetype)initWithInspectableWebContentsViewMac:(brightray::InspectableWebContentsViewMac *)inspectableWebContentsView;
- (void)setDevToolsVisible:(BOOL)visible;
@end

View file

@ -0,0 +1,28 @@
// 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-CHROMIUM file.
#include "common/content_client.h"
#include "common/application_name.h"
#include "ui/base/resource/resource_bundle.h"
#include "webkit/user_agent/user_agent_util.h"
namespace brightray {
ContentClient::ContentClient() {
}
ContentClient::~ContentClient() {
}
std::string ContentClient::GetUserAgent() const {
return webkit_glue::BuildUserAgentFromProduct(GetApplicationName());
}
base::StringPiece ContentClient::GetDataResource(int resource_id, ui::ScaleFactor scale_factor) const {
return ui::ResourceBundle::GetSharedInstance().GetRawDataResourceForScale(resource_id, scale_factor);
}
}

View file

@ -0,0 +1,27 @@
// 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-CHROMIUM file.
#ifndef BRIGHTRAY_COMMON_CONTENT_CLIENT_H_
#define BRIGHTRAY_COMMON_CONTENT_CLIENT_H_
#include "base/compiler_specific.h"
#include "content/public/common/content_client.h"
namespace brightray {
class ContentClient : public content::ContentClient {
public:
ContentClient();
~ContentClient();
private:
virtual std::string GetUserAgent() const OVERRIDE;
virtual base::StringPiece GetDataResource(int resource_id, ui::ScaleFactor) const OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(ContentClient);
};
}
#endif

View file

@ -2,20 +2,28 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.
#include "main_delegate.h"
#include "common/main_delegate.h"
#include "browser/browser_client.h"
#include "common/content_client.h"
#include "browser_client.h"
#include "base/command_line.h"
#include "content/public/common/content_switches.h"
namespace brightray {
MainDelegate::MainDelegate() {
MainDelegate::MainDelegate()
: content_client_(new ContentClient) {
}
MainDelegate::~MainDelegate() {
}
bool MainDelegate::BasicStartupComplete(int* exit_code) {
SetContentClient(content_client_.get());
return false;
}
void MainDelegate::PreSandboxStartup() {
// FIXME: We don't currently support running sandboxed.
CommandLine::ForCurrentProcess()->AppendSwitch(switches::kNoSandbox);
@ -24,6 +32,7 @@ void MainDelegate::PreSandboxStartup() {
OverrideChildProcessPath();
OverrideFrameworkBundlePath();
#endif
InitializeResourceBundle();
}
}

View file

@ -11,19 +11,25 @@
namespace brightray {
class ContentClient;
class MainDelegate : public content::ContentMainDelegate {
public:
MainDelegate();
~MainDelegate();
private:
static void InitializeResourceBundle();
#if defined(OS_MACOSX)
static void OverrideChildProcessPath();
static void OverrideFrameworkBundlePath();
#endif
virtual bool BasicStartupComplete(int* exit_code) OVERRIDE;
virtual void PreSandboxStartup() OVERRIDE;
scoped_ptr<ContentClient> content_client_;
DISALLOW_COPY_AND_ASSIGN(MainDelegate);
};

View file

@ -6,10 +6,12 @@
#import "main_delegate.h"
#include "common/application_name.h"
#include "base/mac/bundle_locations.h"
#include "base/mac/foundation_util.h"
#include "base/path_service.h"
#include "content/public/common/content_paths.h"
#include "ui/base/resource/resource_bundle.h"
namespace brightray {
@ -38,6 +40,12 @@ base::FilePath GetFrameworksPath() {
}
void MainDelegate::InitializeResourceBundle() {
auto path = [base::mac::FrameworkBundle() pathForResource:@"content_shell" ofType:@"pak"];
ui::ResourceBundle::InitSharedInstanceWithPakPath(base::mac::NSStringToFilePath(path));
}
void MainDelegate::OverrideFrameworkBundlePath() {
base::FilePath helper_path = GetFrameworksPath().Append(GetApplicationName() + ".framework");