summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrdevlin.cronin@chromium.org <rdevlin.cronin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-01 00:36:01 +0000
committerrdevlin.cronin@chromium.org <rdevlin.cronin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-01 00:36:01 +0000
commitc934c3813489dab3f349210de396198c6f6ae99a (patch)
treeb1b3443012c807ef70347778ba83429094de102a
parent2a82cd4eeda3e5bdfe2cfab495ddd98f71249b6e (diff)
downloadchromium_src-c934c3813489dab3f349210de396198c6f6ae99a.zip
chromium_src-c934c3813489dab3f349210de396198c6f6ae99a.tar.gz
chromium_src-c934c3813489dab3f349210de396198c6f6ae99a.tar.bz2
Add 'Inspect' Links for views in the Extension Error Console
Add the option to inspect a resource or render view in the error console, opening the developer tools for that resource/view. Goes with: https://codereview.chromium.org/23816005 BUG=21734 TBR=yoshiki@chromium.org (task_manager) TBR=ben@chromium.org (ui [refactor only]) Review URL: https://codereview.chromium.org/23459008 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@232246 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/generated_resources.grd3
-rw-r--r--chrome/browser/devtools/devtools_sanity_browsertest.cc4
-rw-r--r--chrome/browser/devtools/devtools_toggle_action.cc64
-rw-r--r--chrome/browser/devtools/devtools_toggle_action.h54
-rw-r--r--chrome/browser/devtools/devtools_window.cc97
-rw-r--r--chrome/browser/devtools/devtools_window.h13
-rw-r--r--chrome/browser/extensions/api/app_window/app_window_api.cc2
-rw-r--r--chrome/browser/extensions/error_console/error_console_unittest.cc3
-rw-r--r--chrome/browser/extensions/extension_host.cc4
-rw-r--r--chrome/browser/extensions/tab_helper.cc5
-rw-r--r--chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc12
-rw-r--r--chrome/browser/resources/extensions/extension_error.css29
-rw-r--r--chrome/browser/resources/extensions/extension_error.js134
-rw-r--r--chrome/browser/resources/extensions/extensions.html2
-rw-r--r--chrome/browser/task_manager/task_manager_browsertest.cc4
-rw-r--r--chrome/browser/ui/browser_command_controller.cc8
-rw-r--r--chrome/browser/ui/browser_commands.cc2
-rw-r--r--chrome/browser/ui/cocoa/dev_tools_controller_browsertest.mm2
-rw-r--r--chrome/browser/ui/cocoa/view_id_util_browsertest.mm2
-rw-r--r--chrome/browser/ui/panels/panel.cc4
-rw-r--r--chrome/browser/ui/views/extensions/extension_popup.cc2
-rw-r--r--chrome/browser/ui/views/external_tab_container_win.cc8
-rw-r--r--chrome/browser/ui/webui/extensions/extension_error_handler.cc74
-rw-r--r--chrome/browser/ui/webui/extensions/extension_error_handler.h2
-rw-r--r--chrome/browser/ui/webui/extensions/extension_settings_handler.cc33
-rw-r--r--chrome/browser/ui/webui/extensions/extension_settings_handler.h3
-rw-r--r--chrome/chrome.gyp1
-rw-r--r--extensions/browser/extension_error.cc14
-rw-r--r--extensions/browser/extension_error.h13
29 files changed, 484 insertions, 114 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 615406a..3b211ec 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -4765,6 +4765,9 @@ Make sure you do not expose any sensitive information.
<message name="IDS_EXTENSIONS_ERROR_VIEW_SOURCE" desc="The link to view the source code for a file relating to an extension error.">
View source
</message>
+ <message name="IDS_EXTENSIONS_ERROR_INSPECT" desc="The link to open the inspector (developer tools) for the location of a particular error.">
+ Inspect
+ </message>
<message name="IDS_EXTENSIONS_ERROR_CONTEXT" desc="The label for the context of an extension's error.">
Context:
</message>
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index d426741..e25d5b7 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -137,7 +137,7 @@ class DevToolsSanityTest : public InProcessBrowserTest {
content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
content::Source<content::WebContents>(window_->web_contents()));
DevToolsWindow::ToggleDevToolsWindow(inspected_rvh_, false,
- DEVTOOLS_TOGGLE_ACTION_TOGGLE);
+ DevToolsToggleAction::Toggle());
close_observer.Wait();
}
@@ -403,7 +403,7 @@ class WorkerDevToolsSanityTest : public InProcessBrowserTest {
void OpenDevToolsWindowForSharedWorker(WorkerData* worker_data) {
Profile* profile = browser()->profile();
window_ = DevToolsWindow::CreateDevToolsWindowForWorker(profile);
- window_->Show(DEVTOOLS_TOGGLE_ACTION_SHOW);
+ window_->Show(DevToolsToggleAction::Show());
scoped_refptr<DevToolsAgentHost> agent_host(
DevToolsAgentHost::GetForWorker(
worker_data->worker_process_id,
diff --git a/chrome/browser/devtools/devtools_toggle_action.cc b/chrome/browser/devtools/devtools_toggle_action.cc
new file mode 100644
index 0000000..779d5bc
--- /dev/null
+++ b/chrome/browser/devtools/devtools_toggle_action.cc
@@ -0,0 +1,64 @@
+// Copyright 2013 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 "chrome/browser/devtools/devtools_toggle_action.h"
+
+DevToolsToggleAction::RevealParams::RevealParams(const base::string16& url,
+ size_t line_number,
+ size_t column_number)
+ : url(url), line_number(line_number), column_number(column_number) {
+}
+
+DevToolsToggleAction::RevealParams::~RevealParams() {
+}
+
+DevToolsToggleAction::DevToolsToggleAction(Type type) : type_(type) {
+}
+
+DevToolsToggleAction::DevToolsToggleAction(RevealParams* params)
+ : type_(kReveal), params_(params) {
+}
+
+DevToolsToggleAction::DevToolsToggleAction(const DevToolsToggleAction& rhs)
+ : type_(rhs.type_),
+ params_(rhs.params_.get() ? new RevealParams(*rhs.params_) : NULL) {
+}
+
+void DevToolsToggleAction::operator=(const DevToolsToggleAction& rhs) {
+ type_ = rhs.type_;
+ if (rhs.params_.get())
+ params_.reset(new RevealParams(*rhs.params_));
+}
+
+DevToolsToggleAction::~DevToolsToggleAction() {
+}
+
+// static
+DevToolsToggleAction DevToolsToggleAction::Show() {
+ return DevToolsToggleAction(kShow);
+}
+
+// static
+DevToolsToggleAction DevToolsToggleAction::ShowConsole() {
+ return DevToolsToggleAction(kShowConsole);
+}
+
+// static
+DevToolsToggleAction DevToolsToggleAction::Inspect() {
+ return DevToolsToggleAction(kInspect);
+}
+
+// static
+DevToolsToggleAction DevToolsToggleAction::Toggle() {
+ return DevToolsToggleAction(kToggle);
+}
+
+// static
+DevToolsToggleAction DevToolsToggleAction::Reveal(
+ const base::string16& url,
+ size_t line_number,
+ size_t column_number) {
+ return DevToolsToggleAction(
+ new RevealParams(url, line_number, column_number));
+}
diff --git a/chrome/browser/devtools/devtools_toggle_action.h b/chrome/browser/devtools/devtools_toggle_action.h
index ff5c94c..0fd5d36 100644
--- a/chrome/browser/devtools/devtools_toggle_action.h
+++ b/chrome/browser/devtools/devtools_toggle_action.h
@@ -5,11 +5,55 @@
#ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_TOGGLE_ACTION_H_
#define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_TOGGLE_ACTION_H_
-enum DevToolsToggleAction {
- DEVTOOLS_TOGGLE_ACTION_SHOW,
- DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE,
- DEVTOOLS_TOGGLE_ACTION_INSPECT,
- DEVTOOLS_TOGGLE_ACTION_TOGGLE
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+
+struct DevToolsToggleAction {
+ public:
+ enum Type {
+ kShow,
+ kShowConsole,
+ kInspect,
+ kToggle,
+ kReveal
+ };
+
+ struct RevealParams {
+ RevealParams(const base::string16& url,
+ size_t line_number,
+ size_t column_number);
+ ~RevealParams();
+
+ base::string16 url;
+ size_t line_number;
+ size_t column_number;
+ };
+
+ void operator=(const DevToolsToggleAction& rhs);
+ DevToolsToggleAction(const DevToolsToggleAction& rhs);
+ ~DevToolsToggleAction();
+
+ static DevToolsToggleAction Show();
+ static DevToolsToggleAction ShowConsole();
+ static DevToolsToggleAction Inspect();
+ static DevToolsToggleAction Toggle();
+ static DevToolsToggleAction Reveal(const base::string16& url,
+ size_t line_number,
+ size_t column_number);
+
+ Type type() const { return type_; }
+ const RevealParams* params() const { return params_.get(); }
+
+ private:
+ explicit DevToolsToggleAction(Type type);
+ explicit DevToolsToggleAction(RevealParams* reveal_params);
+
+ // The type of action.
+ Type type_;
+
+ // Additional parameters for the Reveal action; NULL if of any other type.
+ scoped_ptr<RevealParams> params_;
};
#endif // CHROME_BROWSER_DEVTOOLS_DEVTOOLS_TOGGLE_ACTION_H_
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index e5af37e..0b757d9 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -11,6 +11,7 @@
#include "base/lazy_instance.h"
#include "base/prefs/scoped_user_pref_update.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
@@ -64,6 +65,8 @@
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"
+using base::DictionaryValue;
+using content::BrowserThread;
using content::DevToolsAgentHost;
@@ -289,7 +292,7 @@ void DevToolsWindow::RegisterProfilePrefs(
prefs::kDevToolsFileSystemPaths,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
registry->RegisterStringPref(
- prefs::kDevToolsAdbKey, std::string(),
+ prefs::kDevToolsAdbKey, EmptyString(),
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
registry->RegisterDictionaryPref(
@@ -316,13 +319,20 @@ void DevToolsWindow::RegisterProfilePrefs(
// static
DevToolsWindow* DevToolsWindow::GetDockedInstanceForInspectedTab(
content::WebContents* inspected_web_contents) {
- if (!inspected_web_contents ||
- !DevToolsAgentHost::HasFor(inspected_web_contents->GetRenderViewHost()))
+ DevToolsWindow* window = GetInstanceForInspectedRenderViewHost(
+ inspected_web_contents->GetRenderViewHost());
+ return (window && window->IsDocked()) ? window : NULL;
+}
+
+// static
+DevToolsWindow* DevToolsWindow::GetInstanceForInspectedRenderViewHost(
+ content::RenderViewHost* inspected_rvh) {
+ if (!inspected_rvh || !DevToolsAgentHost::HasFor(inspected_rvh))
return NULL;
+
scoped_refptr<DevToolsAgentHost> agent(DevToolsAgentHost::GetOrCreateFor(
- inspected_web_contents->GetRenderViewHost()));
- DevToolsWindow* window = FindDevToolsWindow(agent.get());
- return (window && window->IsDocked()) ? window : NULL;
+ inspected_rvh));
+ return FindDevToolsWindow(agent.get());
}
// static
@@ -341,7 +351,7 @@ DevToolsWindow* DevToolsWindow::OpenDevToolsWindowForWorker(
content::DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(
worker_agent, window->frontend_host_.get());
}
- window->Show(DEVTOOLS_TOGGLE_ACTION_SHOW);
+ window->Show(DevToolsToggleAction::Show());
return window;
}
@@ -355,22 +365,23 @@ DevToolsWindow* DevToolsWindow::CreateDevToolsWindowForWorker(
// static
DevToolsWindow* DevToolsWindow::OpenDevToolsWindow(
content::RenderViewHost* inspected_rvh) {
- return ToggleDevToolsWindow(inspected_rvh, true,
- DEVTOOLS_TOGGLE_ACTION_SHOW);
+ return ToggleDevToolsWindow(
+ inspected_rvh, true, DevToolsToggleAction::Show());
}
// static
DevToolsWindow* DevToolsWindow::ToggleDevToolsWindow(
Browser* browser,
- DevToolsToggleAction action) {
- if (action == DEVTOOLS_TOGGLE_ACTION_TOGGLE && browser->is_devtools()) {
+ const DevToolsToggleAction& action) {
+ if (action.type() == DevToolsToggleAction::kToggle &&
+ browser->is_devtools()) {
browser->tab_strip_model()->CloseAllTabs();
return NULL;
}
return ToggleDevToolsWindow(
browser->tab_strip_model()->GetActiveWebContents()->GetRenderViewHost(),
- action == DEVTOOLS_TOGGLE_ACTION_INSPECT, action);
+ action.type() == DevToolsToggleAction::kInspect, action);
}
// static
@@ -385,14 +396,14 @@ void DevToolsWindow::OpenExternalFrontend(
content::DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor(
agent_host, window->frontend_host_.get());
}
- window->Show(DEVTOOLS_TOGGLE_ACTION_SHOW);
+ window->Show(DevToolsToggleAction::Show());
}
// static
DevToolsWindow* DevToolsWindow::ToggleDevToolsWindow(
content::RenderViewHost* inspected_rvh,
bool force_open,
- DevToolsToggleAction action) {
+ const DevToolsToggleAction& action) {
scoped_refptr<DevToolsAgentHost> agent(
DevToolsAgentHost::GetOrCreateFor(inspected_rvh));
content::DevToolsManager* manager = content::DevToolsManager::GetInstance();
@@ -514,7 +525,7 @@ void DevToolsWindow::SetHeight(int height) {
profile_->GetPrefs()->SetInteger(prefs::kDevToolsHSplitLocation, height);
}
-void DevToolsWindow::Show(DevToolsToggleAction action) {
+void DevToolsWindow::Show(const DevToolsToggleAction& action) {
if (IsDocked()) {
Browser* inspected_browser = NULL;
int inspected_tab_index = -1;
@@ -542,7 +553,7 @@ void DevToolsWindow::Show(DevToolsToggleAction action) {
// Avoid consecutive window switching if the devtools window has been opened
// and the Inspect Element shortcut is pressed in the inspected tab.
bool should_show_window =
- !browser_ || (action != DEVTOOLS_TOGGLE_ACTION_INSPECT);
+ !browser_ || (action.type() != DevToolsToggleAction::kInspect);
if (!browser_)
CreateDevToolsBrowser();
@@ -563,7 +574,7 @@ DevToolsWindow::DevToolsWindow(Profile* profile,
browser_(NULL),
dock_side_(dock_side),
is_loaded_(false),
- action_on_load_(DEVTOOLS_TOGGLE_ACTION_SHOW),
+ action_on_load_(DevToolsToggleAction::Show()),
width_(-1),
height_(-1),
dock_side_before_minimized_(dock_side),
@@ -573,7 +584,7 @@ DevToolsWindow::DevToolsWindow(Profile* profile,
frontend_contents_observer_.reset(new FrontendWebContentsObserver(this));
web_contents_->GetController().LoadURL(url, content::Referrer(),
- content::PAGE_TRANSITION_AUTO_TOPLEVEL, std::string());
+ content::PAGE_TRANSITION_AUTO_TOPLEVEL, EmptyString());
frontend_host_.reset(content::DevToolsClientHost::CreateDevToolsFrontendHost(
web_contents_, this));
@@ -977,7 +988,7 @@ void DevToolsWindow::SetDockSide(const std::string& side) {
profile_->GetPrefs()->SetString(prefs::kDevToolsDockSide, pref_value);
}
- Show(DEVTOOLS_TOGGLE_ACTION_SHOW);
+ Show(DevToolsToggleAction::Show());
}
void DevToolsWindow::OpenInNewTab(const std::string& url) {
@@ -1049,7 +1060,7 @@ void DevToolsWindow::RemoveFileSystem(const std::string& file_system_path) {
void DevToolsWindow::IndexPath(int request_id,
const std::string& file_system_path) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
CHECK(web_contents_->GetURL().SchemeIs(chrome::kChromeDevToolsScheme));
if (!file_helper_->IsFileSystemAdded(file_system_path)) {
IndexingDone(request_id, file_system_path);
@@ -1074,7 +1085,7 @@ void DevToolsWindow::IndexPath(int request_id,
}
void DevToolsWindow::StopIndexing(int request_id) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
IndexingJobsMap::iterator it = indexing_jobs_.find(request_id);
if (it == indexing_jobs_.end())
return;
@@ -1085,7 +1096,7 @@ void DevToolsWindow::StopIndexing(int request_id) {
void DevToolsWindow::SearchInPath(int request_id,
const std::string& file_system_path,
const std::string& query) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
CHECK(web_contents_->GetURL().SchemeIs(chrome::kChromeDevToolsScheme));
if (!file_helper_->IsFileSystemAdded(file_system_path)) {
SearchCompleted(request_id, file_system_path, std::vector<std::string>());
@@ -1121,7 +1132,7 @@ void DevToolsWindow::FileSystemsLoaded(
void DevToolsWindow::FileSystemAdded(
const DevToolsFileHelper::FileSystem& file_system) {
- StringValue error_string_value((std::string()));
+ StringValue error_string_value(EmptyString());
DictionaryValue* file_system_value = NULL;
if (!file_system.file_system_path.empty())
file_system_value = CreateFileSystemValue(file_system);
@@ -1135,7 +1146,7 @@ void DevToolsWindow::IndexingTotalWorkCalculated(
int request_id,
const std::string& file_system_path,
int total_work) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
base::FundamentalValue request_id_value(request_id);
StringValue file_system_path_value(file_system_path);
base::FundamentalValue total_work_value(total_work);
@@ -1147,7 +1158,7 @@ void DevToolsWindow::IndexingTotalWorkCalculated(
void DevToolsWindow::IndexingWorked(int request_id,
const std::string& file_system_path,
int worked) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
base::FundamentalValue request_id_value(request_id);
StringValue file_system_path_value(file_system_path);
base::FundamentalValue worked_value(worked);
@@ -1158,7 +1169,7 @@ void DevToolsWindow::IndexingWorked(int request_id,
void DevToolsWindow::IndexingDone(int request_id,
const std::string& file_system_path) {
indexing_jobs_.erase(request_id);
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
base::FundamentalValue request_id_value(request_id);
StringValue file_system_path_value(file_system_path);
CallClientFunction("InspectorFrontendAPI.indexingDone", &request_id_value,
@@ -1169,7 +1180,7 @@ void DevToolsWindow::SearchCompleted(
int request_id,
const std::string& file_system_path,
const std::vector<std::string>& file_paths) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
ListValue file_paths_value;
for (std::vector<std::string>::const_iterator it(file_paths.begin());
it != file_paths.end(); ++it) {
@@ -1257,7 +1268,7 @@ void DevToolsWindow::UpdateFrontendDockSide() {
NULL);
}
-void DevToolsWindow::ScheduleAction(DevToolsToggleAction action) {
+void DevToolsWindow::ScheduleAction(const DevToolsToggleAction& action) {
action_on_load_ = action;
if (is_loaded_)
DoAction();
@@ -1265,26 +1276,40 @@ void DevToolsWindow::ScheduleAction(DevToolsToggleAction action) {
void DevToolsWindow::DoAction() {
UpdateFrontendDockSide();
- switch (action_on_load_) {
- case DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE:
+ switch (action_on_load_.type()) {
+ case DevToolsToggleAction::kShowConsole:
CallClientFunction("InspectorFrontendAPI.showConsole", NULL, NULL, NULL);
break;
- case DEVTOOLS_TOGGLE_ACTION_INSPECT:
+ case DevToolsToggleAction::kInspect:
CallClientFunction("InspectorFrontendAPI.enterInspectElementMode", NULL,
NULL, NULL);
break;
- case DEVTOOLS_TOGGLE_ACTION_SHOW:
- case DEVTOOLS_TOGGLE_ACTION_TOGGLE:
+ case DevToolsToggleAction::kShow:
+ case DevToolsToggleAction::kToggle:
// Do nothing.
break;
+ case DevToolsToggleAction::kReveal: {
+ const DevToolsToggleAction::RevealParams* params =
+ action_on_load_.params();
+ CHECK(params);
+ base::StringValue url_value(params->url);
+ base::FundamentalValue line_value(static_cast<int>(params->line_number));
+ base::FundamentalValue column_value(
+ static_cast<int>(params->column_number));
+ CallClientFunction("InspectorFrontendAPI.revealSourceLine",
+ &url_value,
+ &line_value,
+ &column_value);
+ break;
+ }
default:
NOTREACHED();
break;
}
- action_on_load_ = DEVTOOLS_TOGGLE_ACTION_SHOW;
+ action_on_load_ = DevToolsToggleAction::Show();
}
void DevToolsWindow::UpdateTheme() {
@@ -1297,7 +1322,7 @@ void DevToolsWindow::UpdateTheme() {
SkColorToRGBAString(tp->GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT)) +
"\")");
web_contents_->GetRenderViewHost()->ExecuteJavascriptInWebFrame(
- string16(), ASCIIToUTF16(command));
+ EmptyString16(), ASCIIToUTF16(command));
}
void DevToolsWindow::AddDevToolsExtensionsToClient() {
@@ -1359,7 +1384,7 @@ void DevToolsWindow::CallClientFunction(const std::string& function_name,
}
string16 javascript = ASCIIToUTF16(function_name + "(" + params + ");");
web_contents_->GetRenderViewHost()->
- ExecuteJavascriptInWebFrame(string16(), javascript);
+ ExecuteJavascriptInWebFrame(EmptyString16(), javascript);
}
void DevToolsWindow::UpdateBrowserToolbar() {
diff --git a/chrome/browser/devtools/devtools_window.h b/chrome/browser/devtools/devtools_window.h
index fcdaadb..0f1bdd6 100644
--- a/chrome/browser/devtools/devtools_window.h
+++ b/chrome/browser/devtools/devtools_window.h
@@ -67,6 +67,10 @@ class DevToolsWindow : private content::NotificationObserver,
static std::string GetDevToolsWindowPlacementPrefKey();
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+ // Return the DevToolsWindow for the given RenderViewHost if one exists,
+ // otherwise NULL.
+ static DevToolsWindow* GetInstanceForInspectedRenderViewHost(
+ content::RenderViewHost* inspected_rvh);
static DevToolsWindow* GetDockedInstanceForInspectedTab(
content::WebContents* inspected_tab);
static bool IsDevToolsWindow(content::RenderViewHost* window_rvh);
@@ -78,7 +82,7 @@ class DevToolsWindow : private content::NotificationObserver,
content::RenderViewHost* inspected_rvh);
static DevToolsWindow* ToggleDevToolsWindow(
Browser* browser,
- DevToolsToggleAction action);
+ const DevToolsToggleAction& action);
static void OpenExternalFrontend(Profile* profile,
const std::string& frontend_uri,
content::DevToolsAgentHost* agent_host);
@@ -87,7 +91,8 @@ class DevToolsWindow : private content::NotificationObserver,
static DevToolsWindow* ToggleDevToolsWindow(
content::RenderViewHost* inspected_rvh,
bool force_open,
- DevToolsToggleAction action);
+ const DevToolsToggleAction& action);
+
static void InspectElement(
content::RenderViewHost* inspected_rvh, int x, int y);
@@ -123,7 +128,7 @@ class DevToolsWindow : private content::NotificationObserver,
// Stores preferred devtools window height for this instance.
void SetHeight(int height);
- void Show(DevToolsToggleAction action);
+ void Show(const DevToolsToggleAction& action);
private:
friend class DevToolsControllerTest;
@@ -236,7 +241,7 @@ class DevToolsWindow : private content::NotificationObserver,
BrowserWindow* GetInspectedBrowserWindow();
bool IsInspectedBrowserPopup();
void UpdateFrontendDockSide();
- void ScheduleAction(DevToolsToggleAction action);
+ void ScheduleAction(const DevToolsToggleAction& action);
void DoAction();
void UpdateTheme();
void AddDevToolsExtensionsToClient();
diff --git a/chrome/browser/extensions/api/app_window/app_window_api.cc b/chrome/browser/extensions/api/app_window/app_window_api.cc
index b31b776..0eaaaf5 100644
--- a/chrome/browser/extensions/api/app_window/app_window_api.cc
+++ b/chrome/browser/extensions/api/app_window/app_window_api.cc
@@ -66,7 +66,7 @@ class DevToolsRestorer : public content::NotificationObserver {
DevToolsWindow::ToggleDevToolsWindow(
created_view,
true /* force_open */,
- DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE);
+ DevToolsToggleAction::ShowConsole());
registrar_.Add(
this,
diff --git a/chrome/browser/extensions/error_console/error_console_unittest.cc b/chrome/browser/extensions/error_console/error_console_unittest.cc
index e36c93a..fb78528 100644
--- a/chrome/browser/extensions/error_console/error_console_unittest.cc
+++ b/chrome/browser/extensions/error_console/error_console_unittest.cc
@@ -57,7 +57,8 @@ scoped_ptr<ExtensionError> CreateNewRuntimeError(
message,
GetDefaultStackTrace(),
GURL::EmptyGURL(), // no context url
- logging::LOG_INFO));
+ logging::LOG_INFO,
+ 0, 0 /* Render [View|Process] ID */ ));
}
} // namespace
diff --git a/chrome/browser/extensions/extension_host.cc b/chrome/browser/extensions/extension_host.cc
index e8da09d..19f075d 100644
--- a/chrome/browser/extensions/extension_host.cc
+++ b/chrome/browser/extensions/extension_host.cc
@@ -606,7 +606,9 @@ void ExtensionHost::OnDetailedConsoleMessageAdded(
message,
stack_trace,
context_url,
- static_cast<logging::LogSeverity>(severity_level))));
+ static_cast<logging::LogSeverity>(severity_level),
+ render_view_host_->GetRoutingID(),
+ render_view_host_->GetProcess()->GetID())));
}
}
diff --git a/chrome/browser/extensions/tab_helper.cc b/chrome/browser/extensions/tab_helper.cc
index 63ce4be..b8ede76 100644
--- a/chrome/browser/extensions/tab_helper.cc
+++ b/chrome/browser/extensions/tab_helper.cc
@@ -363,6 +363,7 @@ void TabHelper::OnDetailedConsoleMessageAdded(
const StackTrace& stack_trace,
int32 severity_level) {
if (IsSourceFromAnExtension(source)) {
+ content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
ErrorConsole::Get(profile_)->ReportError(
scoped_ptr<ExtensionError>(new RuntimeError(
extension_app_ ? extension_app_->id() : EmptyString(),
@@ -372,7 +373,9 @@ void TabHelper::OnDetailedConsoleMessageAdded(
stack_trace,
web_contents() ?
web_contents()->GetLastCommittedURL() : GURL::EmptyGURL(),
- static_cast<logging::LogSeverity>(severity_level))));
+ static_cast<logging::LogSeverity>(severity_level),
+ rvh->GetRoutingID(),
+ rvh->GetProcess()->GetID())));
}
}
diff --git a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
index f574710..a17ec42 100644
--- a/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
+++ b/chrome/browser/renderer_host/render_process_host_chrome_browsertest.cc
@@ -315,7 +315,7 @@ IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
EXPECT_EQ(host_count, RenderProcessHostCount());
// DevTools start in docked mode (no new tab), in a separate process.
- chrome::ToggleDevToolsWindow(browser(), DEVTOOLS_TOGGLE_ACTION_INSPECT);
+ chrome::ToggleDevToolsWindow(browser(), DevToolsToggleAction::Inspect());
host_count++;
EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
EXPECT_EQ(host_count, RenderProcessHostCount());
@@ -325,7 +325,7 @@ IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
// DevTools start in a separate process.
DevToolsWindow::ToggleDevToolsWindow(
- devtools, true, DEVTOOLS_TOGGLE_ACTION_INSPECT);
+ devtools, true, DevToolsToggleAction::Inspect());
host_count++;
EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
EXPECT_EQ(host_count, RenderProcessHostCount());
@@ -335,7 +335,7 @@ IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
content::Source<WebContents>(WebContents::FromRenderViewHost(devtools)));
- chrome::ToggleDevToolsWindow(browser(), DEVTOOLS_TOGGLE_ACTION_TOGGLE);
+ chrome::ToggleDevToolsWindow(browser(), DevToolsToggleAction::Toggle());
close_observer.Wait();
}
@@ -363,7 +363,7 @@ IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
EXPECT_EQ(host_count, RenderProcessHostCount());
// DevTools start in docked mode (no new tab), in a separate process.
- chrome::ToggleDevToolsWindow(browser(), DEVTOOLS_TOGGLE_ACTION_INSPECT);
+ chrome::ToggleDevToolsWindow(browser(), DevToolsToggleAction::Inspect());
host_count++;
EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
EXPECT_EQ(host_count, RenderProcessHostCount());
@@ -373,7 +373,7 @@ IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
// DevTools start in a separate process.
DevToolsWindow::ToggleDevToolsWindow(
- devtools, true, DEVTOOLS_TOGGLE_ACTION_INSPECT);
+ devtools, true, DevToolsToggleAction::Inspect());
host_count++;
EXPECT_EQ(tab_count, browser()->tab_strip_model()->count());
EXPECT_EQ(host_count, RenderProcessHostCount());
@@ -383,7 +383,7 @@ IN_PROC_BROWSER_TEST_F(ChromeRenderProcessHostTest,
content::NOTIFICATION_WEB_CONTENTS_DESTROYED,
content::Source<content::WebContents>(
WebContents::FromRenderViewHost(devtools)));
- chrome::ToggleDevToolsWindow(browser(), DEVTOOLS_TOGGLE_ACTION_TOGGLE);
+ chrome::ToggleDevToolsWindow(browser(), DevToolsToggleAction::Toggle());
close_observer.Wait();
}
diff --git a/chrome/browser/resources/extensions/extension_error.css b/chrome/browser/resources/extensions/extension_error.css
index 6cdd717..4bb50c7 100644
--- a/chrome/browser/resources/extensions/extension_error.css
+++ b/chrome/browser/resources/extensions/extension_error.css
@@ -71,10 +71,31 @@
}
.extension-error-view-source {
- -webkit-margin-start: 0 !important;
+ display: inline-block;
+}
+
+a.extension-error-view-source {
+ -webkit-margin-start: 0; /* Needed to override rule 'extension-list-item' */
+}
+
+.extension-error-links {
+ display: inline-block;
float: right;
}
+.extension-error-inspect {
+ content: url('extension_error_inspect.png');
+ width: 10px;
+}
+
+.extension-error-links .extension-error-inspect {
+ -webkit-margin-end: 10px;
+}
+
+.extension-error-links > .extension-error-view-source:first-child {
+ -webkit-margin-start: 20px;
+}
+
.extension-error-details {
-webkit-margin-start: 30px;
}
@@ -83,6 +104,10 @@
-webkit-padding-start: 20px;
}
-.extension-error-stack-trace-list .extension-error-view-source {
+.extension-error-context-wrapper .extension-error-inspect {
+ -webkit-margin-start: 10px;
+}
+
+.extension-error-stack-trace-list .extension-error-links {
float: none;
}
diff --git a/chrome/browser/resources/extensions/extension_error.js b/chrome/browser/resources/extensions/extension_error.js
index 774c9bb..0b2efef4 100644
--- a/chrome/browser/resources/extensions/extension_error.js
+++ b/chrome/browser/resources/extensions/extension_error.js
@@ -63,11 +63,11 @@ cr.define('extensions', function() {
// Add an additional class for the severity level.
if (this.error_.level == 0)
- metadata.className += ' extension-error-severity-info';
+ metadata.classList.add('extension-error-severity-info');
else if (this.error_.level == 1)
- metadata.className += ' extension-error-severity-warning';
+ metadata.classList.add('extension-error-severity-warning');
else
- metadata.className += ' extension-error-severity-fatal';
+ metadata.classList.add('extension-error-severity-fatal');
var iconNode = document.createElement('img');
iconNode.className = 'extension-error-icon';
@@ -81,7 +81,7 @@ cr.define('extensions', function() {
metadata.querySelector('.extension-error-message').textContent =
this.error_.message;
- metadata.appendChild(this.getViewSourceOrPlain_(
+ metadata.appendChild(this.createViewSourceAndInspect_(
getRelativeUrl(this.error_.source, this.extensionUrl_),
this.error_.source));
@@ -92,29 +92,41 @@ cr.define('extensions', function() {
var detailsNode = this.querySelector('.extension-error-details');
if (detailsNode && this.error_.contextUrl)
- detailsNode.appendChild(this.getContextNode_());
- if (detailsNode && this.error_.stackTrace)
- detailsNode.appendChild(this.getStackNode_());
+ detailsNode.appendChild(this.createContextNode_());
+ if (detailsNode && this.error_.stackTrace) {
+ var stackNode = this.createStackNode_();
+ if (stackNode)
+ detailsNode.appendChild(this.createStackNode_());
+ }
},
/**
* Return a div with text |description|. If it's possible to view the source
- * for |url|, linkify the div to do so.
+ * for |url|, linkify the div to do so. Attach an inspect button if it's
+ * possible to open the inspector for |url|.
* @param {string} description a human-friendly description the location
* (e.g., filename, line).
* @param {string} url The url of the resource to view.
* @param {?number} line An optional line number of the resource.
+ * @param {?number} column An optional column number of the resource.
* @return {HTMLElement} The created node, either a link or plaintext.
* @private
*/
- getViewSourceOrPlain_: function(description, url, line) {
+ createViewSourceAndInspect_: function(description, url, line, column) {
+ var errorLinks = document.createElement('div');
+ errorLinks.className = 'extension-error-links';
+
+ if (this.error_.canInspect)
+ errorLinks.appendChild(this.createInspectLink_(url, line, column));
+
if (this.canViewSource_(url))
- var node = this.getViewSourceLink_(url, line);
+ var viewSource = this.createViewSourceLink_(url, line);
else
- var node = document.createElement('div');
- node.className = 'extension-error-view-source';
- node.textContent = description;
- return node;
+ var viewSource = document.createElement('div');
+ viewSource.className = 'extension-error-view-source';
+ viewSource.textContent = description;
+ errorLinks.appendChild(viewSource);
+ return errorLinks;
},
/**
@@ -128,6 +140,19 @@ cr.define('extensions', function() {
},
/**
+ * Determine whether or not we should display the url to the user. We don't
+ * want to include any of our own code in stack traces.
+ * @param {string} url The url in question.
+ * @return {boolean} True if the url should be displayed, and false
+ * otherwise (i.e., if it is an internal script).
+ */
+ shouldDisplayForUrl_: function(url) {
+ var extensionsNamespace = 'extensions::';
+ // All our internal scripts are in the 'extensions::' namespace.
+ return url.substr(0, extensionsNamespace.length) != extensionsNamespace;
+ },
+
+ /**
* Create a clickable node to view the source for the given url.
* @param {string} url The url to the resource to view.
* @param {?number} line An optional line number of the resource (for
@@ -135,8 +160,9 @@ cr.define('extensions', function() {
* @return {HTMLElement} The clickable node to view the source.
* @private
*/
- getViewSourceLink_: function(url, line) {
- var node = document.createElement('a');
+ createViewSourceLink_: function(url, line) {
+ var viewSource = document.createElement('a');
+ viewSource.href = 'javascript:void(0)';
var relativeUrl = getRelativeUrl(url, this.extensionUrl_);
var requestFileSourceArgs = { 'extensionId': this.error_.extensionId,
'message': this.error_.message,
@@ -147,19 +173,57 @@ cr.define('extensions', function() {
} else {
// Prefer |line| if available, or default to the line of the last stack
// frame.
- if (line) {
- requestFileSourceArgs.lineNumber = line;
- } else if (this.error_.stackTrace) {
- requestFileSourceArgs.lineNumber =
- this.error_.stackTrace[0].lineNumber;
- }
+ requestFileSourceArgs.lineNumber =
+ line ? line : this.getLastPosition_('lineNumber');
}
- node.addEventListener('click', function(e) {
+ viewSource.addEventListener('click', function(e) {
chrome.send('extensionErrorRequestFileSource', [requestFileSourceArgs]);
});
- node.title = loadTimeData.getString('extensionErrorViewSource');
- return node;
+ viewSource.title = loadTimeData.getString('extensionErrorViewSource');
+ return viewSource;
+ },
+
+ /**
+ * Check the most recent stack frame to get the last position in the code.
+ * @param {string} type The position type, i.e. '[line|column]Number'.
+ * @return {?number} The last position of the given |type|, or undefined if
+ * there is no stack trace to check.
+ * @private
+ */
+ getLastPosition_: function(type) {
+ var stackTrace = this.error_.stackTrace;
+ return stackTrace && stackTrace[0] ? stackTrace[0][type] : undefined;
+ },
+
+ /**
+ * Create an "Inspect" link, in the form of an icon.
+ * @param {?string} url The url of the resource to inspect; if absent, the
+ * render view (and no particular resource) is inspected.
+ * @param {?number} line An optional line number of the resource.
+ * @param {?number} column An optional column number of the resource.
+ * @return {HTMLImageElement} The created "Inspect" link for the resource.
+ * @private
+ */
+ createInspectLink_: function(url, line, column) {
+ var linkWrapper = document.createElement('a');
+ linkWrapper.href = 'javascript:void(0)';
+ var inspectIcon = document.createElement('img');
+ inspectIcon.className = 'extension-error-inspect';
+ inspectIcon.title = loadTimeData.getString('extensionErrorInspect');
+
+ inspectIcon.addEventListener('click', function(e) {
+ chrome.send('extensionErrorOpenDevTools',
+ [{'renderProcessId': this.error_.renderProcessId,
+ 'renderViewId': this.error_.renderViewId,
+ 'url': url,
+ 'lineNumber': line ? line :
+ this.getLastPosition_('lineNumber'),
+ 'columnNumber': column ? column :
+ this.getLastPosition_('columnNumber')}]);
+ }.bind(this));
+ linkWrapper.appendChild(inspectIcon);
+ return linkWrapper;
},
/**
@@ -170,7 +234,7 @@ cr.define('extensions', function() {
* label and a link to the context.
* @private
*/
- getContextNode_: function() {
+ createContextNode_: function() {
var node = cloneTemplate('extension-error-context-wrapper');
var linkNode = node.querySelector('a');
if (isExtensionUrl(this.error_.contextUrl, this.extensionUrl_)) {
@@ -179,6 +243,11 @@ cr.define('extensions', function() {
} else {
linkNode.textContent = this.error_.contextUrl;
}
+
+ // Prepend a link to inspect the context page, if possible.
+ if (this.error_.canInspect)
+ node.insertBefore(this.createInspectLink_(), linkNode);
+
linkNode.href = this.error_.contextUrl;
linkNode.target = '_blank';
return node;
@@ -188,15 +257,17 @@ cr.define('extensions', function() {
* Get a node for the stack trace for this error. Each stack frame will
* include a resource url, line number, and function name (possibly
* anonymous). If possible, these frames will also be linked for viewing the
- * source.
+ * source and inspection.
* @return {HTMLDetailsElement} The stack trace node for this error, with
* all stack frames nested in a details-summary object.
* @private
*/
- getStackNode_: function() {
+ createStackNode_: function() {
var node = cloneTemplate('extension-error-stack-trace');
var listNode = node.querySelector('.extension-error-stack-trace-list');
this.error_.stackTrace.forEach(function(frame) {
+ if (!this.shouldDisplayForUrl_(frame.url))
+ return;
var frameNode = document.createElement('div');
var description = getRelativeUrl(frame.url, this.extensionUrl_) +
':' + frame.lineNumber;
@@ -206,12 +277,15 @@ cr.define('extensions', function() {
frame.functionName;
description += ' (' + functionName + ')';
}
- frameNode.appendChild(this.getViewSourceOrPlain_(
- description, frame.url, frame.lineNumber));
+ frameNode.appendChild(this.createViewSourceAndInspect_(
+ description, frame.url, frame.lineNumber, frame.columnNumber));
listNode.appendChild(
document.createElement('li')).appendChild(frameNode);
}, this);
+ if (listNode.childElementCount == 0)
+ return undefined;
+
return node;
},
};
diff --git a/chrome/browser/resources/extensions/extensions.html b/chrome/browser/resources/extensions/extensions.html
index a8927c6..9863915 100644
--- a/chrome/browser/resources/extensions/extensions.html
+++ b/chrome/browser/resources/extensions/extensions.html
@@ -3,10 +3,10 @@
<head>
<meta charset="utf-8">
+<link rel="stylesheet" href="extensions.css">
<link rel="stylesheet" href="extension_commands_overlay.css">
<link rel="stylesheet" href="extension_error.css">
<link rel="stylesheet" href="extension_error_overlay.css">
-<link rel="stylesheet" href="extensions.css">
<link rel="stylesheet" href="pack_extension_overlay.css">
<link rel="stylesheet" href="chrome://resources/css/alert_overlay.css">
<link rel="stylesheet" href="chrome://resources/css/chrome_shared.css">
diff --git a/chrome/browser/task_manager/task_manager_browsertest.cc b/chrome/browser/task_manager/task_manager_browsertest.cc
index 0093f38..f77bea4 100644
--- a/chrome/browser/task_manager/task_manager_browsertest.cc
+++ b/chrome/browser/task_manager/task_manager_browsertest.cc
@@ -516,7 +516,7 @@ IN_PROC_BROWSER_TEST_F(TaskManagerBrowserTest, NoticeInTabDevToolsWindow) {
DevToolsWindow* dev_tools = DevToolsWindow::ToggleDevToolsWindow(
model()->GetResourceWebContents(1)->GetRenderViewHost(),
true,
- DEVTOOLS_TOGGLE_ACTION_INSPECT);
+ DevToolsToggleAction::Inspect());
// Dock side bottom should be the default.
ASSERT_EQ(DEVTOOLS_DOCK_SIDE_BOTTOM, dev_tools->dock_side());
TaskManagerBrowserTestUtil::WaitForWebResourceChange(2);
@@ -530,7 +530,7 @@ IN_PROC_BROWSER_TEST_F(TaskManagerNoShowBrowserTest,
DevToolsWindow* dev_tools = DevToolsWindow::ToggleDevToolsWindow(
browser()->tab_strip_model()->GetActiveWebContents()->GetRenderViewHost(),
true,
- DEVTOOLS_TOGGLE_ACTION_INSPECT);
+ DevToolsToggleAction::Inspect());
// Dock side bottom should be the default.
ASSERT_EQ(DEVTOOLS_DOCK_SIDE_BOTTOM, dev_tools->dock_side());
// Make sure that the devtools window is loaded before starting the task
diff --git a/chrome/browser/ui/browser_command_controller.cc b/chrome/browser/ui/browser_command_controller.cc
index 2860eb8..50a870d 100644
--- a/chrome/browser/ui/browser_command_controller.cc
+++ b/chrome/browser/ui/browser_command_controller.cc
@@ -649,19 +649,19 @@ void BrowserCommandController::ExecuteCommandWithDisposition(
CreateApplicationShortcuts(browser_);
break;
case IDC_DEV_TOOLS:
- ToggleDevToolsWindow(browser_, DEVTOOLS_TOGGLE_ACTION_SHOW);
+ ToggleDevToolsWindow(browser_, DevToolsToggleAction::Show());
break;
case IDC_DEV_TOOLS_CONSOLE:
- ToggleDevToolsWindow(browser_, DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE);
+ ToggleDevToolsWindow(browser_, DevToolsToggleAction::ShowConsole());
break;
case IDC_DEV_TOOLS_DEVICES:
InspectUI::InspectDevices(browser_);
break;
case IDC_DEV_TOOLS_INSPECT:
- ToggleDevToolsWindow(browser_, DEVTOOLS_TOGGLE_ACTION_INSPECT);
+ ToggleDevToolsWindow(browser_, DevToolsToggleAction::Inspect());
break;
case IDC_DEV_TOOLS_TOGGLE:
- ToggleDevToolsWindow(browser_, DEVTOOLS_TOGGLE_ACTION_TOGGLE);
+ ToggleDevToolsWindow(browser_, DevToolsToggleAction::Toggle());
break;
case IDC_TASK_MANAGER:
OpenTaskManager(browser_);
diff --git a/chrome/browser/ui/browser_commands.cc b/chrome/browser/ui/browser_commands.cc
index 16ef803..9d6151a 100644
--- a/chrome/browser/ui/browser_commands.cc
+++ b/chrome/browser/ui/browser_commands.cc
@@ -918,7 +918,7 @@ void FocusPreviousPane(Browser* browser) {
}
void ToggleDevToolsWindow(Browser* browser, DevToolsToggleAction action) {
- if (action == DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE)
+ if (action.type() == DevToolsToggleAction::kShowConsole)
content::RecordAction(UserMetricsAction("DevTools_ToggleConsole"));
else
content::RecordAction(UserMetricsAction("DevTools_ToggleWindow"));
diff --git a/chrome/browser/ui/cocoa/dev_tools_controller_browsertest.mm b/chrome/browser/ui/cocoa/dev_tools_controller_browsertest.mm
index fdc12b5..8e4aba2 100644
--- a/chrome/browser/ui/cocoa/dev_tools_controller_browsertest.mm
+++ b/chrome/browser/ui/cocoa/dev_tools_controller_browsertest.mm
@@ -23,7 +23,7 @@ class DevToolsControllerTest : public InProcessBrowserTest {
virtual void SetUpOnMainThread() OVERRIDE {
DevToolsWindow::ToggleDevToolsWindow(browser(),
- DEVTOOLS_TOGGLE_ACTION_SHOW);
+ DevToolsToggleAction::Show());
}
private:
diff --git a/chrome/browser/ui/cocoa/view_id_util_browsertest.mm b/chrome/browser/ui/cocoa/view_id_util_browsertest.mm
index 2b5bc5a..3fdcc0d 100644
--- a/chrome/browser/ui/cocoa/view_id_util_browsertest.mm
+++ b/chrome/browser/ui/cocoa/view_id_util_browsertest.mm
@@ -49,7 +49,7 @@ class ViewIDTest : public InProcessBrowserTest {
// Make sure docked devtools is created to test VIEW_ID_DEV_TOOLS_DOCKED
browser()->profile()->GetPrefs()->SetString(prefs::kDevToolsDockSide,
"dock_bottom");
- chrome::ToggleDevToolsWindow(browser(), DEVTOOLS_TOGGLE_ACTION_INSPECT);
+ chrome::ToggleDevToolsWindow(browser(), DevToolsToggleAction::Inspect());
// Make sure download shelf is created to test VIEW_ID_DOWNLOAD_SHELF
browser()->window()->GetDownloadShelf()->Show();
diff --git a/chrome/browser/ui/panels/panel.cc b/chrome/browser/ui/panels/panel.cc
index bef02b1..c83607d 100644
--- a/chrome/browser/ui/panels/panel.cc
+++ b/chrome/browser/ui/panels/panel.cc
@@ -415,14 +415,14 @@ void Panel::ExecuteCommandWithDisposition(int id,
DevToolsWindow::ToggleDevToolsWindow(
GetWebContents()->GetRenderViewHost(),
true,
- DEVTOOLS_TOGGLE_ACTION_SHOW);
+ DevToolsToggleAction::Show());
break;
case IDC_DEV_TOOLS_CONSOLE:
content::RecordAction(UserMetricsAction("DevTools_ToggleConsole"));
DevToolsWindow::ToggleDevToolsWindow(
GetWebContents()->GetRenderViewHost(),
true,
- DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE);
+ DevToolsToggleAction::ShowConsole());
break;
default:
diff --git a/chrome/browser/ui/views/extensions/extension_popup.cc b/chrome/browser/ui/views/extensions/extension_popup.cc
index 84051ee..7b8d4ef 100644
--- a/chrome/browser/ui/views/extensions/extension_popup.cc
+++ b/chrome/browser/ui/views/extensions/extension_popup.cc
@@ -201,6 +201,6 @@ void ExtensionPopup::ShowBubble() {
if (inspect_with_devtools_) {
DevToolsWindow::ToggleDevToolsWindow(host()->render_view_host(),
true,
- DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE);
+ DevToolsToggleAction::ShowConsole());
}
}
diff --git a/chrome/browser/ui/views/external_tab_container_win.cc b/chrome/browser/ui/views/external_tab_container_win.cc
index 54fcf1d..e906deb 100644
--- a/chrome/browser/ui/views/external_tab_container_win.cc
+++ b/chrome/browser/ui/views/external_tab_container_win.cc
@@ -1278,22 +1278,22 @@ bool ExternalTabContainerWin::AcceleratorPressed(
case IDC_DEV_TOOLS:
DevToolsWindow::ToggleDevToolsWindow(web_contents_->GetRenderViewHost(),
false,
- DEVTOOLS_TOGGLE_ACTION_SHOW);
+ DevToolsToggleAction::Show());
break;
case IDC_DEV_TOOLS_CONSOLE:
DevToolsWindow::ToggleDevToolsWindow(web_contents_->GetRenderViewHost(),
false,
- DEVTOOLS_TOGGLE_ACTION_SHOW_CONSOLE);
+ DevToolsToggleAction::ShowConsole());
break;
case IDC_DEV_TOOLS_INSPECT:
DevToolsWindow::ToggleDevToolsWindow(web_contents_->GetRenderViewHost(),
false,
- DEVTOOLS_TOGGLE_ACTION_INSPECT);
+ DevToolsToggleAction::Inspect());
break;
case IDC_DEV_TOOLS_TOGGLE:
DevToolsWindow::ToggleDevToolsWindow(web_contents_->GetRenderViewHost(),
false,
- DEVTOOLS_TOGGLE_ACTION_TOGGLE);
+ DevToolsToggleAction::Toggle());
break;
default:
NOTREACHED() << "Unsupported accelerator: " << command_id;
diff --git a/chrome/browser/ui/webui/extensions/extension_error_handler.cc b/chrome/browser/ui/webui/extensions/extension_error_handler.cc
index c537365..e99eec1 100644
--- a/chrome/browser/ui/webui/extensions/extension_error_handler.cc
+++ b/chrome/browser/ui/webui/extensions/extension_error_handler.cc
@@ -11,11 +11,17 @@
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
+#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/extensions/extension.h"
#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_data_source.h"
#include "extensions/browser/extension_error.h"
@@ -55,6 +61,9 @@ void ExtensionErrorHandler::GetLocalizedValues(
"extensionErrorViewSource",
l10n_util::GetStringUTF16(IDS_EXTENSIONS_ERROR_VIEW_SOURCE));
source->AddString(
+ "extensionErrorInspect",
+ l10n_util::GetStringUTF16(IDS_EXTENSIONS_ERROR_INSPECT));
+ source->AddString(
"extensionErrorContext",
l10n_util::GetStringUTF16(IDS_EXTENSIONS_ERROR_CONTEXT));
source->AddString(
@@ -70,6 +79,10 @@ void ExtensionErrorHandler::RegisterMessages() {
"extensionErrorRequestFileSource",
base::Bind(&ExtensionErrorHandler::HandleRequestFileSource,
base::Unretained(this)));
+ web_ui()->RegisterMessageCallback(
+ "extensionErrorOpenDevTools",
+ base::Bind(&ExtensionErrorHandler::HandleOpenDevTools,
+ base::Unretained(this)));
}
void ExtensionErrorHandler::HandleRequestFileSource(
@@ -156,6 +169,67 @@ void ExtensionErrorHandler::HandleRequestFileSource(
closure);
}
+void ExtensionErrorHandler::HandleOpenDevTools(const base::ListValue* args) {
+ CHECK(args->GetSize() == 1);
+
+ const base::DictionaryValue* dict = NULL;
+ int render_process_id = 0;
+ int render_view_id = 0;
+
+ // The render view and render process ids are required.
+ if (!args->GetDictionary(0, &dict) ||
+ !dict->GetInteger(RuntimeError::kRenderProcessIdKey,
+ &render_process_id) ||
+ !dict->GetInteger(RuntimeError::kRenderViewIdKey, &render_view_id)) {
+ NOTREACHED();
+ return;
+ }
+
+ content::RenderViewHost* rvh =
+ content::RenderViewHost::FromID(render_process_id, render_view_id);
+
+ // It's possible that the render view was closed since we last updated the
+ // links. Handle this gracefully.
+ if (!rvh)
+ return;
+
+ // Check if we already have an inspector for the given RenderViewHost. If not,
+ // create one.
+ DevToolsWindow* window =
+ DevToolsWindow::GetInstanceForInspectedRenderViewHost(rvh);
+ if (!window)
+ window = DevToolsWindow::OpenDevToolsWindow(rvh);
+
+ // If we include a url, we should inspect it specifically (and not just the
+ // render view).
+ base::string16 url;
+ if (dict->GetString(RuntimeError::kUrlKey, &url)) {
+ // Line and column numbers are optional; default to the first line.
+ int line_number = 1;
+ int column_number = 1;
+ dict->GetInteger(RuntimeError::kLineNumberKey, &line_number);
+ dict->GetInteger(RuntimeError::kColumnNumberKey, &column_number);
+
+ // Line/column numbers are reported in display-friendly 1-based numbers,
+ // but are inspected in zero-based numbers.
+ window->Show(
+ DevToolsToggleAction::Reveal(url, line_number - 1, column_number - 1));
+ }
+
+ // Once we open the inspector, we focus on the appropriate tab...
+ content::WebContents* web_contents =
+ content::WebContents::FromRenderViewHost(rvh);
+ Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
+ // ... but background pages have no associated browser (and the inspector
+ // opens in its own window), so our work is done.
+ if (!browser)
+ return;
+
+ TabStripModel* tab_strip = browser->tab_strip_model();
+ tab_strip->ActivateTabAt(tab_strip->GetIndexOfWebContents(web_contents),
+ false); // Not through direct user gesture.
+}
+
void ExtensionErrorHandler::GetManifestFileCallback(
base::DictionaryValue* results,
const std::string& key,
diff --git a/chrome/browser/ui/webui/extensions/extension_error_handler.h b/chrome/browser/ui/webui/extensions/extension_error_handler.h
index eb61728..b419135 100644
--- a/chrome/browser/ui/webui/extensions/extension_error_handler.h
+++ b/chrome/browser/ui/webui/extensions/extension_error_handler.h
@@ -43,6 +43,8 @@ class ExtensionErrorHandler : public content::WebUIMessageHandler {
// Handle the "requestFileSource" call.
void HandleRequestFileSource(const base::ListValue* args);
+ // Handle the "openDevTools" call.
+ void HandleOpenDevTools(const base::ListValue* args);
// Populate the results for a manifest file's content in response to the
// "requestFileSource" call. Highlight the part of the manifest which
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
index c4f1b7e..0c8bc85 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
+++ b/chrome/browser/ui/webui/extensions/extension_settings_handler.cc
@@ -148,6 +148,8 @@ ExtensionSettingsHandler::ExtensionSettingsHandler()
management_policy_(NULL),
ignore_notifications_(false),
deleting_rvh_(NULL),
+ deleting_rwh_id_(-1),
+ deleting_rph_id_(-1),
registered_for_notifications_(false),
warning_service_observer_(this),
error_console_observer_(this) {
@@ -166,6 +168,8 @@ ExtensionSettingsHandler::ExtensionSettingsHandler(ExtensionService* service,
management_policy_(policy),
ignore_notifications_(false),
deleting_rvh_(NULL),
+ deleting_rwh_id_(-1),
+ deleting_rph_id_(-1),
registered_for_notifications_(false),
warning_service_observer_(this),
error_console_observer_(this) {
@@ -299,10 +303,19 @@ base::DictionaryValue* ExtensionSettingsHandler::CreateExtensionDetailValue(
scoped_ptr<ListValue> runtime_errors(new ListValue);
for (ErrorConsole::ErrorList::const_iterator iter = errors.begin();
iter != errors.end(); ++iter) {
- if ((*iter)->type() == ExtensionError::MANIFEST_ERROR)
+ if ((*iter)->type() == ExtensionError::MANIFEST_ERROR) {
manifest_errors->Append((*iter)->ToValue().release());
- else
- runtime_errors->Append((*iter)->ToValue().release());
+ } else { // Handle runtime error.
+ const RuntimeError* error = static_cast<const RuntimeError*>(*iter);
+ scoped_ptr<DictionaryValue> value = error->ToValue();
+ bool can_inspect =
+ !(deleting_rwh_id_ == error->render_view_id() &&
+ deleting_rph_id_ == error->render_process_id()) &&
+ RenderViewHost::FromID(error->render_process_id(),
+ error->render_view_id()) != NULL;
+ value->SetBoolean("canInspect", can_inspect);
+ runtime_errors->Append(value.release());
+ }
}
if (!manifest_errors->empty())
extension_data->Set("manifestErrors", manifest_errors.release());
@@ -425,7 +438,7 @@ void ExtensionSettingsHandler::GetLocalizedValues(
}
void ExtensionSettingsHandler::RenderViewDeleted(
- content::RenderViewHost* render_view_host) {
+ RenderViewHost* render_view_host) {
deleting_rvh_ = render_view_host;
Profile* source_profile = Profile::FromBrowserContext(
render_view_host->GetSiteInstance()->GetBrowserContext());
@@ -542,6 +555,14 @@ void ExtensionSettingsHandler::Observe(
return;
MaybeUpdateAfterNotification();
break;
+ case content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED: {
+ content::RenderWidgetHost* rwh =
+ content::Source<content::RenderWidgetHost>(source).ptr();
+ deleting_rwh_id_ = rwh->GetRoutingID();
+ deleting_rph_id_ = rwh->GetProcess()->GetID();
+ MaybeUpdateAfterNotification();
+ break;
+ }
case chrome::NOTIFICATION_EXTENSION_LOADED:
case chrome::NOTIFICATION_EXTENSION_UNLOADED:
case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
@@ -1033,6 +1054,10 @@ void ExtensionSettingsHandler::MaybeRegisterForNotifications() {
chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
content::NotificationService::AllBrowserContextsAndSources());
+ registrar_.Add(this,
+ content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED,
+ content::NotificationService::AllBrowserContextsAndSources());
+
content::WebContentsObserver::Observe(web_ui()->GetWebContents());
warning_service_observer_.Add(
diff --git a/chrome/browser/ui/webui/extensions/extension_settings_handler.h b/chrome/browser/ui/webui/extensions/extension_settings_handler.h
index c2125f0..ff7ecac 100644
--- a/chrome/browser/ui/webui/extensions/extension_settings_handler.h
+++ b/chrome/browser/ui/webui/extensions/extension_settings_handler.h
@@ -242,6 +242,9 @@ class ExtensionSettingsHandler
// it is removed from the process). Keep a pointer to it so we can exclude
// it from the active views.
content::RenderViewHost* deleting_rvh_;
+ // Do the same for a deleting RenderWidgetHost ID and RenderProcessHost ID.
+ int deleting_rwh_id_;
+ int deleting_rph_id_;
// We want to register for notifications only after we've responded at least
// once to the page, otherwise we'd be calling JavaScript functions on objects
diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp
index f7f7d59..2262f2b 100644
--- a/chrome/chrome.gyp
+++ b/chrome/chrome.gyp
@@ -189,6 +189,7 @@
'browser/devtools/devtools_protocol.h',
'browser/devtools/devtools_target_impl.cc',
'browser/devtools/devtools_target_impl.h',
+ 'browser/devtools/devtools_toggle_action.cc',
'browser/devtools/devtools_toggle_action.h',
'browser/devtools/devtools_window.cc',
'browser/devtools/devtools_window.h',
diff --git a/extensions/browser/extension_error.cc b/extensions/browser/extension_error.cc
index 071dbc2..ee6b47e 100644
--- a/extensions/browser/extension_error.cc
+++ b/extensions/browser/extension_error.cc
@@ -130,6 +130,8 @@ const char RuntimeError::kFunctionNameKey[] = "functionName";
const char RuntimeError::kLineNumberKey[] = "lineNumber";
const char RuntimeError::kStackTraceKey[] = "stackTrace";
const char RuntimeError::kUrlKey[] = "url";
+const char RuntimeError::kRenderProcessIdKey[] = "renderProcessId";
+const char RuntimeError::kRenderViewIdKey[] = "renderViewId";
RuntimeError::RuntimeError(const std::string& extension_id,
bool from_incognito,
@@ -137,7 +139,9 @@ RuntimeError::RuntimeError(const std::string& extension_id,
const string16& message,
const StackTrace& stack_trace,
const GURL& context_url,
- logging::LogSeverity level)
+ logging::LogSeverity level,
+ int render_view_id,
+ int render_process_id)
: ExtensionError(ExtensionError::RUNTIME_ERROR,
!extension_id.empty() ? extension_id : GURL(source).host(),
from_incognito,
@@ -145,7 +149,9 @@ RuntimeError::RuntimeError(const std::string& extension_id,
source,
message),
context_url_(context_url),
- stack_trace_(stack_trace) {
+ stack_trace_(stack_trace),
+ render_view_id_(render_view_id),
+ render_process_id_(render_process_id) {
CleanUpInit();
}
@@ -155,8 +161,10 @@ RuntimeError::~RuntimeError() {
scoped_ptr<DictionaryValue> RuntimeError::ToValue() const {
scoped_ptr<DictionaryValue> value = ExtensionError::ToValue();
value->SetString(kContextUrlKey, context_url_.spec());
+ value->SetInteger(kRenderViewIdKey, render_view_id_);
+ value->SetInteger(kRenderProcessIdKey, render_process_id_);
- ListValue* trace_value = new ListValue;
+ base::ListValue* trace_value = new base::ListValue;
for (StackTrace::const_iterator iter = stack_trace_.begin();
iter != stack_trace_.end(); ++iter) {
DictionaryValue* frame_value = new DictionaryValue;
diff --git a/extensions/browser/extension_error.h b/extensions/browser/extension_error.h
index 60e3b90..e905549 100644
--- a/extensions/browser/extension_error.h
+++ b/extensions/browser/extension_error.h
@@ -126,7 +126,9 @@ class RuntimeError : public ExtensionError {
const base::string16& message,
const StackTrace& stack_trace,
const GURL& context_url,
- logging::LogSeverity level);
+ logging::LogSeverity level,
+ int render_view_id,
+ int render_process_id);
virtual ~RuntimeError();
virtual scoped_ptr<base::DictionaryValue> ToValue() const OVERRIDE;
@@ -135,6 +137,8 @@ class RuntimeError : public ExtensionError {
const GURL& context_url() const { return context_url_; }
const StackTrace& stack_trace() const { return stack_trace_; }
+ int render_view_id() const { return render_view_id_; }
+ int render_process_id() const { return render_process_id_; }
// Keys used for retrieving JSON values.
static const char kColumnNumberKey[];
@@ -143,6 +147,8 @@ class RuntimeError : public ExtensionError {
static const char kLineNumberKey[];
static const char kStackTraceKey[];
static const char kUrlKey[];
+ static const char kRenderProcessIdKey[];
+ static const char kRenderViewIdKey[];
private:
virtual bool IsEqualImpl(const ExtensionError* rhs) const OVERRIDE;
@@ -155,6 +161,11 @@ class RuntimeError : public ExtensionError {
GURL context_url_;
StackTrace stack_trace_;
+ // Keep track of the render process which caused the error in order to
+ // inspect the view later, if possible.
+ int render_view_id_;
+ int render_process_id_;
+
DISALLOW_COPY_AND_ASSIGN(RuntimeError);
};