diff options
author | erikkay@google.com <erikkay@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-31 16:25:09 +0000 |
---|---|---|
committer | erikkay@google.com <erikkay@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-31 16:25:09 +0000 |
commit | 5ced5eb46be9e6c2d2b72a421d930cee6d7fcf89 (patch) | |
tree | ffccdfbb0ccd8a7f2663d0144e7684c8ffee0194 /chrome | |
parent | f18953d3c2a4eae2bc33b1eecce96e28f0815a64 (diff) | |
download | chromium_src-5ced5eb46be9e6c2d2b72a421d930cee6d7fcf89.zip chromium_src-5ced5eb46be9e6c2d2b72a421d930cee6d7fcf89.tar.gz chromium_src-5ced5eb46be9e6c2d2b72a421d930cee6d7fcf89.tar.bz2 |
Initial cleanup and refactoring to make debugger UI use DHTML and get rid of the last of its native UI. This is done using a DOMUIHost subclass and a new TabContents type.
This checkin also fixes a few minor issues:
* hitting the keyboard accelerator brings the current debugger window to front
* text is grayed out when in "running" mode rather than "paused"
* up/down arrows have command-line history (transient)
* some text used to get eaten when you first bring up the window ("attached to <tabname>"), this is now handled
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@180 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
23 files changed, 585 insertions, 81 deletions
diff --git a/chrome/app/chrome_dll.vcproj b/chrome/app/chrome_dll.vcproj index 06dd49a..eab878e 100644 --- a/chrome/app/chrome_dll.vcproj +++ b/chrome/app/chrome_dll.vcproj @@ -237,6 +237,10 @@ RelativePath="$(IntDir)\..\util_prebuild\setup_strings.rc" > </File> + <File + RelativePath="..\browser\debugger\resources\debugger_resources.rc" + > + </File> </Filter> <File RelativePath=".\resources\chrome.ico" diff --git a/chrome/browser/browser_commands.cc b/chrome/browser/browser_commands.cc index 2489b9d..fc54ae8 100644 --- a/chrome/browser/browser_commands.cc +++ b/chrome/browser/browser_commands.cc @@ -918,13 +918,10 @@ void Browser::OpenDebuggerWindow() { return; if (current_tab->AsWebContents()) { - if (DebuggerWindow::DoesDebuggerExist()) { - // Only one debugger instance can exist at a time right now. - // TODO(erikkay): need an alert, dialog, something - // or better yet, fix the one instance limitation - return; - } - if (!debugger_window_.get()) { + // Only one debugger instance can exist at a time right now. + // TODO(erikkay): need an alert, dialog, something + // or better yet, fix the one instance limitation + if (!DebuggerWindow::DoesDebuggerExist()) { debugger_window_ = new DebuggerWindow(); } debugger_window_->Show(current_tab); diff --git a/chrome/browser/browser_resources.h b/chrome/browser/browser_resources.h index 74ec39a..f19c44f 100644 --- a/chrome/browser/browser_resources.h +++ b/chrome/browser/browser_resources.h @@ -4,10 +4,9 @@ #define IDR_ABOUT_VERSION_HTML 202 #define IDR_ABOUT_MEMORY_HTML 204 #define IDR_ABOUT_STATS_HTML 205 -#define IDR_DEBUGGER_SHELL_JS 206 -#define IDR_SSL_ROAD_BLOCK_HTML 207 -#define IDR_SSL_ERROR_HTML 208 -#define IDR_NEW_TAB_HTML 209 -#define IDR_SAFE_BROWSING_MALWARE_BLOCK 210 -#define IDR_SAFE_BROWSING_PHISHING_BLOCK 211 -#define IDR_INCOGNITO_TAB_HTML 212 +#define IDR_SSL_ROAD_BLOCK_HTML 206 +#define IDR_SSL_ERROR_HTML 207 +#define IDR_NEW_TAB_HTML 208 +#define IDR_SAFE_BROWSING_MALWARE_BLOCK 209 +#define IDR_SAFE_BROWSING_PHISHING_BLOCK 210 +#define IDR_INCOGNITO_TAB_HTML 211 diff --git a/chrome/browser/browser_resources.rc b/chrome/browser/browser_resources.rc index 1dc67e9..399c882 100644 --- a/chrome/browser/browser_resources.rc +++ b/chrome/browser/browser_resources.rc @@ -17,7 +17,6 @@ IDR_ABOUT_PLUGINS_HTML BINDATA "browser\\resources\\about_plugins.html" IDR_ABOUT_VERSION_HTML BINDATA "browser\\resources\\about_version.html" IDR_ABOUT_MEMORY_HTML BINDATA "browser_resources\\about_memory_flat.html" IDR_ABOUT_STATS_HTML BINDATA "browser\\resources\\about_stats.html" -IDR_DEBUGGER_SHELL_JS BINDATA "browser\\resources\\debugger_shell.js" IDR_SSL_ROAD_BLOCK_HTML BINDATA "browser_resources\\ssl_roadblock_flat.html" IDR_SSL_ERROR_HTML BINDATA "browser_resources\\ssl_error_flat.html" IDR_NEW_TAB_HTML BINDATA "browser_resources\\new_tab_flat.html" diff --git a/chrome/browser/debugger/debugger.vcproj b/chrome/browser/debugger/debugger.vcproj index 3159e6d..38c32fd 100644 --- a/chrome/browser/debugger/debugger.vcproj +++ b/chrome/browser/debugger/debugger.vcproj @@ -121,6 +121,34 @@ <References> </References> <Files> + <Filter + Name="resources" + > + <File + RelativePath=".\resources\debugger.css" + > + </File> + <File + RelativePath=".\resources\debugger.html" + > + </File> + <File + RelativePath=".\resources\debugger.js" + > + </File> + <File + RelativePath=".\resources\debugger_shell.js" + > + </File> + </Filter> + <File + RelativePath=".\debugger_contents.cc" + > + </File> + <File + RelativePath=".\debugger_contents.h" + > + </File> <File RelativePath=".\debugger_io.h" > @@ -150,7 +178,7 @@ > </File> <File - RelativePath="..\resources\debugger_shell.js" + RelativePath=".\resources\debugger_resources.h" > </File> <File diff --git a/chrome/browser/debugger/debugger_contents.cc b/chrome/browser/debugger/debugger_contents.cc new file mode 100644 index 0000000..7b2e0a3 --- /dev/null +++ b/chrome/browser/debugger/debugger_contents.cc @@ -0,0 +1,131 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// This file defines utility functions for working with strings. + +#include "chrome/browser/browser_process.h" +#include "chrome/browser/debugger/debugger_contents.h" +#include "chrome/browser/debugger/debugger_shell.h" +#include "chrome/browser/debugger/debugger_wrapper.h" +#include "chrome/browser/debugger/resources/debugger_resources.h" +#include "chrome/browser/dom_ui/chrome_url_data_manager.h" +#include "chrome/common/resource_bundle.h" + +class DebuggerHTMLSource : public ChromeURLDataManager::DataSource { + public: + // Creates our datasource and sets our user message to a specific message + // from our string bundle. + DebuggerHTMLSource() + : DataSource("debugger", MessageLoop::current()) { } + + // Called when the network layer has requested a resource underneath + // the path we registered. + virtual void StartDataRequest(const std::string& path, int request_id) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + int resource_id = 0; + + if (!path.length()) { + resource_id = IDR_DEBUGGER_HTML; + } else if (path == "debugger.js") { + resource_id = IDR_DEBUGGER_JS; + } else if (path == "debugger.css") { + resource_id = IDR_DEBUGGER_CSS; + } else { + SendResponse(request_id, NULL); + return; + } + const std::string& data_str = rb.GetDataResource(resource_id); + scoped_refptr<RefCountedBytes> data_bytes(new RefCountedBytes); + data_bytes->data.resize(data_str.size()); + std::copy(data_str.begin(), data_str.end(), data_bytes->data.begin()); + + SendResponse(request_id, data_bytes); + } + + private: + DISALLOW_EVIL_CONSTRUCTORS(DebuggerHTMLSource); +}; + + +class DebuggerHandler : public DOMMessageHandler { + public: + explicit DebuggerHandler(DOMUIHost* host) { + host->RegisterMessageCallback("command", + NewCallback(this, &DebuggerHandler::HandleCommand)); + } + + void HandleCommand(const Value* content) { + // Extract the parameters out of the input list. + if (!content || !content->IsType(Value::TYPE_LIST)) { + NOTREACHED(); + return; + } + const ListValue* args = static_cast<const ListValue*>(content); + if (args->GetSize() != 1) { + NOTREACHED(); + return; + } + std::wstring command; + Value* value = NULL; + if (!args->Get(0, &value) || !value->GetAsString(&command)) { + NOTREACHED(); + return; + } +#ifndef CHROME_DEBUGGER_DISABLED + DebuggerWrapper* wrapper = g_browser_process->debugger_wrapper(); + DebuggerShell* shell = wrapper->GetDebugger(); + shell->ProcessCommand(command); +#endif + } + private: + DISALLOW_EVIL_CONSTRUCTORS(DebuggerHandler); +}; + + +DebuggerContents::DebuggerContents(Profile* profile, SiteInstance* instance) + : DOMUIHost(profile, instance, NULL) { + type_ = TAB_CONTENTS_DEBUGGER; +} + +void DebuggerContents::AttachMessageHandlers() { + AddMessageHandler(new DebuggerHandler(this)); + + DebuggerHTMLSource* html_source = new DebuggerHTMLSource(); + g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE, + NewRunnableMethod(&chrome_url_data_manager, + &ChromeURLDataManager::AddDataSource, + html_source)); +} + +// static +bool DebuggerContents::IsDebuggerUrl(const GURL& url) { + if (url.SchemeIs("chrome-resource") && url.host() == "debugger") + return true; + return false; +} diff --git a/chrome/browser/debugger/debugger_contents.h b/chrome/browser/debugger/debugger_contents.h new file mode 100644 index 0000000..9e8e271 --- /dev/null +++ b/chrome/browser/debugger/debugger_contents.h @@ -0,0 +1,56 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// This file defines utility functions for working with strings. + +#ifndef CHROME_BROWSER_SHELL_DEBUGGER_CONTENTS_H__ +#define CHROME_BROWSER_SHELL_DEBUGGER_CONTENTS_H__ + +#include "chrome/browser/dom_ui/dom_ui_host.h" + +class DebuggerContents : public DOMUIHost { + public: + DebuggerContents(Profile* profile, SiteInstance* instance); + + static bool IsDebuggerUrl(const GURL& url); + + protected: + // WebContents overrides: + // We override updating history with a no-op so these pages + // are not saved to history. + virtual void UpdateHistoryForNavigation(const GURL& url, + const ViewHostMsg_FrameNavigate_Params& params) { } + + // DOMUIHost implementation. + virtual void AttachMessageHandlers(); + + DISALLOW_EVIL_CONSTRUCTORS(DebuggerContents); +}; + +#endif // CHROME_BROWSER_DEBUGGER_CONTENTS_H__ diff --git a/chrome/browser/debugger/debugger_disabled.vcproj b/chrome/browser/debugger/debugger_disabled.vcproj index 6279337..750ae30 100644 --- a/chrome/browser/debugger/debugger_disabled.vcproj +++ b/chrome/browser/debugger/debugger_disabled.vcproj @@ -122,7 +122,15 @@ </References> <Files> <File - RelativePath=".\debugger.h" + RelativePath=".\debugger_contents.cc" + > + </File> + <File + RelativePath=".\debugger_contents.h" + > + </File> + <File + RelativePath=".\debugger_shell.h" > </File> <File diff --git a/chrome/browser/debugger/debugger_io_socket.cc b/chrome/browser/debugger/debugger_io_socket.cc index b3036a8..7b5e013c 100644 --- a/chrome/browser/debugger/debugger_io_socket.cc +++ b/chrome/browser/debugger/debugger_io_socket.cc @@ -34,7 +34,6 @@ #include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/browser_resources.h" #include "chrome/browser/render_process_host.h" #include "chrome/browser/tab_contents.h" #include "chrome/browser/debugger/debugger_shell.h" @@ -138,8 +137,9 @@ void DebuggerInputOutputSocket::DidRead(ListenSocket *connection, const std::string& data) { DCHECK(MessageLoop::current() == io_loop_); if (connection == connection_) { + const std::wstring wstr = UTF8ToWide(data); ui_loop_->PostTask(FROM_HERE, NewRunnableMethod( - debugger_, &DebuggerShell::ProcessCommand, data)); + debugger_, &DebuggerShell::ProcessCommand, wstr)); } else { // TODO(erikkay): assert? } diff --git a/chrome/browser/debugger/debugger_shell.cc b/chrome/browser/debugger/debugger_shell.cc index 0679292..9f47258 100644 --- a/chrome/browser/debugger/debugger_shell.cc +++ b/chrome/browser/debugger/debugger_shell.cc @@ -36,14 +36,13 @@ #include "chrome/browser/browser.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/browser_resources.h" -#include "chrome/browser/render_process_host.h" -#include "chrome/browser/tab_contents.h" #include "chrome/browser/debugger/debugger_io.h" #include "chrome/browser/debugger/debugger_node.h" +#include "chrome/browser/debugger/resources/debugger_resources.h" +#include "chrome/browser/render_process_host.h" +#include "chrome/browser/tab_contents.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/resource_bundle.h" -#include "v8/public/v8.h" DebuggerShell::DebuggerShell(DebuggerInputOutput* io) : io_(io), debugger_ready_(true) { @@ -148,11 +147,11 @@ v8::Handle<v8::Value> DebuggerShell::Subshell(const v8::Arguments& args) { v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(args[0]); v8::Local<v8::Object> obj = func->NewInstance(); if (!obj->IsUndefined()) { - shell_= v8::Persistent<v8::Object>::New(obj); + shell_ = v8::Persistent<v8::Object>::New(obj); v8_context_->Global()->Set(v8::String::New("shell_"), shell_); } } else if (args[0]->IsObject()) { - shell_= v8::Persistent<v8::Object>::New(v8::Local<v8::Object>::Cast(args[0])); + shell_ = v8::Persistent<v8::Object>::New(v8::Local<v8::Object>::Cast(args[0])); v8_context_->Global()->Set(v8::String::New("shell_"), shell_); } return v8::Undefined(); @@ -346,20 +345,22 @@ void DebuggerShell::PrintPrompt() { io_->OutputPrompt(out); } -void DebuggerShell::ProcessCommand(const std::string& data) { +void DebuggerShell::ProcessCommand(const std::wstring& data) { v8::HandleScope outer; v8::Context::Scope scope(v8_context_); - if (!shell_.IsEmpty() && data.substr(0, 7) != "source(") { - if (data == "exit") { + if (!shell_.IsEmpty() && data.substr(0, 7) != L"source(") { + if (data == L"exit") { PrintObject(SubshellFunction("exit", 0, NULL)); v8_context_->Global()->Delete(v8::String::New("shell_")); shell_.Dispose(); shell_.Clear(); } else { - v8::Handle<v8::Value> argv[] = {v8::String::New(data.c_str())}; + const uint16* utf16 = reinterpret_cast<const uint16*>(data.c_str()); + v8::Handle<v8::Value> argv[] = {v8::String::New(utf16)}; PrintObject(SubshellFunction("command", 1, argv)); } } else if (data.length()) { + //TODO(erikkay): change everything to wstring v8::Handle<v8::Value> result = CompileAndRun(data); PrintObject(result); } @@ -394,8 +395,21 @@ void DebuggerShell::DidConnect() { PrintPrompt(); } -v8::Handle<v8::Value> DebuggerShell::CompileAndRun(const std::string& str, - const std::string& filename) { +void DebuggerShell::DidDisconnect() { + v8::HandleScope outer; + SubshellFunction("exit", 0, NULL); +} + +v8::Handle<v8::Value> DebuggerShell::CompileAndRun( + const std::string& str, + const std::string& filename) { + const std::wstring wstr = UTF8ToWide(str); + return CompileAndRun(wstr, filename); +} + +v8::Handle<v8::Value> DebuggerShell::CompileAndRun( + const std::wstring& wstr, + const std::string& filename) { v8::Context::Scope scope(v8_context_); v8::Handle<v8::String> scriptname; if (filename.length() > 0) { @@ -403,10 +417,10 @@ v8::Handle<v8::Value> DebuggerShell::CompileAndRun(const std::string& str, } else { scriptname = v8::String::New(""); } - v8::ScriptOrigin origin = - v8::ScriptOrigin(scriptname); + const uint16* utf16 = reinterpret_cast<const uint16*>(wstr.c_str()); + v8::ScriptOrigin origin = v8::ScriptOrigin(scriptname); v8::Local<v8::Script> code = - v8::Script::Compile(v8::String::New(str.c_str()), &origin); + v8::Script::Compile(v8::String::New(utf16), &origin); if (!code.IsEmpty()) { v8::Local<v8::Value> result = code->Run(); if (!result.IsEmpty()) { diff --git a/chrome/browser/debugger/debugger_shell.h b/chrome/browser/debugger/debugger_shell.h index d7b18b4..cafb8bf 100644 --- a/chrome/browser/debugger/debugger_shell.h +++ b/chrome/browser/debugger/debugger_shell.h @@ -47,7 +47,7 @@ class DebuggerShell : public base::RefCountedThreadSafe<DebuggerShell> { public: DebuggerShell() { - LOG(ERROR) << "Debug Debugger not enabled for KJS"; + LOG(ERROR) << "Debugger not enabled for KJS"; } virtual ~DebuggerShell() {} void Start() {} @@ -83,7 +83,8 @@ class DebuggerShell : public base::RefCountedThreadSafe<DebuggerShell> { // SocketInputOutput callback methods void DidConnect(); - void ProcessCommand(const std::string& data); + void DidDisconnect(); + void ProcessCommand(const std::wstring& data); static v8::Handle<v8::Value> SetDebuggerReady(const v8::Arguments& args, DebuggerShell* debugger); @@ -108,6 +109,8 @@ class DebuggerShell : public base::RefCountedThreadSafe<DebuggerShell> { void PrintLine(const std::string& out); void PrintString(const std::string& out); void PrintPrompt(); + v8::Handle<v8::Value> CompileAndRun(const std::wstring& wstr, + const std::string& filename = ""); v8::Handle<v8::Value> CompileAndRun(const std::string& str, const std::string& filename = ""); @@ -120,7 +123,7 @@ class DebuggerShell : public base::RefCountedThreadSafe<DebuggerShell> { void MessageListener(v8::Handle<v8::Message> message); - // global debugger() function designed to allow command-line processing by + // global shell() function designed to allow command-line processing by // javascript code rather than by this object. static v8::Handle<v8::Value> DelegateSubshell(const v8::Arguments& args); v8::Handle<v8::Value> Subshell(const v8::Arguments& args); diff --git a/chrome/browser/debugger/debugger_view.cc b/chrome/browser/debugger/debugger_view.cc index 14b1733..be711f0 100644 --- a/chrome/browser/debugger/debugger_view.cc +++ b/chrome/browser/debugger/debugger_view.cc @@ -35,8 +35,12 @@ #include "base/values.h" #include "chrome/browser/browser_list.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/render_view_host.h" +#include "chrome/browser/debugger/resources/debugger_resources.h" +#include "chrome/browser/debugger/debugger_shell.h" #include "chrome/browser/debugger/debugger_view.h" +#include "chrome/browser/debugger/debugger_wrapper.h" +#include "chrome/browser/dom_ui/chrome_url_data_manager.h" +#include "chrome/browser/render_view_host.h" #include "chrome/browser/standard_layout.h" #include "chrome/browser/tab_contents.h" #include "chrome/browser/tab_contents_container_view.h" @@ -51,11 +55,7 @@ #include "chrome/views/view.h" -DebuggerView::DebuggerView(ChromeViews::TextField::Controller* controller) { - command_text_ = new ChromeViews::TextField(); - command_text_->SetFont(font_); - command_text_->SetController(controller); - AddChildView(command_text_); +DebuggerView::DebuggerView() : output_ready_(false) { web_container_ = new TabContentsContainerView(); AddChildView(web_container_); } @@ -69,9 +69,7 @@ void DebuggerView::GetPreferredSize(CSize* out) { } void DebuggerView::Layout() { - int cmd_height = 20; - web_container_->SetBounds(0, 0, GetWidth(), GetHeight() - cmd_height); - command_text_->SetBounds(0, GetHeight() - cmd_height, GetWidth(), cmd_height); + web_container_->SetBounds(0, 0, GetWidth(), GetHeight()); } void DebuggerView::Paint(ChromeCanvas* canvas) { @@ -82,54 +80,78 @@ void DebuggerView::Paint(ChromeCanvas* canvas) { #endif } +void DebuggerView::SetOutputViewReady() { + output_ready_ = true; + for (std::vector<std::wstring>::iterator i = pending_output_.begin(); + i != pending_output_.end(); ++i) { + Output(*i); + } + pending_output_.clear(); +} + void DebuggerView::Output(const std::string& out) { Output(UTF8ToWide(out)); } void DebuggerView::Output(const std::wstring& out) { - if (web_contents_->is_loading()) { - Sleep(100); + if (!output_ready_) { + pending_output_.push_back(out); + return; } Value* str_value = Value::CreateStringValue(out); std::string json; JSONWriter::Write(str_value, false, &json); - const std::string js = - StringPrintf("javascript:void(appendText(%s))", json.c_str()); - web_contents_->render_view_host()->ExecuteJavascriptInWebFrame(L"", - UTF8ToWide(js)); + const std::string js = StringPrintf("appendText(%s)", json.c_str()); + ExecuteJavascript(js); } void DebuggerView::OnInit() { // We can't create the WebContents until we've actually been put into a real // view hierarchy somewhere. Profile* profile = BrowserList::GetLastActive()->profile(); - TabContents* tc = TabContents::CreateWithType(TAB_CONTENTS_WEB, + TabContents* tc = TabContents::CreateWithType(TAB_CONTENTS_DEBUGGER, ::GetDesktopWindow(), profile, NULL); web_contents_ = tc->AsWebContents(); web_contents_->SetupController(profile); web_contents_->set_delegate(this); web_container_->SetTabContents(web_contents_); + web_contents_->render_view_host()->AllowDOMUIBindings(); - // TODO(erikkay): move this into chrome-tools scheme when that gets added. - // This will allow us to do some spiffier things as well as making this - // HTML easier to maintain. - GURL contents("data:text/html,<html><head><script>function appendText(txt){var output = document.getElementById('output'); output.appendChild(document.createTextNode(txt)); output.appendChild(document.createElement('br')); document.body.scrollTop = document.body.scrollHeight;};</script><style type='text/css'>body{margin:0px;padding:0px;}#output { font-family: monospace; background-} #outer { width: 100%; height: 100%; white-space: pre-wrap;}</style></head><body><table id='outer'><tr><td valign='bottom' id='output'>JavaScript Debugger<br/></td></tr></table></body></html>"); + GURL contents("chrome-resource://debugger/"); web_contents_->controller()->LoadURL(contents, PageTransition::START_PAGE); } void DebuggerView::OnShow() { - command_text_->RequestFocus(); + web_contents_->Focus(); + if (output_ready_) + ExecuteJavascript("focusOnCommandLine()"); } void DebuggerView::OnClose() { web_container_->SetTabContents(NULL); - web_contents_->CloseContents(); } +void DebuggerView::SetDebuggerBreak(bool is_broken) { + const std::string js = + StringPrintf("setDebuggerBreak(%s)", is_broken ? "true" : "false"); + ExecuteJavascript(js); +} + void DebuggerView::OpenURLFromTab(TabContents* source, const GURL& url, WindowOpenDisposition disposition, PageTransition::Type transition) { BrowserList::GetLastActive()->OpenURL(url, disposition, transition); } + +void DebuggerView::ExecuteJavascript(const std::string& js) { + const std::string url = StringPrintf("javascript:void(%s)", js.c_str()); + web_contents_->render_view_host()->ExecuteJavascriptInWebFrame(L"", + UTF8ToWide(url)); +} + +void DebuggerView::LoadingStateChanged(TabContents* source) { + if (!source->is_loading()) + SetOutputViewReady(); +} diff --git a/chrome/browser/debugger/debugger_view.h b/chrome/browser/debugger/debugger_view.h index a4ae560..aaa372c 100644 --- a/chrome/browser/debugger/debugger_view.h +++ b/chrome/browser/debugger/debugger_view.h @@ -48,7 +48,7 @@ class WebContents; class DebuggerView : public ChromeViews::View, public TabContentsDelegate { public: - DebuggerView(ChromeViews::TextField::Controller* controller); + DebuggerView(); virtual ~DebuggerView(); // Output a line of text to the debugger view @@ -63,6 +63,11 @@ class DebuggerView : public ChromeViews::View, // Called when the window is being closed. void OnClose(); + // Called when the debugger hits a breakpoint or continues. + void SetDebuggerBreak(bool is_broken); + + void SetOutputViewReady(); + // Overridden from ChromeViews::View: virtual std::string GetClassName() const { return "DebuggerView"; @@ -71,11 +76,13 @@ class DebuggerView : public ChromeViews::View, virtual void Layout(); virtual void Paint(ChromeCanvas* canvas); - // Overridden from TabContentsDelegate: + // Overridden from PageNavigator (TabContentsDelegate's base interface): virtual void OpenURLFromTab(TabContents* source, const GURL& url, WindowOpenDisposition disposition, PageTransition::Type transition); + + // Overridden from TabContentsDelegate: virtual void NavigationStateChanged(const TabContents* source, unsigned changed_flags) {} virtual void ReplaceContents(TabContents* source, @@ -86,7 +93,7 @@ class DebuggerView : public ChromeViews::View, const gfx::Rect& initial_pos, bool user_gesture) {} virtual void ActivateContents(TabContents* contents) {} - virtual void LoadingStateChanged(TabContents* source) {} + virtual void LoadingStateChanged(TabContents* source); virtual void CloseContents(TabContents* source) {} virtual void MoveContents(TabContents* source, const gfx::Rect& pos) {} virtual bool IsPopup(TabContents* source) { return false; } @@ -96,12 +103,14 @@ class DebuggerView : public ChromeViews::View, virtual bool CanBlur() const { return false; } private: + void ExecuteJavascript(const std::string& js); - ChromeViews::TextField* command_text_; DebuggerWindow* window_; ChromeFont font_; WebContents* web_contents_; TabContentsContainerView* web_container_; + std::vector<std::wstring> pending_output_; + bool output_ready_; DISALLOW_EVIL_CONSTRUCTORS(DebuggerView); }; diff --git a/chrome/browser/debugger/debugger_window.cc b/chrome/browser/debugger/debugger_window.cc index 6e94a06..d9842c2 100644 --- a/chrome/browser/debugger/debugger_window.cc +++ b/chrome/browser/debugger/debugger_window.cc @@ -61,7 +61,7 @@ void DebuggerWindow::Show(TabContents* tab) { view_->OnShow(); return; } - view_ = new DebuggerView(this); + view_ = new DebuggerView(); window_ = ChromeViews::Window::CreateChromeWindow(NULL, gfx::Rect(), this); view_->OnInit(); window_->Show(); @@ -131,7 +131,8 @@ void DebuggerWindow::SetDebuggerReady(bool ready) { #ifndef CHROME_DEBUGGER_DISABLED if (debugger_ready_ != ready) { debugger_ready_ = ready; - window_->UpdateWindowTitle(); + if (window_) + window_->UpdateWindowTitle(); } #endif } @@ -140,9 +141,13 @@ void DebuggerWindow::SetDebuggerBreak(bool brk) { #ifndef CHROME_DEBUGGER_DISABLED if (debugger_break_ != brk) { debugger_break_ = brk; - window_->UpdateWindowTitle(); - if (brk) - window_->Activate(); + if (window_) { + if (view_) + view_->SetDebuggerBreak(brk); + window_->UpdateWindowTitle(); + if (brk) + window_->Activate(); + } } #endif } @@ -164,9 +169,12 @@ void DebuggerWindow::WindowClosing() { #ifndef CHROME_DEBUGGER_DISABLED view_->OnClose(); #endif - debugger_ = NULL; window_ = NULL; view_ = NULL; +#ifndef CHROME_DEBUGGER_DISABLED + debugger_->DidDisconnect(); +#endif + debugger_ = NULL; DebuggerWrapper* wrapper = g_browser_process->debugger_wrapper(); wrapper->SetDebugger(NULL); } @@ -194,7 +202,7 @@ void DebuggerWindow::HandleKeystroke(ChromeViews::TextField* sender, UINT messag std::wstring txt = sender->GetText(); if (txt.length()) { view_->Output(L"$ " + txt); - debugger_->ProcessCommand(WideToUTF8(txt)); + debugger_->ProcessCommand(txt); sender->SetText(L""); } } diff --git a/chrome/browser/debugger/resources/debugger.css b/chrome/browser/debugger/resources/debugger.css new file mode 100644 index 0000000..ed9df2f --- /dev/null +++ b/chrome/browser/debugger/resources/debugger.css @@ -0,0 +1,35 @@ +/** + * Style for javascript debugger. See debugger.html. + */ + +html,body { + margin: 0px; + padding: 0px; + height: 100%; +} +#output { + font-family: monospace; + background-color: #ffffff; + min-height: 100%; +} +#outer { + height: 100%; + width: 100%; + white-space: pre-wrap; + padding: 0px 0px 24px 0px; +} +#command-line { + bottom: 0px; + /* not quite sure why this 5px is necessary */ + right: 5px; + left: 0px; + position: fixed; + padding: 0px; + margin: 0px; +} +#command-line-text { + height: 20px; + display: block; + width: 100%; + font-family: monospace; +} diff --git a/chrome/browser/debugger/resources/debugger.html b/chrome/browser/debugger/resources/debugger.html new file mode 100644 index 0000000..7eab990 --- /dev/null +++ b/chrome/browser/debugger/resources/debugger.html @@ -0,0 +1,34 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" + "http://www.w3.org/TR/html4/strict.dtd"> +<html> +<!-- + The UI for the javascript debugger window. +--> + <head> + <title>JavaScript Debugger</title> + <meta http-equiv="Content-Type" content="text/html; charset=UTF8" /> + <link rel="stylesheet" href="debugger.css" type="text/css" /> + <script type="text/javascript" src="debugger.js"></script> + </head> + + <body> + + <table id='outer'> + <tr> + <td valign='bottom' id='output'>Chrome JavaScript Debugger<br />Type 'help' for a list of commands.<br /></td> + </tr> + </table> + + <div id='command-line'> + <!-- TODO(erikkay) - use addEventListener instead --> + <input id='command-line-text' + onkeydown="return keydown(event);" + onkeypress="return keypress(event);" type="text" /> + </div> + + <script type="text/javascript" language="javascript"> + loaded(); + </script> + + </body> +</html> diff --git a/chrome/browser/debugger/resources/debugger.js b/chrome/browser/debugger/resources/debugger.js new file mode 100644 index 0000000..a52a5c0 --- /dev/null +++ b/chrome/browser/debugger/resources/debugger.js @@ -0,0 +1,124 @@ +/** + * @fileoverview Helper functions and objects for the JS debugger UI. + * @see debugger.html + */ + +/** + * Called at the end of <body>. + */ +function loaded() { + focusOnCommandLine(); +}; + +/** + * Sets focus to command-line-text element. + */ +function focusOnCommandLine() { + var input = document.getElementById('command-line-text'); + input.focus(); +}; + +/** + * Called by chrome code when there's output to display. + */ +function appendText(txt) { + var output = document.getElementById('output'); + output.appendChild(document.createTextNode(txt)); + output.appendChild(document.createElement('br')); + document.body.scrollTop = document.body.scrollHeight; +}; + +// command object stores command-line history state. +var command = { + history: [], + history_index: 0, + pending: null +}; + +/** + * Execute a debugger command, add it to the command history and display it in + * the output window. + */ +function executeCommand(str) { + appendText("$ " + str); + // Sends field.value to DebuggerContents.HandleCommand. + chrome.send("command", [str]); + command.history.push(str); + command.history_index = command.history.length; + command.pending = null; +}; + +/** + * Display the previous history item in the given text field. + */ +function selectPreviousCommand(field) { + if (command.history_index > 0) { + // Remember the current field value as a pending command if we're at the + // end (it's something the user typed in). + if (command.history_index == command.history.length) + command.pending = field.value; + command.history_index--; + field.value = command.history[command.history_index]; + field.select(); + } +}; + +/** + * Display the next history item in the given text field. + */ +function selectNextCommand(field) { + if (command.history_index < command.history.length) { + command.history_index++; + if (command.history_index == command.history.length) { + field.value = command.pending || ""; + } else { + field.value = command.history[command.history_index]; + } + field.select(); + } +}; + + +/** + * command-line-text's onkeypress handler + */ +function keypress(e) { + var field = e.target; + var key = e.keyCode; + if (key == 13) { // enter + executeCommand(field.value); + field.value = ""; + return false; + } + return true; +}; + +/** + * command-line-text's onkeydown handler + */ +function keydown(e) { + var field = e.target; + var key = e.keyCode; + if (key == 38) { // up arrow + selectPreviousCommand(field); + return false; + } else if (key == 40) { // down arrow + selectNextCommand(field); + return false; + } + return true; +}; + +/** + * Called by chrome code to set the current state as to whether the debugger + * is stopped at a breakpoint or is running. + */ +function setDebuggerBreak(is_broken) { + var out = document.getElementById('output'); + if (is_broken) { + out.style.color = "black"; + focusOnCommandLine(); + } else { + out.style.color = "gray"; + } +}; diff --git a/chrome/browser/debugger/resources/debugger_resources.h b/chrome/browser/debugger/resources/debugger_resources.h new file mode 100644 index 0000000..0dbf643 --- /dev/null +++ b/chrome/browser/debugger/resources/debugger_resources.h @@ -0,0 +1,6 @@ +// TODO(tc): Come up with a way to automate the generation of these +// IDs so they don't collide with other rc files. +#define IDR_DEBUGGER_SHELL_JS 600 +#define IDR_DEBUGGER_HTML 601 +#define IDR_DEBUGGER_CSS 602 +#define IDR_DEBUGGER_JS 603 diff --git a/chrome/browser/debugger/resources/debugger_resources.rc b/chrome/browser/debugger/resources/debugger_resources.rc new file mode 100644 index 0000000..13c2e87 --- /dev/null +++ b/chrome/browser/debugger/resources/debugger_resources.rc @@ -0,0 +1,19 @@ +// Resources used by browser/debugger/*.
+//
+// Paths in this file are relative to SolutionDir.
+
+#ifdef APSTUDIO_INVOKED
+ #error // Don't open in the Visual Studio resource editor!
+#endif //APSTUDIO_INVOKED
+
+#include "browser\\debugger\\resources\\debugger_resources.h"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// data resources
+//
+
+IDR_DEBUGGER_SHELL_JS BINDATA "browser\\debugger\\resources\\debugger_shell.js"
+IDR_DEBUGGER_HTML BINDATA "browser\\debugger\\resources\\debugger.html"
+IDR_DEBUGGER_CSS BINDATA "browser\\debugger\\resources\\debugger.css"
+IDR_DEBUGGER_JS BINDATA "browser\\debugger\\resources\\debugger.js"
diff --git a/chrome/browser/resources/debugger_shell.js b/chrome/browser/debugger/resources/debugger_shell.js index 4685896..ab89c0d 100644 --- a/chrome/browser/resources/debugger_shell.js +++ b/chrome/browser/debugger/resources/debugger_shell.js @@ -1,19 +1,15 @@ -// Copyright 2008 Google Inc. -// All Rights Reserved. - -// TODO(erikkay): look into how this can be split up into multiple files -// It's currently loaded explicitly by Chrome, so maybe I need an "include" -// or "source" builtin to allow a core source file to reference multiple -// sub-files. - /** * @fileoverview Shell objects and global helper functions for Chrome * automation shell / debugger. This file is loaded into the global namespace * of the interactive shell, so users can simply call global functions * directly. - * @author erikkay@google.com (Erik Kay) */ +// TODO(erikkay): look into how this can be split up into multiple files +// It's currently loaded explicitly by Chrome, so maybe I need an "include" +// or "source" builtin to allow a core source file to reference multiple +// sub-files. + /** * Sequence number of the DebugCommand. */ @@ -102,13 +98,16 @@ DebugCommand.log10 = function(num) { * @param {Object} obj - object to encode */ DebugCommand.toJSON = function(obj) { + // TODO(erikkay): use a real JSON library var json = '{'; for (var key in obj) { + if (json.length > 1) + json += ","; var val = obj[key]; if (!DebugCommand.isInt(val)) { val = DebugCommand.stringToJSON(val.toString()); } - json += '"' + key + '":' + val + ','; + json += '"' + key + '":' + val; } json += '}'; return json; @@ -119,6 +118,7 @@ DebugCommand.toJSON = function(obj) { * @see http://wiki/Main/V8Debugger */ DebugCommand.prototype.toJSONProtocol = function() { + // TODO(erikkay): use a real JSON library var json = '{'; json += '"seq":"' + this.seq; json += '","type":"' + this.type; diff --git a/chrome/browser/tab_contents_factory.cc b/chrome/browser/tab_contents_factory.cc index 4fbbf07..641826e 100644 --- a/chrome/browser/tab_contents_factory.cc +++ b/chrome/browser/tab_contents_factory.cc @@ -39,6 +39,7 @@ #include "chrome/browser/network_status_view.h" #include "chrome/browser/profile.h" #include "chrome/browser/render_process_host.h" +#include "chrome/browser/debugger/debugger_contents.h" #include "chrome/browser/tab_contents_factory.h" #include "chrome/browser/view_source_contents.h" #include "chrome/browser/web_contents.h" @@ -85,6 +86,9 @@ TabContents* TabContents::CreateWithType(TabContentsType type, case TAB_CONTENTS_ABOUT_UI: contents = new BrowserAboutHandler(profile, instance, NULL); break; + case TAB_CONTENTS_DEBUGGER: + contents = new DebuggerContents(profile, instance); + break; default: if (g_extra_types) { TabContentsFactoryMap::const_iterator it = g_extra_types->find(type); @@ -126,6 +130,9 @@ TabContentsType TabContents::TypeForURL(GURL* url) { if (HtmlDialogContents::IsHtmlDialogUrl(*url)) return TAB_CONTENTS_HTML_DIALOG; + if (DebuggerContents::IsDebuggerUrl(*url)) + return TAB_CONTENTS_DEBUGGER; + if (url->SchemeIs("view-source")) { // Load the inner URL instead, but render it using a ViewSourceContents. *url = GURL(url->path()); diff --git a/chrome/browser/tab_contents_type.h b/chrome/browser/tab_contents_type.h index 1ebc811..2aa92ee 100644 --- a/chrome/browser/tab_contents_type.h +++ b/chrome/browser/tab_contents_type.h @@ -47,6 +47,7 @@ enum TabContentsType { TAB_CONTENTS_VIEW_SOURCE, TAB_CONTENTS_HTML_DIALOG, TAB_CONTENTS_ABOUT_UI, + TAB_CONTENTS_DEBUGGER, TAB_CONTENTS_NUM_TYPES }; diff --git a/chrome/test/debugger/debugger_unittests.py b/chrome/test/debugger/debugger_unittests.py index bacaa00..bdf22ea 100644 --- a/chrome/test/debugger/debugger_unittests.py +++ b/chrome/test/debugger/debugger_unittests.py @@ -30,7 +30,7 @@ def RunTests(build_dir=None): cmd = [v8_shell, "--allow-natives-syntax", "--expose-debug-as", "debugContext", # these two are together - os.path.join(chrome_dir, "browser", "resources", "debugger_shell.js"), + os.path.join(chrome_dir, "browser", "debugger", "resources", "debugger_shell.js"), os.path.join(v8_dir, "tests", "mjsunit.js"), os.path.join(chrome_dir, "test", "debugger", "test_protocol.js") ] |