2013-03-27 18:33:00 +04:00
|
|
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
|
|
|
// Copyright (c) 2013 Adam Roben <adam@roben.org>. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE-CHROMIUM file.
|
|
|
|
|
2013-03-14 17:03:50 +04:00
|
|
|
#include "browser/inspectable_web_contents_impl.h"
|
|
|
|
|
2013-03-27 18:33:00 +04:00
|
|
|
#include "browser/browser_client.h"
|
2013-04-08 21:53:53 +04:00
|
|
|
#include "browser/browser_context.h"
|
2013-03-27 18:33:00 +04:00
|
|
|
#include "browser/browser_main_parts.h"
|
2014-03-04 12:12:02 +04:00
|
|
|
#include "browser/inspectable_web_contents_delegate.h"
|
2013-03-14 17:03:50 +04:00
|
|
|
#include "browser/inspectable_web_contents_view.h"
|
|
|
|
|
2014-07-09 11:34:10 +04:00
|
|
|
#include "base/json/json_reader.h"
|
2013-04-08 21:53:53 +04:00
|
|
|
#include "base/prefs/pref_registry_simple.h"
|
|
|
|
#include "base/prefs/pref_service.h"
|
2013-10-07 23:16:49 +04:00
|
|
|
#include "base/strings/stringprintf.h"
|
2013-08-24 00:56:30 +04:00
|
|
|
#include "base/strings/utf_string_conversions.h"
|
2014-07-04 17:34:47 +04:00
|
|
|
#include "base/values.h"
|
2013-03-27 18:33:00 +04:00
|
|
|
#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"
|
2014-08-26 11:06:51 +04:00
|
|
|
#include "content/public/browser/host_zoom_map.h"
|
2014-07-09 11:34:10 +04:00
|
|
|
#include "content/public/browser/render_frame_host.h"
|
2013-03-27 19:19:15 +04:00
|
|
|
#include "content/public/browser/render_view_host.h"
|
2013-03-27 18:33:00 +04:00
|
|
|
|
2013-03-14 17:03:50 +04:00
|
|
|
namespace brightray {
|
|
|
|
|
2013-04-08 21:53:53 +04:00
|
|
|
namespace {
|
|
|
|
|
2014-08-26 11:06:51 +04:00
|
|
|
const double kPresetZoomFactors[] = { 0.25, 0.333, 0.5, 0.666, 0.75, 0.9, 1.0,
|
|
|
|
1.1, 1.25, 1.5, 1.75, 2.0, 2.5, 3.0, 4.0,
|
|
|
|
5.0 };
|
|
|
|
|
|
|
|
const char kDevToolsScheme[] = "chrome-devtools";
|
|
|
|
const char kDevToolsHost[] = "devtools";
|
2014-08-11 06:42:50 +04:00
|
|
|
const char kChromeUIDevToolsURL[] = "chrome-devtools://devtools/devtools.html?"
|
|
|
|
"can_dock=true&&"
|
|
|
|
"experiments=true";
|
2014-07-04 17:34:47 +04:00
|
|
|
const char kDevToolsBoundsPref[] = "brightray.devtools.bounds";
|
2013-04-08 21:53:53 +04:00
|
|
|
|
2014-07-09 11:34:10 +04:00
|
|
|
const char kFrontendHostId[] = "id";
|
|
|
|
const char kFrontendHostMethod[] = "method";
|
|
|
|
const char kFrontendHostParams[] = "params";
|
|
|
|
|
2014-07-04 17:34:47 +04:00
|
|
|
void RectToDictionary(const gfx::Rect& bounds, base::DictionaryValue* dict) {
|
|
|
|
dict->SetInteger("x", bounds.x());
|
|
|
|
dict->SetInteger("y", bounds.y());
|
|
|
|
dict->SetInteger("width", bounds.width());
|
|
|
|
dict->SetInteger("height", bounds.height());
|
2013-04-08 21:53:53 +04:00
|
|
|
}
|
|
|
|
|
2014-07-04 17:34:47 +04:00
|
|
|
void DictionaryToRect(const base::DictionaryValue& dict, gfx::Rect* bounds) {
|
|
|
|
int x = 0, y = 0, width = 800, height = 600;
|
|
|
|
dict.GetInteger("x", &x);
|
|
|
|
dict.GetInteger("y", &y);
|
|
|
|
dict.GetInteger("width", &width);
|
|
|
|
dict.GetInteger("height", &height);
|
|
|
|
*bounds = gfx::Rect(x, y, width, height);
|
|
|
|
}
|
|
|
|
|
2014-07-11 18:22:23 +04:00
|
|
|
bool ParseMessage(const std::string& message,
|
|
|
|
std::string* method,
|
|
|
|
base::ListValue* params,
|
|
|
|
int* id) {
|
|
|
|
scoped_ptr<base::Value> parsed_message(base::JSONReader::Read(message));
|
|
|
|
if (!parsed_message)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
base::DictionaryValue* dict = NULL;
|
|
|
|
if (!parsed_message->GetAsDictionary(&dict))
|
|
|
|
return false;
|
|
|
|
if (!dict->GetString(kFrontendHostMethod, method))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// "params" is optional.
|
|
|
|
if (dict->HasKey(kFrontendHostParams)) {
|
|
|
|
base::ListValue* internal_params;
|
|
|
|
if (dict->GetList(kFrontendHostParams, &internal_params))
|
|
|
|
params->Swap(internal_params);
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
*id = 0;
|
|
|
|
dict->GetInteger(kFrontendHostId, id);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-08-26 11:06:51 +04:00
|
|
|
double GetZoomLevelForWebContents(content::WebContents* web_contents) {
|
|
|
|
content::HostZoomMap* host_zoom_map = content::HostZoomMap::GetForBrowserContext(
|
|
|
|
web_contents->GetBrowserContext());
|
|
|
|
return host_zoom_map->GetZoomLevelForHostAndScheme(kDevToolsScheme, kDevToolsHost);
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetZoomLevelForWebContents(content::WebContents* web_contents, double level) {
|
|
|
|
content::HostZoomMap* host_zoom_map = content::HostZoomMap::GetForBrowserContext(
|
|
|
|
web_contents->GetBrowserContext());
|
|
|
|
return host_zoom_map->SetZoomLevelForHostAndScheme(kDevToolsScheme, kDevToolsHost, level);
|
|
|
|
}
|
|
|
|
|
|
|
|
double GetNextZoomLevel(double level, bool out) {
|
|
|
|
double factor = content::ZoomLevelToZoomFactor(level);
|
|
|
|
size_t size = arraysize(kPresetZoomFactors);
|
|
|
|
for (size_t i = 0; i < size; ++i) {
|
|
|
|
if (!content::ZoomValuesEqual(kPresetZoomFactors[i], factor))
|
|
|
|
continue;
|
|
|
|
if (out && i > 0)
|
|
|
|
return content::ZoomFactorToZoomLevel(kPresetZoomFactors[i - 1]);
|
|
|
|
if (!out && i != size - 1)
|
|
|
|
return content::ZoomFactorToZoomLevel(kPresetZoomFactors[i + 1]);
|
|
|
|
}
|
|
|
|
return level;
|
|
|
|
}
|
|
|
|
|
2014-07-04 17:34:47 +04:00
|
|
|
} // namespace
|
|
|
|
|
2013-03-14 17:03:50 +04:00
|
|
|
// Implemented separately on each platform.
|
2013-11-18 03:08:34 +04:00
|
|
|
InspectableWebContentsView* CreateInspectableContentsView(
|
|
|
|
InspectableWebContentsImpl* inspectable_web_contents_impl);
|
2013-03-14 17:03:50 +04:00
|
|
|
|
2013-04-08 21:53:53 +04:00
|
|
|
void InspectableWebContentsImpl::RegisterPrefs(PrefRegistrySimple* registry) {
|
2014-07-11 17:55:57 +04:00
|
|
|
auto bounds_dict = make_scoped_ptr(new base::DictionaryValue);
|
2014-07-04 17:34:47 +04:00
|
|
|
RectToDictionary(gfx::Rect(0, 0, 800, 600), bounds_dict.get());
|
|
|
|
registry->RegisterDictionaryPref(kDevToolsBoundsPref, bounds_dict.release());
|
2013-04-08 21:53:53 +04:00
|
|
|
}
|
|
|
|
|
2013-11-18 03:08:34 +04:00
|
|
|
InspectableWebContentsImpl::InspectableWebContentsImpl(
|
|
|
|
content::WebContents* web_contents)
|
2014-03-04 12:12:02 +04:00
|
|
|
: web_contents_(web_contents),
|
|
|
|
delegate_(nullptr) {
|
2014-07-04 17:34:47 +04:00
|
|
|
auto context = static_cast<BrowserContext*>(web_contents_->GetBrowserContext());
|
|
|
|
auto bounds_dict = context->prefs()->GetDictionary(kDevToolsBoundsPref);
|
|
|
|
if (bounds_dict)
|
|
|
|
DictionaryToRect(*bounds_dict, &devtools_bounds_);
|
|
|
|
|
2013-03-14 17:03:50 +04:00
|
|
|
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() {
|
2014-07-02 12:21:47 +04:00
|
|
|
// Show devtools only after it has done loading, this is to make sure the
|
|
|
|
// SetIsDocked is called *BEFORE* ShowDevTools.
|
2013-03-27 18:33:00 +04:00
|
|
|
if (!devtools_web_contents_) {
|
2013-12-02 21:38:24 +04:00
|
|
|
embedder_message_dispatcher_.reset(
|
|
|
|
new DevToolsEmbedderMessageDispatcher(this));
|
|
|
|
|
2014-08-31 14:43:01 +04:00
|
|
|
content::WebContents::CreateParams create_params(web_contents_->GetBrowserContext());
|
2013-11-18 03:08:34 +04:00
|
|
|
devtools_web_contents_.reset(content::WebContents::Create(create_params));
|
2013-10-10 22:07:20 +04:00
|
|
|
|
2013-03-27 18:33:00 +04:00
|
|
|
Observe(devtools_web_contents_.get());
|
|
|
|
devtools_web_contents_->SetDelegate(this);
|
|
|
|
|
2013-11-18 03:08:34 +04:00
|
|
|
agent_host_ = content::DevToolsAgentHost::GetOrCreateFor(
|
|
|
|
web_contents_->GetRenderViewHost());
|
|
|
|
frontend_host_.reset(
|
|
|
|
content::DevToolsClientHost::CreateDevToolsFrontendHost(
|
|
|
|
devtools_web_contents_.get(), this));
|
|
|
|
content::DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(
|
|
|
|
agent_host_, frontend_host_.get());
|
2013-03-27 18:33:00 +04:00
|
|
|
|
2013-05-14 11:36:40 +04:00
|
|
|
GURL devtools_url(kChromeUIDevToolsURL);
|
2013-11-18 03:08:34 +04:00
|
|
|
devtools_web_contents_->GetController().LoadURL(
|
|
|
|
devtools_url,
|
|
|
|
content::Referrer(),
|
|
|
|
content::PAGE_TRANSITION_AUTO_TOPLEVEL,
|
|
|
|
std::string());
|
2014-07-02 12:21:47 +04:00
|
|
|
} else {
|
|
|
|
view_->ShowDevTools();
|
2013-03-27 18:33:00 +04:00
|
|
|
}
|
2013-03-14 17:03:50 +04:00
|
|
|
}
|
|
|
|
|
2014-03-20 05:26:21 +04:00
|
|
|
void InspectableWebContentsImpl::CloseDevTools() {
|
2014-07-02 12:21:47 +04:00
|
|
|
if (devtools_web_contents_) {
|
2014-03-20 05:26:21 +04:00
|
|
|
view_->CloseDevTools();
|
|
|
|
devtools_web_contents_.reset();
|
2014-07-27 14:44:58 +04:00
|
|
|
web_contents_->Focus();
|
2014-03-20 05:26:21 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-09 16:34:44 +04:00
|
|
|
bool InspectableWebContentsImpl::IsDevToolsViewShowing() {
|
|
|
|
return devtools_web_contents_ && view_->IsDevToolsViewShowing();
|
2013-11-05 06:29:53 +04:00
|
|
|
}
|
|
|
|
|
2014-07-04 17:34:47 +04:00
|
|
|
gfx::Rect InspectableWebContentsImpl::GetDevToolsBounds() const {
|
|
|
|
return devtools_bounds_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContentsImpl::SaveDevToolsBounds(const gfx::Rect& bounds) {
|
|
|
|
auto context = static_cast<BrowserContext*>(web_contents_->GetBrowserContext());
|
|
|
|
base::DictionaryValue bounds_dict;
|
|
|
|
RectToDictionary(bounds, &bounds_dict);
|
|
|
|
context->prefs()->Set(kDevToolsBoundsPref, bounds_dict);
|
|
|
|
devtools_bounds_ = bounds;
|
|
|
|
}
|
|
|
|
|
2013-03-27 18:33:00 +04:00
|
|
|
void InspectableWebContentsImpl::ActivateWindow() {
|
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContentsImpl::CloseWindow() {
|
2014-07-27 15:18:15 +04:00
|
|
|
devtools_web_contents()->DispatchBeforeUnload(false);
|
2013-03-27 18:33:00 +04:00
|
|
|
}
|
|
|
|
|
2014-07-02 12:21:47 +04:00
|
|
|
void InspectableWebContentsImpl::SetContentsResizingStrategy(
|
|
|
|
const gfx::Insets& insets, const gfx::Size& min_size) {
|
|
|
|
DevToolsContentsResizingStrategy strategy(insets, min_size);
|
|
|
|
if (contents_resizing_strategy_.Equals(strategy))
|
|
|
|
return;
|
|
|
|
|
|
|
|
contents_resizing_strategy_.CopyFrom(strategy);
|
|
|
|
view_->SetContentsResizingStrategy(contents_resizing_strategy_);
|
2013-03-27 18:33:00 +04:00
|
|
|
}
|
|
|
|
|
2014-07-08 11:58:38 +04:00
|
|
|
void InspectableWebContentsImpl::InspectElementCompleted() {
|
|
|
|
}
|
|
|
|
|
2014-07-02 12:21:47 +04:00
|
|
|
void InspectableWebContentsImpl::MoveWindow(int x, int y) {
|
|
|
|
}
|
2013-03-27 19:19:15 +04:00
|
|
|
|
2014-07-02 12:21:47 +04:00
|
|
|
void InspectableWebContentsImpl::SetIsDocked(bool docked) {
|
|
|
|
view_->SetIsDocked(docked);
|
2013-03-27 18:33:00 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContentsImpl::OpenInNewTab(const std::string& url) {
|
|
|
|
}
|
|
|
|
|
2013-11-18 03:08:34 +04:00
|
|
|
void InspectableWebContentsImpl::SaveToFile(
|
|
|
|
const std::string& url, const std::string& content, bool save_as) {
|
2014-04-04 20:10:09 +04:00
|
|
|
if (delegate_)
|
|
|
|
delegate_->DevToolsSaveToFile(url, content, save_as);
|
2013-03-27 18:33:00 +04:00
|
|
|
}
|
|
|
|
|
2013-11-18 03:08:34 +04:00
|
|
|
void InspectableWebContentsImpl::AppendToFile(
|
|
|
|
const std::string& url, const std::string& content) {
|
2014-04-04 20:10:09 +04:00
|
|
|
if (delegate_)
|
|
|
|
delegate_->DevToolsAppendToFile(url, content);
|
2013-03-27 18:33:00 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContentsImpl::RequestFileSystems() {
|
2014-07-09 11:34:10 +04:00
|
|
|
devtools_web_contents()->GetMainFrame()->ExecuteJavaScript(
|
|
|
|
base::ASCIIToUTF16("InspectorFrontendAPI.fileSystemsLoaded([])"));
|
2013-03-27 18:33:00 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContentsImpl::AddFileSystem() {
|
|
|
|
}
|
|
|
|
|
2013-11-18 03:08:34 +04:00
|
|
|
void InspectableWebContentsImpl::RemoveFileSystem(
|
|
|
|
const std::string& file_system_path) {
|
2013-03-27 18:33:00 +04:00
|
|
|
}
|
|
|
|
|
2014-07-08 11:58:38 +04:00
|
|
|
void InspectableWebContentsImpl::UpgradeDraggedFileSystemPermissions(
|
|
|
|
const std::string& file_system_url) {
|
|
|
|
}
|
|
|
|
|
2013-11-18 03:08:34 +04:00
|
|
|
void InspectableWebContentsImpl::IndexPath(
|
|
|
|
int request_id, const std::string& file_system_path) {
|
2013-10-07 23:29:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContentsImpl::StopIndexing(int request_id) {
|
|
|
|
}
|
|
|
|
|
2013-11-18 03:08:34 +04:00
|
|
|
void InspectableWebContentsImpl::SearchInPath(
|
|
|
|
int request_id,
|
|
|
|
const std::string& file_system_path,
|
|
|
|
const std::string& query) {
|
2013-10-07 23:29:17 +04:00
|
|
|
}
|
|
|
|
|
2014-07-08 11:58:38 +04:00
|
|
|
void InspectableWebContentsImpl::ZoomIn() {
|
2014-08-26 11:06:51 +04:00
|
|
|
double level = GetZoomLevelForWebContents(devtools_web_contents());
|
|
|
|
SetZoomLevelForWebContents(devtools_web_contents(), GetNextZoomLevel(level, false));
|
2014-07-08 11:58:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContentsImpl::ZoomOut() {
|
2014-08-26 11:06:51 +04:00
|
|
|
double level = GetZoomLevelForWebContents(devtools_web_contents());
|
|
|
|
SetZoomLevelForWebContents(devtools_web_contents(), GetNextZoomLevel(level, true));
|
2014-07-08 11:58:38 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void InspectableWebContentsImpl::ResetZoom() {
|
2014-08-26 11:06:51 +04:00
|
|
|
SetZoomLevelForWebContents(devtools_web_contents(), 0.);
|
2014-07-08 11:58:38 +04:00
|
|
|
}
|
|
|
|
|
2013-12-02 21:38:24 +04:00
|
|
|
void InspectableWebContentsImpl::DispatchOnEmbedder(
|
|
|
|
const std::string& message) {
|
2014-07-09 11:34:10 +04:00
|
|
|
std::string method;
|
2014-07-11 18:22:23 +04:00
|
|
|
base::ListValue params;
|
|
|
|
int id;
|
|
|
|
if (!ParseMessage(message, &method, ¶ms, &id)) {
|
2014-07-09 11:34:10 +04:00
|
|
|
LOG(ERROR) << "Invalid message was sent to embedder: " << message;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-11 18:22:23 +04:00
|
|
|
std::string error = embedder_message_dispatcher_->Dispatch(method, ¶ms);
|
2014-07-09 11:34:10 +04:00
|
|
|
if (id) {
|
|
|
|
std::string ack = base::StringPrintf(
|
|
|
|
"InspectorFrontendAPI.embedderMessageAck(%d, \"%s\");", id, error.c_str());
|
|
|
|
devtools_web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(ack));
|
|
|
|
}
|
2013-12-02 21:38:24 +04:00
|
|
|
}
|
|
|
|
|
2013-03-27 18:33:00 +04:00
|
|
|
void InspectableWebContentsImpl::InspectedContentsClosing() {
|
|
|
|
}
|
|
|
|
|
2013-11-18 03:08:34 +04:00
|
|
|
void InspectableWebContentsImpl::AboutToNavigateRenderView(
|
|
|
|
content::RenderViewHost* render_view_host) {
|
|
|
|
content::DevToolsClientHost::SetupDevToolsFrontendClient(
|
|
|
|
web_contents()->GetRenderViewHost());
|
2013-03-27 18:33:00 +04:00
|
|
|
}
|
|
|
|
|
2013-11-18 03:08:34 +04:00
|
|
|
void InspectableWebContentsImpl::DidFinishLoad(int64 frame_id,
|
|
|
|
const GURL& validated_url,
|
|
|
|
bool is_main_frame,
|
|
|
|
content::RenderViewHost*) {
|
2013-04-08 21:53:53 +04:00
|
|
|
if (!is_main_frame)
|
|
|
|
return;
|
|
|
|
|
2014-07-02 12:21:47 +04:00
|
|
|
view_->ShowDevTools();
|
2013-04-08 21:53:53 +04:00
|
|
|
}
|
|
|
|
|
2014-07-27 14:27:19 +04:00
|
|
|
void InspectableWebContentsImpl::WebContentsDestroyed() {
|
2013-11-18 03:08:34 +04:00
|
|
|
content::DevToolsManager::GetInstance()->ClientHostClosing(
|
|
|
|
frontend_host_.get());
|
2013-03-27 18:33:00 +04:00
|
|
|
Observe(nullptr);
|
|
|
|
agent_host_ = nullptr;
|
|
|
|
frontend_host_.reset();
|
|
|
|
}
|
|
|
|
|
2014-08-28 08:53:35 +04:00
|
|
|
bool InspectableWebContentsImpl::AddMessageToConsole(
|
|
|
|
content::WebContents* source,
|
|
|
|
int32 level,
|
|
|
|
const base::string16& message,
|
|
|
|
int32 line_no,
|
|
|
|
const base::string16& source_id) {
|
|
|
|
logging::LogMessage("CONSOLE", line_no, level).stream() << "\"" <<
|
|
|
|
message << "\", source: " << source_id << " (" << line_no << ")";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-11-18 03:08:34 +04:00
|
|
|
void InspectableWebContentsImpl::HandleKeyboardEvent(
|
|
|
|
content::WebContents* source,
|
|
|
|
const content::NativeWebKeyboardEvent& event) {
|
2013-03-27 18:33:00 +04:00
|
|
|
auto delegate = web_contents_->GetDelegate();
|
|
|
|
if (delegate)
|
|
|
|
delegate->HandleKeyboardEvent(source, event);
|
|
|
|
}
|
|
|
|
|
2014-07-13 06:08:28 +04:00
|
|
|
void InspectableWebContentsImpl::CloseContents(content::WebContents* source) {
|
|
|
|
CloseDevTools();
|
|
|
|
}
|
|
|
|
|
2013-11-18 03:08:34 +04:00
|
|
|
} // namespace brightray
|