diff options
author | dglazkov@google.com <dglazkov@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-23 23:46:13 +0000 |
---|---|---|
committer | dglazkov@google.com <dglazkov@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-12-23 23:46:13 +0000 |
commit | 8d13c8aa8cc2666d20ccbdd949286722310774c7 (patch) | |
tree | 3a7f64d154695389cb1f81202ea1027be98fa3a1 | |
parent | 95037cc520c1c5662d07de4454b055933384f55a (diff) | |
download | chromium_src-8d13c8aa8cc2666d20ccbdd949286722310774c7.zip chromium_src-8d13c8aa8cc2666d20ccbdd949286722310774c7.tar.gz chromium_src-8d13c8aa8cc2666d20ccbdd949286722310774c7.tar.bz2 |
Move port/page/inspector bits to WebCore/inspector (2/2)
Review URL: http://codereview.chromium.org/16253
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@7458 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | webkit/build/V8Bindings/SConscript | 1 | ||||
-rw-r--r-- | webkit/build/V8Bindings/V8Bindings.vcproj | 4 | ||||
-rw-r--r-- | webkit/build/WebCore/SConscript | 2 | ||||
-rw-r--r-- | webkit/build/WebCore/WebCore.vcproj | 12 | ||||
-rw-r--r-- | webkit/build/port/port.vcproj | 12 | ||||
-rw-r--r-- | webkit/port/DerivedSources.make | 2 | ||||
-rw-r--r-- | webkit/port/page/inspector/BASE_REVISION | 1 | ||||
-rw-r--r-- | webkit/port/page/inspector/DebuggerConsole.js | 173 | ||||
-rw-r--r-- | webkit/port/page/inspector/DebuggerIPC.js | 109 | ||||
-rw-r--r-- | webkit/port/page/inspector/DebuggerPanel.js | 201 | ||||
-rw-r--r-- | webkit/port/page/inspector/DebuggerShell.js | 1327 | ||||
-rw-r--r-- | webkit/port/page/inspector/InspectorController.cpp | 1824 | ||||
-rw-r--r-- | webkit/port/page/inspector/InspectorController.idl | 33 | ||||
-rw-r--r-- | webkit/port/page/inspector/debugger.css | 35 | ||||
-rw-r--r-- | webkit/port/page/inspector/debugger.html | 31 |
15 files changed, 21 insertions, 3746 deletions
diff --git a/webkit/build/V8Bindings/SConscript b/webkit/build/V8Bindings/SConscript index 74d147e..a1af82c 100644 --- a/webkit/build/V8Bindings/SConscript +++ b/webkit/build/V8Bindings/SConscript @@ -341,7 +341,6 @@ inputs = [ '$PORT_DIR/bindings/v8/v8_vectornodelist.cpp', '$PORT_DIR/bindings/v8/V8MessagePortCustom.cpp', '$PORT_DIR/bindings/v8/V8XMLHttpRequestCustom.cpp', - '$PORT_DIR/page/inspector/InspectorController.cpp', ] if env.Bit('windows'): diff --git a/webkit/build/V8Bindings/V8Bindings.vcproj b/webkit/build/V8Bindings/V8Bindings.vcproj index bebcad7..83aa56a 100644 --- a/webkit/build/V8Bindings/V8Bindings.vcproj +++ b/webkit/build/V8Bindings/V8Bindings.vcproj @@ -2429,10 +2429,6 @@ > </File> <File - RelativePath="..\..\port\page\inspector\InspectorController.cpp" - > - </File> - <File RelativePath="..\..\port\bindings\v8\JSDOMBinding.cpp" > </File> diff --git a/webkit/build/WebCore/SConscript b/webkit/build/WebCore/SConscript index e4e972d..621898e 100644 --- a/webkit/build/WebCore/SConscript +++ b/webkit/build/WebCore/SConscript @@ -315,6 +315,8 @@ input_files = [ '$WEBCORE_DIR/html/PreloadScanner.cpp', '$WEBCORE_DIR/html/TimeRanges.cpp', + '$WEBCORE_DIR/inspector/InspectorController.cpp', + '$WEBCORE_DIR/loader/Cache.cpp', '$WEBCORE_DIR/loader/CachedCSSStyleSheet.cpp', '$WEBCORE_DIR/loader/CachedFont.cpp', diff --git a/webkit/build/WebCore/WebCore.vcproj b/webkit/build/WebCore/WebCore.vcproj index 62d697d..8a37fd6 100644 --- a/webkit/build/WebCore/WebCore.vcproj +++ b/webkit/build/WebCore/WebCore.vcproj @@ -131,6 +131,18 @@ </References> <Files> <Filter + Name="inspector" + > + <File + RelativePath="..\..\..\third_party\WebKit\WebCore\inspector\InspectorController.cpp" + > + </File> + <File + RelativePath="..\..\..\third_party\WebKit\WebCore\inspector\InspectorController.h" + > + </File> + </Filter> + <Filter Name="page" > <File diff --git a/webkit/build/port/port.vcproj b/webkit/build/port/port.vcproj index ee59035..3db4f3d 100644 --- a/webkit/build/port/port.vcproj +++ b/webkit/build/port/port.vcproj @@ -176,28 +176,28 @@ > </File> <File - RelativePath="..\..\port\page\inspector\debugger.css" + RelativePath="..\..\..\third_party\WebKit\WebCore\inspector\front-end\debugger.css" > </File> <File - RelativePath="..\..\port\page\inspector\debugger.html" + RelativePath="..\..\..\third_party\WebKit\WebCore\inspector\front-end\debugger.html" > </File> <File - RelativePath="..\..\port\page\inspector\DebuggerConsole.js" + RelativePath="..\..\..\third_party\WebKit\WebCore\inspector\front-end\DebuggerConsole.js" > </File> <File - RelativePath="..\..\port\page\inspector\DebuggerIPC.js" + RelativePath="..\..\..\third_party\WebKit\WebCore\inspector\front-end\DebuggerIPC.js" > </File> <File - RelativePath="..\..\port\page\inspector\DebuggerPanel.js" + RelativePath="..\..\..\third_party\WebKit\WebCore\inspector\front-end\DebuggerPanel.js" DeploymentContent="true" > </File> <File - RelativePath="..\..\port\page\inspector\DebuggerShell.js" + RelativePath="..\..\..\third_party\WebKit\WebCore\inspector\front-end\DebuggerShell.js" > </File> <File diff --git a/webkit/port/DerivedSources.make b/webkit/port/DerivedSources.make index bc05efd..167116e 100644 --- a/webkit/port/DerivedSources.make +++ b/webkit/port/DerivedSources.make @@ -27,7 +27,6 @@ VPATH = \ $(PORTROOT)/bindings/v8 \ - $(PORTROOT)/page/inspector \ $(WebCore) \ $(WebCore)/bindings/js \ $(WebCore)/bindings/v8 \ @@ -35,6 +34,7 @@ VPATH = \ $(WebCore)/css \ $(WebCore)/dom \ $(WebCore)/html \ + $(WebCore)/inspector \ $(WebCore)/page \ $(WebCore)/plugins \ $(WebCore)/storage \ diff --git a/webkit/port/page/inspector/BASE_REVISION b/webkit/port/page/inspector/BASE_REVISION deleted file mode 100644 index f14d099..0000000 --- a/webkit/port/page/inspector/BASE_REVISION +++ /dev/null @@ -1 +0,0 @@ -http://svn.webkit.org/repository/webkit/trunk/WebCore/page/inspector@32408 diff --git a/webkit/port/page/inspector/DebuggerConsole.js b/webkit/port/page/inspector/DebuggerConsole.js deleted file mode 100644 index 0ba3b28..0000000 --- a/webkit/port/page/inspector/DebuggerConsole.js +++ /dev/null @@ -1,173 +0,0 @@ -// Copyright (c) 2006-2008 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. - -/** - * @fileoverview Helper functions and objects for the JS debugger UI. - * @see debugger.html - */ - -/** - * Document load listener. - */ -function onLoad() { - var debuggerConsole = new DebuggerConsole(); - DebuggerIPC.init(debuggerConsole); - DebugShell.initDebugShell(debuggerConsole); - debuggerConsole.focusOnCommandLine(); -} - -/** - * @constructor - */ -function DebuggerConsole() -{ - this._output = document.getElementById("output"); - - var input = document.getElementById("command-line-text"); - var self = this; - input.addEventListener( - 'keydown', - function(e) { - return self._onInputKeyDown(e); - }, - true); - input.addEventListener( - 'keypress', - function(e) { - return self._onInputKeyPress(e); - }, - true); - this._commandLineInput = input; - - // command object stores command-line history state. - this._command = { - history: [], - history_index: 0, - pending: null - }; -}; - -DebuggerConsole.prototype = { - /** - * Sets focus to command-line-text element. - */ - focusOnCommandLine: function() { - this._commandLineInput.focus(); - }, - - /** - * Called by chrome code when there's output to display. - * @param {string} txt - */ - appendText: function(txt) - { - this._output.appendChild(document.createTextNode(txt)); - this._output.appendChild(document.createElement('br')); - document.body.scrollTop = document.body.scrollHeight; - }, - - /** - * Called by chrome code to set the current state as to whether the debugger - * is stopped at a breakpoint or is running. - * @param {boolean} isBroken - */ - setDebuggerBreak: function(isBroken) - { - var out = this._output; - if (isBroken) { - out.style.color = "black"; - this.focusOnCommandLine(); - } else { - out.style.color = "gray"; - } - }, - - /** - * Execute a debugger command, add it to the command history and display it in - * the output window. - * @param {string} str - */ - executeCommand: function(str) { - this.appendText("$ " + str); - // Sends message to DebuggerContents.HandleCommand. - if (DebugShell.singleton) { - DebugShell.singleton.command(str); - } else { - this.appendText("FAILED to send the command as DebugShell is null"); - } - - this._command.history.push(str); - this._command.history_index = this._command.history.length; - this._command.pending = null; - }, - - - /** - * Display the previous history item in the given text field. - * @param {HTMLInputElement} field - */ - selectPreviousCommand_: function(field) { - var command = this._command; - 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. - * @param {HTMLInputElement} field - */ - selectNextCommand_: function(field) { - var command = this._command; - 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 onkeydown handler. - * @param {KeyboardEvent} e - * @return {boolean} - */ - _onInputKeyDown: function (e) { - var field = e.target; - var key = e.keyCode; - if (key == 38) { // up arrow - this.selectPreviousCommand_(field); - return false; - } else if (key == 40) { // down arrow - this.selectNextCommand_(field); - return false; - } - return true; - }, - - /** - * command-line-text's onkeypress handler. - * @param {KeyboardEvent} e - * @return {boolean} - */ - _onInputKeyPress: function (e) { - var field = e.target; - var key = e.keyCode; - if (key == 13) { // enter - this.executeCommand(field.value); - field.value = ""; - return false; - } - return true; - } -}; diff --git a/webkit/port/page/inspector/DebuggerIPC.js b/webkit/port/page/inspector/DebuggerIPC.js deleted file mode 100644 index 15835fc..0000000 --- a/webkit/port/page/inspector/DebuggerIPC.js +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2006-2008 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. - -/** - * @fileoverview Implementation of debugger inter-process communication. - * Debugger UI can send messages to the DebuggerHost object living in - * Chrome browser process. The messages are either processed by DebuggerHost - * itself or trigger IPC message(such as break, evaluate script etc) from - * browser process to the renderer where the v8 instance being debugged - * will process them. - */ - -var DebuggerIPC = {}; - -/** - * Set up default debugger UI. - * @param {DebuggerPanel|DebuggerConsole} debuggerUI - */ -DebuggerIPC.init = function(debuggerUI) { - DebuggerIPC.debuggerUI = debuggerUI; -} - -/** - * Sends JSON message to DebuggerHost. - * @param {Array.<Object>} nameAndArguments - */ -DebuggerIPC.sendMessage = function(nameAndArguments) { - //alert("DebuggerIPC.sendMessage " + nameAndArguments); - dprint("DebuggerIPC.callMethod([" + nameAndArguments + "])"); - // convert all arguments to strings - // TODO(yurys): extend chrome.send to accept array of any value - // objects not only strings - for (var i = 0; i < nameAndArguments.length; i++) { - if (typeof nameAndArguments[i] != "string") { - nameAndArguments[i] = "" + nameAndArguments[i]; - } - } - - chrome.send("DebuggerHostMessage", nameAndArguments); -}; - -/** - * Handles messages from DebuggerHost. - * @param {Object} msg An object representing the message. - */ -DebuggerIPC.onMessageReceived = function(msg) { - //alert("DebuggerIPC.onMessageReceived " + msg.event); - var ui = DebuggerIPC.debuggerUI; - dprint("onMessageReceived: " + (msg && msg.event)); - if (msg.type == "event") { - if (msg.event == "setDebuggerBreak") { - var val = msg.body.argument; - ui.setDebuggerBreak(val); - } else if (msg.event == "appendText") { - var text = msg.body.text; - ui.appendText(text); - } else if (msg.event == "focusOnCommandLine") { - dprint("focusOnCommandLine event received"); - // messages to DebugShell - } else if (msg.event == "initDebugShell") { - // DebugShell.initDebugShell(); - dprint(msg.event + " done"); - } else if (msg.event == "on_attach") { - if (DebugShell.singleton) { - var args = msg.body.arguments; - if (!args || args.length != 1) { - dprint(msg.event + " failed: invalid arguments"); - return; - } - var title = args[0]; - DebugShell.singleton.on_attach(title); - dprint(msg.event + " done"); - } else { - dprint(msg.event + " failed: DebugShell.singleton == null"); - } - } else if (msg.event == "on_disconnect") { - if (DebugShell.singleton) { - DebugShell.singleton.on_disconnect(); - dprint(msg.event + " done"); - } else { - dprint(msg.event + " failed: DebugShell.singleton == null"); - } - } else if (msg.event == "exit") { - if (DebugShell.singleton) { - DebugShell.singleton.exit(); - dprint(msg.event + " done"); - } else { - dprint(msg.event + " failed: DebugShell.singleton == null"); - } - } else if (msg.event == "response") { - if (DebugShell.singleton) { - var args = msg.body.arguments; - if (!args || args.length != 1) { - dprint(msg.event + " failed: invalid argument"); - return; - } - DebugShell.singleton.response(args[0]); - dprint(msg.event + " done"); - } else { - ui.appendText(msg.event + " failed: DebugShell.singleton == null"); - } - } else { - ui.appendText("Unknown event: " + msg.event); - } - } else { - ui.appendText("Unknown message type: " + msg.type); - } -}; diff --git a/webkit/port/page/inspector/DebuggerPanel.js b/webkit/port/page/inspector/DebuggerPanel.js deleted file mode 100644 index bb059ac..0000000 --- a/webkit/port/page/inspector/DebuggerPanel.js +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (c) 2006-2008 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. - -/** - * @fileoverview WebInspector panel representing command line debugger. - */ - -/** - * Command line debugger panel. - * @constructor - * @extends {WebInspector.Panel} - */ -WebInspector.DebuggerPanel = function() -{ - WebInspector.Panel.call(this); - - this.contentElement = document.createElement("div"); - this.contentElement.id = "debugger-content"; - - var table = document.createElement("table"); - table.id = 'outer'; - var tr = document.createElement("tr"); - this._output = document.createElement("td"); - this._output.id = "output"; - this._output.valign = "bottom"; - this.appendText("Chrome JavaScript Debugger"); - this.appendText("Type 'help' for a list of commands."); - - tr.appendChild(this._output); - table.appendChild(tr); - this.contentElement.appendChild(table); - - - var commandLine = document.createElement("div"); - commandLine.id = "command-line"; - var input = document.createElement("input"); - input.id = "command-line-text"; - input.addEventListener('keydown', this._onInputKeyDown.bind(this), true); - input.addEventListener('keypress', this._onInputKeyPress.bind(this), true); - input.type = "text"; - this.commandLineInput_ = input; - - commandLine.appendChild(input); - this.contentElement.appendChild(commandLine); - - // command object stores command-line history state. - this._command = { - history: [], - history_index: 0, - pending: null - }; - - this.element.appendChild(this.contentElement); - p('DebuggerPanel created'); -}; - -WebInspector.DebuggerPanel.prototype = { - toolbarItemClass: "debugger", - - get toolbarItemLabel() - { - return "Debugger"; //WebInspector.UIString("Debugger"); - }, - - show: function() - { - WebInspector.Panel.prototype.show.call(this); - this.focusOnCommandLine(); - }, - - /** - * Sets focus to command-line-text element. - */ - focusOnCommandLine: function() - { - if (this.visible) { - this.commandLineInput_.focus(); - } - }, - - /** - * Called by chrome code when there's output to display. - * @param {string} txt - */ - appendText: function(txt) - { - this._output.appendChild(document.createTextNode(txt)); - this._output.appendChild(document.createElement('br')); - }, - - /** - * Called by chrome code to set the current state as to whether the debugger - * is stopped at a breakpoint or is running. - * @param {boolean} isBroken - */ - setDebuggerBreak: function(isBroken) - { - var out = this._output; - if (isBroken) { - out.style.color = "black"; - this.focusOnCommandLine(); - } else { - out.style.color = "gray"; - } - }, - - /** - * Execute a debugger command, add it to the command history and display - * it in the output window. - * @param {string} str - */ - executeCommand: function(str) - { - this.appendText("$ " + str); - // Sends message to DebuggerContents.HandleCommand. - if (DebugShell.singleton) { - DebugShell.singleton.command(str); - } else { - this.appendText("FAILED to send the command as DebugShell is null"); - } - - this._command.history.push(str); - this._command.history_index = this._command.history.length; - this._command.pending = null; - }, - - /** - * Display the previous history item in the given text field. - * @param {HTMLInputElement} field - */ - _selectPreviousCommand: function(field) - { - var command = this._command; - 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. - * @param {HTMLInputElement} field - */ - _selectNextCommand: function(field) - { - var command = this._command; - 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 onkeydown handler. - * @param {KeyboardEvent} e - * @return {boolean} - */ - _onInputKeyDown: function (e) - { - var field = e.target; - var key = e.keyCode; - if (key == 38) { // up arrow - this._selectPreviousCommand(field); - return false; - } else if (key == 40) { // down arrow - this._selectNextCommand(field); - return false; - } - return true; - }, - - /** - * command-line-text's onkeypress handler. - * @param {KeyboardEvent} e - * @return {boolean} - */ - _onInputKeyPress: function (e) - { - var field = e.target; - var key = e.keyCode; - if (key == 13) { // enter - this.executeCommand(field.value); - field.value = ""; - return false; - } - return true; - } -}; - -WebInspector.DebuggerPanel.prototype.__proto__ = WebInspector.Panel.prototype; diff --git a/webkit/port/page/inspector/DebuggerShell.js b/webkit/port/page/inspector/DebuggerShell.js deleted file mode 100644 index 804bb9a..0000000 --- a/webkit/port/page/inspector/DebuggerShell.js +++ /dev/null @@ -1,1327 +0,0 @@ -// Copyright (c) 2006-2008 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. - -/** - * @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. - */ - -// 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. - */ -DebugCommand.next_seq_ = 0; - -/** - * Command messages to be sent to the debugger. - * @constructor - */ -function DebugCommand(str) { - this.command = undefined; - // first, strip off of the leading word as the command - var argv = str.split(' '); - this.user_command = argv.shift(); - // the rest of the string is argv to the command - str = argv.join(' '); - if (DebugCommand.aliases[this.user_command]) - this.user_command = DebugCommand.aliases[this.user_command]; - if (this.parseArgs_(str) == 1) - this.type = "request"; - if (this.command == undefined) - this.command = this.user_command; -}; - -// Mapping of some control characters to avoid the \uXXXX syntax for most -// commonly used control cahracters. -const ctrlCharMap_ = { - '\b': '\\b', - '\t': '\\t', - '\n': '\\n', - '\f': '\\f', - '\r': '\\r', - '"' : '\\"', - '\\': '\\\\' -}; - -// Regular expression matching ", \ and control characters (0x00 - 0x1F) -// globally. -const ctrlCharMatch_ = /["\\\\\x00-\x1F]/g; - -/** - * Convert a String to its JSON representation. - * @param {String} value - String to be converted - * @return {String} JSON formatted String - */ -DebugCommand.stringToJSON = function(value) { - // Check for" , \ and control characters (0x00 - 0x1F). - if (ctrlCharMatch_.test(value)) { - // Replace ", \ and control characters (0x00 - 0x1F). - return '"' + value.replace(ctrlCharMatch_, function (char) { - // Use charmap if possible. - var mapped = ctrlCharMap_[char]; - if (mapped) return mapped; - mapped = char.charCodeAt(); - // Convert control character to unicode escape sequence. - var dig1 = (Math.floor(mapped / 16)); - var dig2 = (mapped % 16) - return '\\u00' + dig1.toString(16) + dig2.toString(16); - }) - + '"'; - } - - // Simple string with no special characters. - return '"' + value + '"'; -}; - -/** - * @return {bool} True if x is an integer. - */ -DebugCommand.isInt = function(x) { - var y = parseInt(x); - if (isNaN(y)) - return false; - return x == y && x.toString() == y.toString(); -}; - -/** - * @return {float} log base 10 of num - */ -DebugCommand.log10 = function(num) { - return Math.log(num)/Math.log(10); -}; - -/** - * Take an object and encode it (non-recursively) as a JSON dict. - * @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 += '}'; - return json; -}; - -/** - * Encode the DebugCommand object into the V8 debugger JSON protocol format. - */ -DebugCommand.prototype.toJSONProtocol = function() { - // TODO(erikkay): use a real JSON library - var json = '{'; - json += '"seq":"' + this.seq; - json += '","type":"' + this.type; - json += '","command":"' + this.command + '"'; - if (this.arguments) { - json += ',"arguments":' + DebugCommand.toJSON(this.arguments); - } - json += '}' - return json; -} - -/** - * Encode the contents of this message and send it to the debugger. - * @param {Object} tab - tab being debugged. This is an internal - * Chrome object. - */ -DebugCommand.prototype.sendToDebugger = function(tab) { - this.seq = DebugCommand.next_seq_++; - str = this.toJSONProtocol(); - dprint("sending: " + str); - tab.sendToDebugger(str); -}; - -DebugCommand.trim = function(str) { - return str.replace(/^\s*/, '').replace(/\s*$/, ''); -}; - -/** - * Strip off a trailing parameter after a ':'. As the identifier for the - * source can contain ':' characters (e.g. 'http://www....) something after - * a ':' is only considered a parameter if it is numeric. - * @return {Array} two element array, the trimmed string and the parameter, - * or -1 if no parameter - */ -DebugCommand.stripTrailingParameter = function(str, opt_separator) { - var sep = opt_separator || ':'; - var index = str.lastIndexOf(sep); - // If a separator character if found strip if numeric. - if (index != -1) { - var value = parseInt(str.substring(index + 1, str.length), 10); - if (isNaN(value) || value < 0) { - return [str, -1]; - } - str = str.substring(0, index); - return [str, value]; - } - return [str, -1]; -}; - -/** - * Format source and location strings based on source location input data. - * @param {Object} script - script information object - * @param {String} source - source code for the current location - * @param {int} line - line number (0-based) - * @param {String} func - function name - * @return {array} [location(string), source line(string), line number(int)] - */ -DebugCommand.getSourceLocation = function(script, source, line, func) { - // source line is 0-based, we present as 1-based - line++; - - // TODO(erikkay): take column into account as well - if (source) - source = "" + line + ": " + source; - var location = ''; - if (func) { - location = func + ", "; - } - location += script ? script.name : '[no source]'; - return [location, source, line]; -}; - -/** - * Aliases for debugger commands. - */ -DebugCommand.aliases = { - 'b': 'break', - 'bi': 'break_info', - 'br': 'break', - 'bt': 'backtrace', - 'c': 'continue', - 'f': 'frame', - 'h': 'help', - '?': 'help', - 'ls': 'source', - 'n': 'next', - 'p': 'print', - 's': 'step', - 'so': 'stepout', -}; - -/** - * Parses arguments to "args" and "locals" command, and initializes - * the underlying DebugCommand (which is a frame request). - * @see DebugCommand.commands - * @param {string} str The arguments to be parsed. - * @return -1 for usage error, 1 for success - */ -DebugCommand.prototype.parseArgsAndLocals_ = function(str) { - this.command = "frame"; - return str.length ? -1 : 1; -}; - -/** - * Parses arguments to "break_info" command, and executes it. - * "break_info" has an optional argument, which is the breakpoint - * identifier. - * @see DebugCommand.commands - * @param {string} str - The arguments to be parsed. - * @return -1 for usage error, 0 for success - */ -DebugCommand.prototype.parseBreakInfo_ = function(str) { - this.type = "shell"; - - // Array of breakpoints to be printed by this command - // (default to all breakpoints) - var breakpointsToPrint = shell_.breakpoints; - - if (str.length > 0) { - // User specified an invalid breakpoint (not a number) - if (!str.match(/^\s*\d+\s*$/)) - return -1; // invalid usage - - // Check that the specified breakpoint identifier exists - var id = parseInt(str); - var info = shell_.breakpoints[id]; - if (!info) { - print("Error: Invalid breakpoint"); - return 0; // success (of sorts) - } - breakpointsToPrint = [info]; - } else { - // breakpointsToPrint.length isn't accurate, because of - // deletions - var num_breakpoints = 0; - for (var i in breakpointsToPrint) num_breakpoints++; - - print("Num breakpoints: " + num_breakpoints); - } - - DebugShell.printBreakpoints_(breakpointsToPrint); - - return 0; // success -} - -/** - * Parses arguments to "step" command. - * @see DebugCommand.commands - * @param {string} str The arguments to be parsed. - * @return -1 for usage error, 1 for success - */ -DebugCommand.prototype.parseStep_ = function(str, opt_stepaction) { - this.command = "continue"; - action = opt_stepaction || "in"; - this.arguments = {"stepaction" : action} - if (str.length) { - count = parseInt(str); - if (count > 0) { - this.arguments["stepcount"] = count; - } else { - return -1; - } - } - return 1; -}; - -/** - * Parses arguments to "step" command. - * @see DebugCommand.commands - * @param {string} str The arguments to be parsed. - * @return -1 for usage error, 1 for success - */ -DebugCommand.prototype.parseStepOut_ = function(str) { - return this.parseStep_(str, "out"); -}; - -/** - * Parses arguments to "next" command. - * @see DebugCommand.commands - * @param {string} str The arguments to be parsed. - * @return -1 for usage error, 1 for success - */ -DebugCommand.prototype.parseNext_ = function(str) { - return this.parseStep_(str, "next"); -}; - -/** - * Parse the arguments to "print" command. - * @see DebugCommand.commands - * @param {string} str The arguments to be parsed. - * @return 1 - always succeeds - */ -DebugCommand.prototype.parsePrint_ = function(str) { - this.command = "evaluate"; - this.arguments = { "expression" : str }; - // If the page is in the running state, then we force the expression to - // evaluate in the global context to avoid evaluating in a random context. - if (shell_.running) - this.arguments["global"] = true; - return 1; -}; - -/** - * Handle the response to a "print" command and display output to user. - * @param {Object} msg - the V8 debugger response object - */ -DebugCommand.responsePrint_ = function(msg) { - body = msg["body"]; - if (body['text'] != undefined) { - print(body['text']); - } else { - // TODO(erikkay): is "text" ever not set? - print("can't print response"); - } -}; - -/** - * Parses arguments to "break" command. See DebugCommand.commands below - * for syntax details. - * @see DebugCommand.commands - * @param {string} str The arguments to be parsed. - * @return -1 for usage error, 1 for success, 0 for handled internally - */ -DebugCommand.prototype.parseBreak_ = function(str) { - function stripTrailingParameter() { - var ret = DebugCommand.stripTrailingParameter(str, ':'); - str = ret[0]; - return ret[1]; - } - - if (str.length == 0) { - this.command = "break"; - return 1; - } else { - var parts = str.split(/\s+/); - var condition = null; - if (parts.length > 1) { - str = parts.shift(); - condition = parts.join(" "); - } - - this.command = "setbreakpoint"; - - // Locate ...[:line[:column]] if present. - var line = -1; - var column = -1; - line = stripTrailingParameter(); - if (line != -1) { - line -= 1; - var l = stripTrailingParameter(); - if (l != -1) { - column = line; - line = l - 1; - } - } - - if (line == -1 && column == -1) { - this.arguments = { 'type' : 'function', - 'target' : str }; - } else { - var script = shell_.matchScript(str, line); - if (script) { - this.arguments = { 'type' : 'script', - 'target' : script.name }; - } else { - this.arguments = { 'type' : 'function', - 'target' : str }; - } - this.arguments.line = line; - if (column != -1) - this.arguments.position = column; - } - if (condition) - this.arguments.condition = condition; - } - return 1; -}; - -/** - * Handle the response to a "break" command and display output to user. - * @param {Object} msg - the V8 debugger response object - */ -DebugCommand.responseBreak_ = function(msg) { - var info = new BreakpointInfo( - parseInt(msg.body.breakpoint), - msg.command.arguments.type, - msg.command.arguments.target, - msg.command.arguments.line, - msg.command.arguments.position, - msg.command.arguments.condition); - shell_.addedBreakpoint(info); -}; - -/** - * Parses arguments to "backtrace" command. See DebugCommand.commands below - * for syntax details. - * @see DebugCommand.commands - * @param {string} str The arguments to be parsed. - * @return -1 for usage error, 1 for success - */ - DebugCommand.prototype.parseBacktrace_ = function(str) { - if (str.length > 0) { - var parts = str.split(/\s+/); - var non_empty_parts = parts.filter(function(s) { return s.length > 0; }); - // We need exactly two arguments. - if (non_empty_parts.length != 2) { - return -1; - } - var from = parseInt(non_empty_parts[0], 10); - var to = parseInt(non_empty_parts[1], 10); - // The two arguments have to be integers. - if (from != non_empty_parts[0] || to != non_empty_parts[1]) { - return -1; - } - this.arguments = { 'fromFrame': from, 'toFrame': to + 1 }; - } else { - // Default to fetching the first 10 frames. - this.arguments = { 'fromFrame': 0, 'toFrame': 10 }; - } - return 1; -}; - -/** - * Handle the response to a "backtrace" command and display output to user. - * @param {Object} msg - the V8 debugger response object - */ -DebugCommand.responseBacktrace_ = function(msg) { - body = msg["body"]; - if (body && body.totalFrames) { - print('Frames #' + body.fromFrame + ' to #' + (body.toFrame - 1) + - ' of ' + body.totalFrames + ":"); - for (var i = 0; i < body.frames.length; i++) { - print(body.frames[i].text); - } - } else { - print("unimplemented (sorry)"); - } -}; - - -/** - * Parses arguments to "clear" command. See DebugCommand.commands below - * for syntax details. - * @see DebugCommand.commands - * @param {string} str The arguments to be parsed. - * @return -1 for usage error, 1 for success - */ -DebugCommand.prototype.parseClearCommand_ = function(str) { - this.command = "clearbreakpoint"; - if (str.length > 0) { - var i = parseInt(str, 10); - if (i != str) { - return -1; - } - this.arguments = { 'breakpoint': i }; - } - return 1; -} - -/** - * Handle the response to a "clear" command and display output to user. - * @param {Object} msg - the V8 debugger response object - */ -DebugCommand.responseClear_ = function(msg) { - shell_.clearedBreakpoint(parseInt(msg.command.arguments.breakpoint)); -} - - -/** - * Parses arguments to "continue" command. See DebugCommand.commands below - * for syntax details. - * @see DebugCommand.commands - * @param {string} str The arguments to be parsed. - * @return -1 for usage error, 1 for success - */ -DebugCommand.prototype.parseContinueCommand_ = function(str) { - this.command = "continue"; - if (str.length > 0) { - return -1; - } - return 1; -} - -/** - * Parses arguments to "frame" command. See DebugCommand.commands below - * for syntax details. - * @see DebugCommand.commands - * @param {string} str The arguments to be parsed. - * @return -1 for usage error, 1 for success - */ -DebugCommand.prototype.parseFrame_ = function(str) { - if (str.length > 0) { - var i = parseInt(str, 10); - if (i != str) { - return -1; - } - this.arguments = { 'number': i }; - } - return 1; -}; - -/** - * Handle the response to a "frame" command and display output to user. - * @param {Object} msg - the V8 debugger response object - */ -DebugCommand.responseFrame_ = function(msg) { - body = msg.body; - loc = DebugCommand.getSourceLocation(body.func.script, - body.sourceLineText, body.line, body.func.name); - print("#" + (body.index <= 9 ? '0' : '') + body.index + " " + loc[0]); - print(loc[1]); - shell_.current_frame = body.index; - shell_.current_line = loc[2]; - shell_.current_script = body.func.script; -}; - -/** - * Handle the response to a "args" command and display output to user. - * @param {Object} msg - the V8 debugger response object (for "frame" command) - */ -DebugCommand.responseArgs_ = function(msg) { - DebugCommand.printVariables_(msg.body.arguments); -} - -/** - * Handle the response to a "locals" command and display output to user. - * @param {Object} msg - the V8 debugger response object (for "frame" command) - */ -DebugCommand.responseLocals_ = function(msg) { - DebugCommand.printVariables_(msg.body.locals); -} - -DebugCommand.printVariables_ = function(variables) { - for (var i = 0; i < variables.length; i++) { - print(variables[i].name + " = " + - DebugCommand.toPreviewString_(variables[i].value)); - } -} - -DebugCommand.toPreviewString_ = function(value) { - // TODO(ericroman): pretty print arrays and objects, recursively. - // TODO(ericroman): truncate length of preview if too long? - if (value.type == "string") { - // Wrap the string in quote marks and JS-escape - return DebugCommand.stringToJSON(value.text); - } - return value.text; -} - -/** - * Parses arguments to "scripts" command. - * @see DebugCommand.commands - * @param {string} str - The arguments to be parsed. - * @return -1 for usage error, 1 for success - */ -DebugCommand.prototype.parseScripts_ = function(str) { - return 1 -}; - -/** - * Handle the response to a "scripts" command and display output to user. - * @param {Object} msg - the V8 debugger response object - */ -DebugCommand.responseScripts_ = function(msg) { - scripts = msg.body; - shell_.scripts = []; - for (var i in scripts) { - var script = scripts[i]; - - // Add this script to the internal list of scripts. - shell_.scripts.push(script); - - // Print result if this response was the result of a user command. - if (msg.command.from_user) { - var name = script.name; - if (name) { - if (script.lineOffset > 0) { - print(name + " (lines " + script.lineOffset + "-" + - (script.lineOffset + script.lineCount - 1) + ")"); - } else { - print(name + " (lines " + script.lineCount + ")"); - } - } else { - // For unnamed scripts (typically eval) display some source. - var sourceStart = script.sourceStart; - if (sourceStart.length > 40) - sourceStart = sourceStart.substring(0, 37) + '...'; - print("[unnamed] (source:\"" + sourceStart + "\")"); - } - } - } -}; - -/** - * Parses arguments to "source" command. - * @see DebugCommand.commands - * @param {string} str - The arguments to be parsed. - * @return -1 for usage error, 1 for success - */ -DebugCommand.prototype.parseSource_ = function(str) { - this.arguments = {}; - if (this.current_frame > 0) - this.arguments.frame = this.current_frame; - if (str.length) { - var args = str.split(" "); - if (args.length == 1) { - // with 1 argument n, we print 10 lines starting at n - var num = parseInt(args[0]); - if (num > 0) { - this.arguments.fromLine = num - 1; - this.arguments.toLine = this.arguments.fromLine + 10; - } else { - return -1; - } - } else if (args.length == 2) { - // with 2 arguments x and y, we print from line x to line x + y - var from = parseInt(args[0]); - var len = parseInt(args[1]); - if (from > 0 && len > 0) { - this.arguments.fromLine = from - 1; - this.arguments.toLine = this.arguments.fromLine + len; - } else { - return -1; - } - } else { - return -1; - } - if (this.arguments.fromLine < 0) - return -1; - if (this.arguments.toLine <= this.arguments.fromLine) - return -1; - } else if (shell_.current_line > 0) { - // with no arguments, we print 11 lines with the current line as the center - this.arguments.fromLine = - Math.max(0, shell_.current_line - 6); - this.arguments.toLine = this.arguments.fromLine + 11; - } - return 1; -}; - -/** - * Handle the response to a "source" command and display output to user. - * @param {Object} msg - the V8 debugger response object - */ -DebugCommand.responseSource_ = function(msg) { - var body = msg.body; - var from_line = parseInt(body.fromLine) + 1; - var source = body.source; - var lines = source.split('\n'); - var maxdigits = 1 + Math.floor(DebugCommand.log10(from_line + lines.length)) - for (var num in lines) { - // there's an extra newline at the end - if (num >= (lines.length - 1) && lines[num].length == 0) - break; - spacer = maxdigits - (1 + Math.floor(DebugCommand.log10(from_line))) - var line = ""; - if (from_line == shell_.current_line) { - for (var i = 0; i < (maxdigits + 2); i++) - line += ">"; - } else { - for (var i = 0; i < spacer; i++) - line += " "; - line += from_line + ": "; - } - line += lines[num]; - print(line); - from_line++; - } -}; - -/** - * Parses arguments to "help" command. See DebugCommand.commands below - * for syntax details. - * @see DebugCommand.commands - * @param {string} str The arguments to be parsed. - * @return 0 for handled internally - */ -DebugCommand.parseHelp_ = function(str) { - DebugCommand.help(str); - return 0; -}; - -/** - * Takes argument and evaluates it in the context of the shell to allow commands - * to be escaped to the outer shell. Used primarily for development purposes. - * @see DebugCommand.commands - * @param {string} str The expression to be evaluated - * @return 0 for handled internally - */ -DebugCommand.parseShell_ = function(str) { - print(eval(str)); - return 0; -} - -DebugCommand.parseShellDebug_ = function(str) { - shell_.debug = !shell_.debug; - if (shell_.debug) { - print("shell debugging enabled"); - } else { - print("shell debugging disabled"); - } - return 0; -} - -/** - * Parses a user-entered command string. - * @param {string} str The arguments to be parsed. - */ -DebugCommand.prototype.parseArgs_ = function(str) { - if (str.length) - str = DebugCommand.trim(str); - var cmd = DebugCommand.commands[this.user_command]; - if (cmd) { - var parse = cmd['parse']; - if (parse == undefined) { - print('>>>can\'t find parse func for ' + this.user_command); - this.type = "error"; - } else { - var ret = parse.call(this, str); - if (ret > 0) { - // Command gererated a debugger request. - this.type = "request"; - } else if (ret == 0) { - // Command handeled internally. - this.type = "handled"; - } else if (ret < 0) { - // Command error. - this.type = "handled"; - DebugCommand.help(this.user_command); - } - } - } else { - this.type = "handled"; - print('unknown command: ' + this.user_command); - DebugCommand.help(); - } -}; - -/** - * Displays command help or all help. - * @param {string} opt_str Which command to print help for. - */ -DebugCommand.help = function(opt_str) { - if (opt_str) { - var cmd = DebugCommand.commands[opt_str]; - var usage = cmd.usage; - print('usage: ' + usage); - // Print additional details for the command. - if (cmd.help) { - print(cmd.help); - } - } else { - if (shell_.running) { - print('Status: page is running'); - } else { - print('Status: page is paused'); - } - print('Available commands:'); - for (var key in DebugCommand.commands) { - var cmd = DebugCommand.commands[key]; - if (!cmd['hidden'] && (!shell_.running || cmd['while_running'])) { - var usage = cmd.usage; - print(' ' + usage); - } - } - } -}; - -/** - * Valid commands, their argument parser and their associated usage text. - */ -DebugCommand.commands = { - 'args': { 'parse': DebugCommand.prototype.parseArgsAndLocals_, - 'usage': 'args', - 'help': 'summarize the arguments to the current function.', - 'response': DebugCommand.responseArgs_ }, - 'break': { 'parse': DebugCommand.prototype.parseBreak_, - 'response': DebugCommand.responseBreak_, - 'usage': 'break [location] <condition>', - 'help': 'location is one of <function> | <script:function> | <script:line> | <script:line:pos>', - 'while_running': true }, - 'break_info': { 'parse': DebugCommand.prototype.parseBreakInfo_, - 'usage': 'break_info [breakpoint #]', - 'help': 'list the current breakpoints, or the details on a single one', - 'while_running': true }, - 'backtrace': { 'parse': DebugCommand.prototype.parseBacktrace_, - 'response': DebugCommand.responseBacktrace_, - 'usage': 'backtrace [from frame #] [to frame #]' }, - 'clear': { 'parse': DebugCommand.prototype.parseClearCommand_, - 'response': DebugCommand.responseClear_, - 'usage': 'clear <breakpoint #>', - 'while_running': true }, - 'continue': { 'parse': DebugCommand.prototype.parseContinueCommand_, - 'usage': 'continue' }, - 'frame': { 'parse': DebugCommand.prototype.parseFrame_, - 'response': DebugCommand.responseFrame_, - 'usage': 'frame <frame #>' }, - 'help': { 'parse': DebugCommand.parseHelp_, - 'usage': 'help [command]', - 'while_running': true }, - 'locals': { 'parse': DebugCommand.prototype.parseArgsAndLocals_, - 'usage': 'locals', - 'help': 'summarize the local variables for current frame', - 'response': DebugCommand.responseLocals_ }, - 'next': { 'parse': DebugCommand.prototype.parseNext_, - 'usage': 'next' } , - 'print': { 'parse': DebugCommand.prototype.parsePrint_, - 'response': DebugCommand.responsePrint_, - 'usage': 'print <expression>', - 'while_running': true }, - 'scripts': { 'parse': DebugCommand.prototype.parseScripts_, - 'response': DebugCommand.responseScripts_, - 'usage': 'scripts', - 'while_running': true }, - 'source': { 'parse': DebugCommand.prototype.parseSource_, - 'response': DebugCommand.responseSource_, - 'usage': 'source [from line] | [<from line> <num lines>]' }, - 'step': { 'parse': DebugCommand.prototype.parseStep_, - 'usage': 'step' }, - 'stepout': { 'parse': DebugCommand.prototype.parseStepOut_, - 'usage': 'stepout' }, - // local eval for debugging - remove this later - 'shell': { 'parse': DebugCommand.parseShell_, - 'usage': 'shell <expression>', - 'while_running': true, - 'hidden': true }, - 'shelldebug': { 'parse': DebugCommand.parseShellDebug_, - 'usage': 'shelldebug', - 'while_running': true, - 'hidden': true }, -}; - - -/** - * Debug shell using the new JSON protocol - * @param {Object} tab - which tab is to be debugged. This is an internal - * Chrome object. - * @constructor - */ -function DebugShell(tab) { - this.tab = tab; - this.tab.attach(); - this.ready = true; - this.running = true; - this.current_command = undefined; - this.pending_commands = []; - // The auto continue flag is used to indicate whether the JavaScript execution - // should automatically continue after a break event and the processing of - // pending commands. This is used to make it possible for the user to issue - // commands, e.g. setting break points, without making an explicit break. In - // this case the debugger will silently issue a forced break issue the command - // and silently continue afterwards. - this.auto_continue = false; - this.debug = false; - this.last_msg = undefined; - this.current_line = -1; - this.current_pos = -1; - this.current_frame = 0; - this.current_script = undefined; - this.scripts = []; - - // Mapping of breakpoints id --> info. - // Must use numeric keys. - this.breakpoints = []; -}; - -DebugShell.prototype.set_ready = function(ready) { - if (ready != this.ready) { - this.ready = ready; - ChromeNode.setDebuggerReady(this.ready); - } -}; - -DebugShell.prototype.set_running = function(running) { - if (running != this.running) { - this.running = running; - ChromeNode.setDebuggerBreak(!this.running); - } -}; - -/** - * Execute a constructed DebugCommand object if possible, otherwise pend. - * @param cmd {DebugCommand} - command to execute - */ -DebugShell.prototype.process_command = function(cmd) { - dprint("Running: " + (this.running ? "yes" : "no")); - - // The "break" commands needs to be handled seperatly - if (cmd.command == "break") { - if (this.running) { - // Schedule a break. - print("Stopping JavaScript execution..."); - this.tab.debugBreak(false); - } else { - print("JavaScript execution already stopped."); - } - return; - } - - // If page is running an break needs to be issued. - if (this.running) { - // Some requests are not valid when the page is running. - var cmd_info = DebugCommand.commands[cmd.user_command]; - if (!cmd_info['while_running']) { - print(cmd.user_command + " can only be run while paused"); - return; - } - - // Add the command as pending before scheduling a break. - this.pending_commands.push(cmd); - dprint("pending command: " + cmd.toJSONProtocol()); - - // Schedule a forced break and enable auto continue. - this.tab.debugBreak(true); - this.auto_continue = true; - this.set_ready(false); - return; - } - - // If waiting for a response add command as pending otherwise send the - // command. - if (this.current_command) { - this.pending_commands.push(cmd); - dprint("pending command: " + cmd.toJSONProtocol()); - } else { - this.current_command = cmd; - cmd.sendToDebugger(this.tab); - this.set_ready(false); - } -}; - -/** - * Handle a break event from the debugger. - * @param msg {Object} - event protocol message to handle - */ -DebugShell.prototype.event_break = function(msg) { - this.current_frame = 0; - this.set_running(false); - if (msg.body) { - var body = msg.body; - this.current_script = body.script; - var loc = DebugCommand.getSourceLocation(body.script, - body.sourceLineText, body.sourceLine, body.invocationText); - var location = loc[0]; - var source = loc[1]; - this.current_line = loc[2]; - if (msg.body.breakpoints) { - // Always disable auto continue if a real break point is hit. - this.auto_continue = false; - var breakpoints = msg.body.breakpoints; - print("paused at breakpoint " + breakpoints.join(",") + ": " + - location); - for (var i = 0; i < breakpoints.length; i++) - this.didHitBreakpoint(parseInt(breakpoints[i])); - } else if (body.scriptData == "") { - print("paused"); - } else { - // step, stepout, next, "break" and a "debugger" line in the code - // are all treated the same (they're not really distinguishable anyway) - if (location != this.last_break_location) { - // We only print the location (function + script) when it changes, - // so as we step, you only see the source line when you transition - // to a new script and/or function. Also if auto continue is enables - // don't print the break location. - if (!this.auto_continue) - print(location); - } - } - // Print th current source line unless auto continue is enabled. - if (source && !this.auto_continue) - print(source); - this.last_break_location = location; - } - if (!this.auto_continue) - this.set_ready(true); -}; - -/** - * Handle an exception event from the debugger. - * @param msg {Object} - event protocol message to handle - */ -DebugShell.prototype.event_exception = function(msg) { - this.set_running(false); - this.set_ready(true); - if (msg.body) { - if (msg.body["uncaught"]) { - print("uncaught exception " + msg.body["exception"].text); - } else { - print("paused at exception " + msg.body["exception"].text); - } - } -}; - -DebugShell.prototype.matchScript = function(script_match, line) { - var script = null; - // In the v8 debugger, all scripts have a name, line offset and line count - // Script names are usually URLs which are a pain to have to type again and - // again, so we match the tail end of the script name. This makes it easy - // to type break foo.js:23 rather than - // http://www.foo.com/bar/baz/quux/test/foo.js:23. In addition to the tail - // of the name we also look at the lines the script cover. If there are - // several scripts with the same tail including the requested line we match - // the first one encountered. - // TODO(sgjesse) Find how to handle several matching scripts. - var candidate_scripts = []; - for (var i in this.scripts) { - if (this.scripts[i].name && - this.scripts[i].name.indexOf(script_match) >= 0) { - candidate_scripts.push(this.scripts[i]); - } - } - for (var i in candidate_scripts) { - var s = candidate_scripts[i]; - var from = s.lineOffset; - var to = from + s.lineCount; - if (from <= line && line < to) { - script = s; - break; - } - } - if (script) - return script; - else - return null; -} - -// The Chrome Subshell interface requires: -// prompt(), command(), response(), exit() and on_disconnect() - -/** - * Called by Chrome Shell to get a prompt string to display. - */ -DebugShell.prototype.prompt = function() { - if (this.current_command) - return ''; - if (!this.running) - return 'v8(paused)> '; - else - return 'v8(running)> '; -}; - -/** - * Called by Chrome Shell when command input has been received from the user. - */ -DebugShell.prototype.command = function(str) { - if (this.tab) { - str = DebugCommand.trim(str); - if (str.length) { - var cmd = new DebugCommand(str); - cmd.from_user = true; - if (cmd.type == "request") - this.process_command(cmd); - } - } else { - print(">>not connected to a tab"); - } -}; - -/** - * Called when a response to a previous command has been received. - * @param {Object} msg Message object. - */ -DebugShell.prototype.response = function(msg) { - dprint("received: " + (msg && msg.type)); - this.last_msg = msg; - if (msg.type == "event") { - ev = msg["event"] - if (ev == "break") { - this.event_break(msg); - } else if (ev == "exception") { - this.event_exception(msg); - } - } else if (msg.type == "response") { - if (msg.request_seq != undefined) { - if (!this.current_command || this.current_command.seq != msg.request_seq){ - throw("received response to unknown command " + DebugCommand.toJSON(msg)); - } - } else { - // TODO(erikkay): should we reject these when they happen? - print(">>no request_seq in response " + DebugCommand.toJSON(msg)); - } - var cmd = DebugCommand.commands[this.current_command.user_command] - msg.command = this.current_command; - this.current_command = null - if (msg.running != undefined) { - this.set_running(msg.running); - } - if (!msg['success']) { - print(msg['message']); - } else { - var response = cmd['response']; - if (response != undefined) { - response.call(this, msg); - } - } - this.set_ready(true); - } - - // Process next pending command if any. - if (this.pending_commands.length) { - this.process_command(this.pending_commands.shift()); - } else if (this.auto_continue) { - // If no more pending commands and auto continue is active issue a continue command. - this.auto_continue = false; - this.process_command(new DebugCommand("continue")); - } -}; - -/** - * Called when a breakpoint has been set. - * @param {BreakpointInfo} info - details of breakpoint set. - */ -DebugShell.prototype.addedBreakpoint = function(info) { - print("set breakpoint #" + info.id); - this.breakpoints[info.id] = info; -} - -/** - * Called when a breakpoint has been cleared. - * @param {int} id - the breakpoint number that was cleared. - */ -DebugShell.prototype.clearedBreakpoint = function(id) { - assertIsNumberType(id, "clearedBreakpoint called with invalid id"); - - print("cleared breakpoint #" + id); - delete this.breakpoints[id]; -} - -/** - * Called when a breakpoint has been reached. - * @param {int} id - the breakpoint number that was hit. - */ -DebugShell.prototype.didHitBreakpoint = function(id) { - assertIsNumberType(id, "didHitBreakpoint called with invalid id"); - - var info = this.breakpoints[id]; - if (!info) - throw "Could not find breakpoint #" + id; - - info.hit_count ++; -} - -/** - * Print a summary of the specified breakpoints. - * - * @param {Array<BreakpointInfo>} breakpointsToPrint - List of breakpoints. The - * index is unused (id is determined from the info). - */ -DebugShell.printBreakpoints_ = function(breakpoints) { - // TODO(ericroman): this would look much nicer if we could output as an HTML - // table. I tried outputting as formatted text table, but this looks aweful - // once it triggers wrapping (which is very likely if the target is a script) - - // Output as a comma separated list of key=value - for (var i in breakpoints) { - var b = breakpoints[i]; - var props = ["id", "hit_count", "type", "target", "line", "position", - "condition"]; - var propertyList = []; - for (var i = 0; i < props.length; i++) { - var prop = props[i]; - var val = b[prop]; - if (val != undefined) - propertyList.push(prop + "=" + val); - } - print(propertyList.join(", ")); - } -} - -/** - * Called by Chrome Shell when the outer shell is detaching from debugging - * this tab. - */ -DebugShell.prototype.exit = function() { - if (this.tab) { - this.tab.detach(); - this.tab = null; - } -}; - -/** - * Called by the Chrome Shell when the tab that the shell is debugging - * have attached. - */ -DebugShell.prototype.on_attach = function(title) { - if (!title) - title = "Untitled"; - print('attached to ' + title); - // on attach, we update our current script list - var cmd = new DebugCommand("scripts"); - cmd.from_user = false; - this.process_command(cmd); -}; - - -/** - * Called by the Chrome Shell when the tab that the shell is debugging - * went away. - */ -DebugShell.prototype.on_disconnect = function() { - print(">>lost connection to tab"); - this.tab = null; -}; - - -/** - * Structure that holds the details about a breakpoint. - * @constructor - * - * @param {int} id - breakpoint number - * @param {string} type - "script" or "function" - * @param {string} target - either a function name, or script url - * @param {int} line - line number in the script, or undefined - * @param {int} position - column in the script, or undefined - * @param {string} condition - boolean expression, or undefined - */ -function BreakpointInfo(id, type, target, line, position, condition) { - this.id = id; - this.type = type; - this.target = target; - - if (line != undefined) - this.line = line; - if (position != undefined) - this.position = position; - if (condition != undefined) - this.condition = condition; - - this.hit_count = 0; - - // Check that the id is numeric, otherwise will run into problems later - assertIsNumberType(this.id, "id is not a number"); -} - -var shell_ = null; -DebugShell.initDebugShell = function(debuggerUI) { - if (!DebugShell.singleton) { - DebugShell.ui = debuggerUI; - DebugShell.singleton = new DebugShell(TabNode); - shell_ = DebugShell.singleton; - - // enable debug output - //shell_.debug = true; - } -}; - -/** - * Print debugging message when DebugShell's debug flag is true. - */ -function dprint(str) { - if (shell_ && shell_.debug) { - print(str); - } -}; - -/** - * Helper that throws error if x is not a number - * @param x {object} - object to test type of - * @param error_message {string} - error to throw on failure - */ -function assertIsNumberType(x, error_message) { - if (typeof x != "number") - throw error_message; -} - -////////////////////// migration staff ////////////////////////// -// This file was copied from chrome\browser\debugger\resources\debugger_shell.js - -function print(txt) { - var ui = DebugShell.ui; - if (ui) { - ui.appendText(txt); - } -} - -var TabNode = { - debugBreak: function(force) { - DebuggerIPC.sendMessage(["debugBreak", force]); - }, - attach: function() { - DebuggerIPC.sendMessage(["attach"]); - }, - detach: function() { - // TODO(yurys): send this from DebugHandler when it's being destroyed? - DebuggerIPC.sendMessage(["detach"]); - }, - sendToDebugger: function(str) { - DebuggerIPC.sendMessage(["sendToDebugger", str]); - } -}; - -var ChromeNode = { - setDebuggerReady: function(isReady) { - DebuggerIPC.sendMessage(["setDebuggerReady", isReady]); - }, - setDebuggerBreak: function(isBreak) { - var ui = DebugShell.ui; - if (ui) { - ui.setDebuggerBreak(isBreak); - } - DebuggerIPC.sendMessage(["setDebuggerBreak", isBreak]); - } -}; diff --git a/webkit/port/page/inspector/InspectorController.cpp b/webkit/port/page/inspector/InspectorController.cpp deleted file mode 100644 index 9dde0b0..0000000 --- a/webkit/port/page/inspector/InspectorController.cpp +++ /dev/null @@ -1,1824 +0,0 @@ -/* - * Copyright (C) 2007 Google Inc. All rights reserved. - * Authors: Collin Jackson, Adam Barth - * - * This is the V8 version of the KJS InspectorController, which is located in - * webkit/pending. - * Copyright (C) 2007 Apple 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: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. 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. - * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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. - */ - -#include "config.h" -#include "InspectorController.h" - -#include "NotImplemented.h" - -#include "CString.h" -#include "CachedCSSStyleSheet.h" -#include "CachedResource.h" -#include "CachedScript.h" -#include "CachedXSLStyleSheet.h" -#include "Console.h" -#include "DOMWindow.h" -#include "DocLoader.h" -#include "Document.h" -#include "DocumentLoader.h" -#include "Element.h" -#include "FloatConversion.h" -#include "FloatRect.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "FrameTree.h" -#include "FrameView.h" -#include "GraphicsContext.h" -#include "HitTestResult.h" -#include "HTMLFrameOwnerElement.h" -#include "InspectorClient.h" -#include "v8_proxy.h" -#include "v8_binding.h" -#include "Page.h" -#include "Range.h" -#include "ResourceRequest.h" -#include "ResourceResponse.h" -#include "ScriptCallStack.h" -#include "ScriptController.h" -#include "Settings.h" -#include "SharedBuffer.h" -#include "SystemTime.h" -#include "TextEncoding.h" -#include "TextIterator.h" -#include <wtf/RefCounted.h> - -#if ENABLE(DATABASE) -#include "Database.h" -#if USE(JSC) -#include "JSDatabase.h" -#endif -#endif - -#if ENABLE(JAVASCRIPT_DEBUGGER) -#include "JavaScriptDebugServer.h" -#endif - -namespace WebCore { - -// Maximum size of the console message cache. -static const size_t MAX_CONSOLE_MESSAGES = 250; - -namespace bug1228513 { - // TODO(ericroman): Temporary hacks to help diagnose http://b/1228513 - - // To remove all these hacks, search for "bug1228513" - // in InspectorController.{cpp,h} - - // The goal is to push useful data onto the stack, so it is available in - // the minidump (bug repros occasionally on chrome-bot) to: - // (1) distinguish whether "InspectorController* this" is: - // {a valid InspectorController, a freed InspectorController, other} - // (2) know whether an inspector window was previously opened. - // We shouldn't see this happening on chrome-bot, yet it appears - // to be the case. - - enum InspectorControllerState { - VALID = 0x18565F18, - DELETED = 0x2B197D29 - }; - - static int g_totalNumShow = 0; - static int g_totalNumClose = 0; - - struct Info { - int totalNumShow; - int totalNumClose; - int inspectorState; - }; - - void getInfo(Info& info, const InspectorController* inspector) { - info.totalNumShow = g_totalNumShow; - info.totalNumClose = g_totalNumClose; - info.inspectorState = inspector->m_bug1228513_inspectorState; - } -} // namespace bug1228513 - -struct ConsoleMessage { - ConsoleMessage(MessageSource s, MessageLevel l, const String& m, unsigned li, const String& u, unsigned g) - : source(s) - , level(l) - , message(m) - , line(li) - , url(u) - , groupLevel(g) - , repeatCount(1) - { - } - - ConsoleMessage(MessageSource s, MessageLevel l, ScriptCallStack* callStack, unsigned g) - : source(s) - , level(l) -#if USE(JSC) - , wrappedArguments(callStack->at(0).argumentCount()) -#elif USE(V8) - , arguments(callStack->at(0).argumentCount()) -#endif - , groupLevel(g) - , repeatCount(1) - { - const ScriptCallFrame& lastCaller = callStack->at(0); - line = lastCaller.lineNumber(); - url = lastCaller.sourceURL().string(); - -#if USE(JSC) - JSLock lock(false); - for (unsigned i = 0; i < lastCaller.argumentCount(); ++i) - wrappedArguments[i] = JSInspectedObjectWrapper::wrap(callStack->state(), lastCaller.argumentAt(i).jsValue()); -#elif USE(V8) - for (unsigned i = 0; i < lastCaller.argumentCount(); ++i) { - arguments[i] = lastCaller.argumentAt(i); - } -#endif - } - - bool operator==(ConsoleMessage msg) const - { - return msg.source == this->source - && msg.level == this->level - && msg.message == this->message -#if USE(JSC) - && msg.wrappedArguments == this->wrappedArguments -#elif USE(V8) - && msg.arguments == this->arguments -#endif - && msg.line == this->line - && msg.url == this->url - && msg.groupLevel == this->groupLevel; - } - - MessageSource source; - MessageLevel level; - String message; -#if USE(JSC) - Vector<ProtectedPtr<JSValue> > wrappedArguments; -#elif USE(V8) - Vector<ScriptValue> arguments; -#endif - unsigned line; - String url; - unsigned groupLevel; - unsigned repeatCount; -}; - -struct XMLHttpRequestResource { - XMLHttpRequestResource(const String& str) - { - sourceString = str; - } - - ~XMLHttpRequestResource() { } - - String sourceString; -}; - -// InspectorResource Struct - -struct InspectorResource : public RefCounted<InspectorResource> { - // Keep these in sync with WebInspector.Resource.Type - enum Type { - Doc, - Stylesheet, - Image, - Font, - Script, - XHR, - Media, - Other - }; - - static PassRefPtr<InspectorResource> create(unsigned long identifier, DocumentLoader* documentLoader, Frame* frame) - { - // Apple changed the default refcount to 1: http://trac.webkit.org/changeset/30406 - // We default it to 1 in the protected constructor below to match Apple, - // so adoptRef is the right thing. - return adoptRef(new InspectorResource(identifier, documentLoader, frame)); - } - - ~InspectorResource() - { - setScriptObject(v8::Handle<v8::Object>()); - } - - Type type() const - { - if (xmlHttpRequestResource) - return XHR; - - if (requestURL == loader->requestURL()) - return Doc; - - if (loader->frameLoader() && requestURL == loader->frameLoader()->iconURL()) - return Image; - - CachedResource* cachedResource = frame->document()->docLoader()->cachedResource(requestURL.string()); - if (!cachedResource) - return Other; - - switch (cachedResource->type()) { - case CachedResource::ImageResource: - return Image; - case CachedResource::FontResource: - return Font; - case CachedResource::CSSStyleSheet: -#if ENABLE(XSLT) - case CachedResource::XSLStyleSheet: -#endif - return Stylesheet; - case CachedResource::Script: - return Script; - default: - return Other; - } - } - - void setScriptObject(v8::Handle<v8::Object> newScriptObject) - { - //XXXMB - the InspectorController and InspectorResource both maintain persistent handles - // to this object (I think!). If so, calling dispose could clobber the other. - if (!scriptObject.IsEmpty()) { - scriptObject.Dispose(); - scriptObject.Clear(); - } - if (!newScriptObject.IsEmpty()) - scriptObject = v8::Persistent<v8::Object>::New(newScriptObject); - } - - // TODO(ojan): XHR requests show up in the inspector, but not their contents. - // Something is wrong obviously, but not sure what. Not the highest priority - // thing the inspector needs fixed right now though. - void setXMLHttpRequestProperties(String& data) - { - xmlHttpRequestResource.set(new XMLHttpRequestResource(data)); - } - - String sourceString() const - { - if (xmlHttpRequestResource) { - return xmlHttpRequestResource->sourceString; - } - - String sourceString; - - if (requestURL == loader->requestURL()) { - RefPtr<SharedBuffer> buffer = loader->mainResourceData(); - String textEncodingName = frame->document()->inputEncoding(); - if (buffer) { - TextEncoding encoding(textEncodingName); - if (!encoding.isValid()) - encoding = WindowsLatin1Encoding(); - return encoding.decode(buffer->data(), buffer->size()); - } - return String(); - } else { - CachedResource* cachedResource = frame->document()->docLoader()->cachedResource(requestURL.string()); - if (!cachedResource) - return String(); - - // Try to get the decoded source. Only applies to some CachedResource - // types. - switch(cachedResource->type()) { - case CachedResource::CSSStyleSheet: - { - CachedCSSStyleSheet *sheet = - reinterpret_cast<CachedCSSStyleSheet*>(cachedResource); - sourceString = sheet->sheetText(); - } - break; - case CachedResource::Script: - { - CachedScript *script = - reinterpret_cast<CachedScript*>(cachedResource); - sourceString = script->script(); - } - break; -#if ENABLE(XSLT) - case CachedResource::XSLStyleSheet: - { - CachedXSLStyleSheet *sheet = - reinterpret_cast<CachedXSLStyleSheet*>(cachedResource); - sourceString = sheet->sheet(); - } - break; -#endif - default: - break; - } - } - - return sourceString; - } - - unsigned long identifier; - RefPtr<DocumentLoader> loader; - RefPtr<Frame> frame; - OwnPtr<XMLHttpRequestResource> xmlHttpRequestResource; - KURL requestURL; - HTTPHeaderMap requestHeaderFields; - HTTPHeaderMap responseHeaderFields; - String mimeType; - String suggestedFilename; - v8::Persistent<v8::Object> scriptObject; - long long expectedContentLength; - bool cached; - bool finished; - bool failed; - int length; - int responseStatusCode; - double startTime; - double responseReceivedTime; - double endTime; - - // Helper function to determine when the script object is initialized - inline bool hasScriptObject() { return !scriptObject.IsEmpty(); } - -protected: - InspectorResource(unsigned long identifier, DocumentLoader* documentLoader, Frame* frame) - : identifier(identifier) - , loader(documentLoader) - , frame(frame) - , xmlHttpRequestResource(0) - , expectedContentLength(0) - , cached(false) - , finished(false) - , failed(false) - , length(0) - , responseStatusCode(0) - , startTime(-1.0) - , responseReceivedTime(-1.0) - , endTime(-1.0) - { - } -}; - -// InspectorDatabaseResource Struct - -#if ENABLE(DATABASE) -struct InspectorDatabaseResource : public RefCounted<InspectorDatabaseResource> { - static PassRefPtr<InspectorDatabaseResource> create(Database* database, const String& domain, const String& name, const String& version) - { - // Apple changed the default refcount to 1: http://trac.webkit.org/changeset/30406 - // We default it to 1 in the protected constructor below to match Apple, - // so adoptRef is the right thing. - return adoptRef(new InspectorDatabaseResource(database, domain, name, version)); - } - - void setScriptObject() - { - // TODO(aa): Implement this. - } - - RefPtr<Database> database; - String domain; - String name; - String version; - -private: - InspectorDatabaseResource(Database* database, const String& domain, const String& name, const String& version) - : database(database) - , domain(domain) - , name(name) - , version(version) - { - } -}; -#endif - -// JavaScript Callbacks - -void InspectorController::addSourceToFrame(unsigned long identifier, Node* node) -{ - RefPtr<InspectorResource> resource = this->resources().get(identifier); - ASSERT(resource); - if (!resource) - return; - - String sourceString = resource->sourceString(); - if (sourceString.isEmpty()) - return; - - ASSERT(node); - if (!node) - return; - - if (!node->attached()) { - ASSERT_NOT_REACHED(); - return; - } - - ASSERT(node->isElementNode()); - if (!node->isElementNode()) - return; - - Element* element = static_cast<Element*>(node); - ASSERT(element->isFrameOwnerElement()); - if (!element->isFrameOwnerElement()) - return; - - HTMLFrameOwnerElement* frameOwner = static_cast<HTMLFrameOwnerElement*>(element); - ASSERT(frameOwner->contentFrame()); - if (!frameOwner->contentFrame()) - return; - - FrameLoader* loader = frameOwner->contentFrame()->loader(); - - loader->setResponseMIMEType(resource->mimeType); - loader->begin(); - loader->write(sourceString); - loader->end(); -} - -Node* InspectorController::getResourceDocumentNode(unsigned long identifier) { - RefPtr<InspectorResource> resource = this->resources().get(identifier); - ASSERT(resource); - if (!resource) - return 0; - - Frame* frame = resource->frame.get(); - - Document* document = frame->document(); - if (!document) - return 0; - - if (document->isPluginDocument() || document->isImageDocument()) - return 0; - - return document; -} -void InspectorController::highlightDOMNode(Node* node) -{ - if (!enabled()) - return; - - ASSERT_ARG(node, node); - m_client->highlight(node); -} -void InspectorController::hideDOMNodeHighlight() -{ - if (!enabled()) - return; - - m_client->hideHighlight(); -} - -void InspectorController::loaded() { - scriptObjectReady(); -} - -// We don't need to implement this because we just map windowUnloading to -// InspectorController::close in the IDL file. - -void InspectorController::attach() { - attachWindow(); -} - -void InspectorController::detach() { - detachWindow(); -} - -// TODO(ojan): See when/if this works. We should either make it work or remove it. -void InspectorController::search(Node* node, const String& target) { - v8::HandleScope handle_scope; - v8::Handle<v8::Context> context = V8Proxy::GetContext(m_page->mainFrame()); - v8::Context::Scope scope(context); - - v8::Handle<v8::Object> global = context->Global(); - v8::Handle<v8::Array> array = v8::Array::New(); - - v8::Handle<v8::Value> push = array->Get(v8::String::New("push")); - ASSERT(push->IsFunction()); - - RefPtr<Range> searchRange(rangeOfContents(node)); - - int exception = 0; - do { - RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, false)); - if (resultRange->collapsed(exception)) - break; - - // A non-collapsed result range can in some funky whitespace cases still not - // advance the range's start position (4509328). Break to avoid infinite loop. - VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM); - if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM)) - break; - - v8::Handle<v8::Value> arg0 = V8Proxy::ToV8Object(V8ClassIndex::RANGE, resultRange.get()); - v8::Handle<v8::Value> args[] = { arg0 }; - - (v8::Function::Cast(*push))->Call(array, 1, args); - - setStart(searchRange.get(), newStart); - } while (true); - - // TODO(jackson): Figure out how to return array -} - -#if ENABLE(DATABASE) -#if USE(JSC) -static JSValueRef databaseTableNames(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (!controller) - return JSValueMakeUndefined(ctx); - - if (argumentCount < 1) - return JSValueMakeUndefined(ctx); - - JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(toJS(arguments[0])); - if (!wrapper) - return JSValueMakeUndefined(ctx); - - Database* database = toDatabase(wrapper->unwrappedObject()); - if (!database) - return JSValueMakeUndefined(ctx); - - JSObjectRef global = JSContextGetGlobalObject(ctx); - - JSValueRef arrayProperty = JSObjectGetProperty(ctx, global, jsStringRef("Array").get(), exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - JSObjectRef arrayConstructor = JSValueToObject(ctx, arrayProperty, exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - JSValueRef pushProperty = JSObjectGetProperty(ctx, result, jsStringRef("push").get(), exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - JSObjectRef pushFunction = JSValueToObject(ctx, pushProperty, exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - Vector<String> tableNames = database->tableNames(); - unsigned length = tableNames.size(); - for (unsigned i = 0; i < length; ++i) { - String tableName = tableNames[i]; - JSValueRef tableNameValue = JSValueMakeString(ctx, jsStringRef(tableName).get()); - - JSValueRef pushArguments[] = { tableNameValue }; - JSObjectCallAsFunction(ctx, pushFunction, result, 1, pushArguments, exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - } - - return result; -} -#elif USE(V8) -// TODO(aa): Implement inspector database support -#endif -#endif - -DOMWindow* InspectorController::inspectedWindow() { - // Can be null if page was already destroyed. - if (!m_inspectedPage) - return NULL; - return m_inspectedPage->mainFrame()->domWindow(); -} - -String InspectorController::platform() const { - return String("windows"); -} - -// InspectorController Class - -InspectorController::InspectorController(Page* page, InspectorClient* client) - : - // The V8 version of InspectorController is RefCounted while the JSC - // version uses an OwnPtr (http://b/904340). However, since we're not - // using a create method to initialize the InspectorController, we need - // to start the RefCount at 0. - RefCounted<InspectorController>(0) - , m_bug1228513_inspectorState(bug1228513::VALID) - , m_trackResources(false) - , m_inspectedPage(page) - , m_client(client) - , m_page(0) - , m_windowVisible(false) -#if ENABLE(JAVASCRIPT_DEBUGGER) - , m_debuggerAttached(false) - , m_attachDebuggerWhenShown(false) -#endif - , m_recordingUserInitiatedProfile(false) - , m_showAfterVisible(ElementsPanel) - , m_nextIdentifier(-2) - , m_groupLevel(0) - , m_searchingForNode(false) - , m_currentUserInitiatedProfileNumber(-1) - , m_nextUserInitiatedProfileNumber(1) - , m_previousMessage(0) -{ - ASSERT_ARG(page, page); - ASSERT_ARG(client, client); -} - -InspectorController::~InspectorController() -{ - m_bug1228513_inspectorState = bug1228513::DELETED; - m_client->inspectorDestroyed(); - - if (m_page) - m_page->setParentInspectorController(0); - - // m_inspectedPage should have been cleared by inspectedPageDestroyed - ASSERT(!m_inspectedPage); - - deleteAllValues(m_frameResources); - deleteAllValues(m_consoleMessages); -} - -void InspectorController::inspectedPageDestroyed() -{ - close(); - - ASSERT(m_inspectedPage); - m_inspectedPage = 0; -} - -bool InspectorController::enabled() const -{ - // Copy some data onto the stack in case we crash on line - // "m_inspectedPage->settings()->developerExtrasEnabled();" - bug1228513::Info bug1228513_info; - bug1228513::getInfo(bug1228513_info, this); - - if (!m_inspectedPage) - return false; - - bool b = m_inspectedPage->settings()->developerExtrasEnabled(); - - if (bug1228513_info.inspectorState != bug1228513::VALID) { - CRASH(); - } - - return b; -} - -String InspectorController::localizedStringsURL() -{ - if (!enabled()) - return String(); - return m_client->localizedStringsURL(); -} - -void InspectorController::inspect(Node* node) -{ - if (!node || !enabled()) - return; - - show(); - - if (node->nodeType() != Node::ELEMENT_NODE && node->nodeType() != Node::DOCUMENT_NODE) - node = node->parentNode(); - m_nodeToFocus = node; - - if (!hasScriptObject()) { - m_showAfterVisible = ElementsPanel; - return; - } - - if (windowVisible()) - focusNode(); -} - -void InspectorController::focusNode() -{ - if (!enabled() || !m_nodeToFocus) - return; - - ASSERT(hasScriptObject()); - - Frame* frame = m_nodeToFocus->document()->frame(); - if (!frame) - return; - - v8::HandleScope handle_scope; - v8::Handle<v8::Context> context = V8Proxy::GetContext(m_page->mainFrame()); - v8::Context::Scope scope(context); - - v8::Handle<v8::Value> nodeToFocus = V8Proxy::ToV8Object(V8ClassIndex::NODE, m_nodeToFocus.get()); - v8::Handle<v8::Value> updateFocusedNode = m_scriptObject->Get(v8::String::New("updateFocusedNode")); - ASSERT(updateFocusedNode->IsFunction()); - - v8::Handle<v8::Function> func(v8::Function::Cast(*updateFocusedNode)); - v8::Handle<v8::Value> args[] = { nodeToFocus }; - func->Call(m_scriptObject, 1, args); -} - -void InspectorController::highlight(Node* node) -{ - if (!enabled()) - return; - ASSERT_ARG(node, node); - m_highlightedNode = node; - m_client->highlight(node); -} - -void InspectorController::hideHighlight() -{ - if (!enabled()) - return; - m_client->hideHighlight(); -} - -bool InspectorController::windowVisible() -{ - return m_windowVisible; -} - -void InspectorController::setWindowVisible(bool visible, bool attached) -{ - // Policy: only log resources while the inspector window is visible. - enableTrackResources(visible); - - if (visible == m_windowVisible) - return; - - m_windowVisible = visible; - - if (!hasScriptObject()) - return; - - if (m_windowVisible) { - setAttachedWindow(attached); - populateScriptObjects(); - if (m_nodeToFocus) - focusNode(); -#if ENABLE(JAVASCRIPT_DEBUGGER) - if (m_attachDebuggerWhenShown) - startDebuggingAndReloadInspectedPage(); -#endif - if (m_showAfterVisible != CurrentPanel) - showPanel(m_showAfterVisible); - } else { -#if ENABLE(JAVASCRIPT_DEBUGGER) - stopDebugging(); -#endif - resetScriptObjects(); - } - - m_showAfterVisible = CurrentPanel; -} - -void InspectorController::enableTrackResources(bool trackResources) -{ - if (m_trackResources == trackResources) - return; - - m_trackResources = trackResources; - - // Clear the current resources. - deleteAllValues(m_frameResources); - m_mainResource = NULL; - m_frameResources.clear(); - m_resources.clear(); -} - -void InspectorController::addDatabaseScriptResource(InspectorDatabaseResource*) -{ - // TODO(aa): Implement database support for inspector. -} - -void InspectorController::addMessageToConsole(MessageSource source, MessageLevel level, ScriptCallStack* callStack) -{ - if (!enabled()) - return; - - addConsoleMessage(0, new ConsoleMessage(source, level, callStack, m_groupLevel)); -} - -void InspectorController::addMessageToConsole(MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceID) -{ - if (!enabled()) - return; - - addConsoleMessage(0, new ConsoleMessage(source, level, message, lineNumber, sourceID, m_groupLevel)); -} - -void InspectorController::addConsoleMessage(ScriptState*, ConsoleMessage* consoleMessage) -{ - ASSERT(enabled()); - ASSERT_ARG(consoleMessage, consoleMessage); - - // Limit the number of console messages we keep in memory so a poorly - // behaving script doesn't cause unbounded memory growth. We remove the - // oldest messages so that the most recent errors are preserved. - // TODO(erikkay): this is not very efficient since Vector has to do a copy - // when you remove from anywhere other than the end. Unfortunately, WTF - // doesn't appear to have a double-ended list we could use instead. The - // extra CPU cost is definitely better than the memory cost. - if (m_consoleMessages.size() >= MAX_CONSOLE_MESSAGES) { - ConsoleMessage* msg = m_consoleMessages[0]; - m_consoleMessages.remove(0); - delete msg; - } - m_previousMessage = consoleMessage; - m_consoleMessages.append(consoleMessage); - if (windowVisible()) - addScriptConsoleMessage(m_previousMessage); -} - -void InspectorController::clearConsoleMessages() -{ - deleteAllValues(m_consoleMessages); - m_consoleMessages.clear(); - m_previousMessage = 0; -} - -void InspectorController::startGroup(MessageSource source, ScriptCallStack* callStack) -{ - ++m_groupLevel; - - addConsoleMessage(0, new ConsoleMessage(source, StartGroupMessageLevel, callStack, m_groupLevel)); -} - -void InspectorController::endGroup(MessageSource source, unsigned lineNumber, const String& sourceURL) -{ - if (m_groupLevel == 0) - return; - - --m_groupLevel; - - addConsoleMessage(0, new ConsoleMessage(source, EndGroupMessageLevel, String(), lineNumber, sourceURL, m_groupLevel)); -} - -void InspectorController::attachWindow() -{ - if (!enabled()) - return; - m_client->attachWindow(); -} - -void InspectorController::detachWindow() -{ - if (!enabled()) - return; - m_client->detachWindow(); -} - -void InspectorController::setScriptObject(v8::Handle<v8::Object> newScriptObject) -{ - if (hasScriptObject()) { - m_scriptObject.Dispose(); - m_scriptObject.Clear(); - } - - if (!newScriptObject.IsEmpty()) - m_scriptObject = v8::Persistent<v8::Object>::New(newScriptObject); -} - -void InspectorController::inspectedWindowScriptObjectCleared(Frame* frame) -{ - // TODO(tc): We need to call inspectedWindowCleared, but that won't matter - // until we merge in inspector.js as well. - notImplemented(); -} - -void InspectorController::setAttachedWindow(bool attached) -{ - notImplemented(); -} - -void InspectorController::setAttachedWindowHeight(unsigned height) -{ - notImplemented(); -} - -void InspectorController::toggleSearchForNodeInPage() -{ - if (!enabled()) - return; - - m_searchingForNode = !m_searchingForNode; - if (!m_searchingForNode) - hideHighlight(); -} - -void InspectorController::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags) -{ - if (!enabled() || !m_searchingForNode) - return; - - Node* node = result.innerNode(); - if (node) - highlight(node); -} - -void InspectorController::handleMousePressOnNode(Node* node) -{ - if (!enabled()) - return; - - ASSERT(m_searchingForNode); - ASSERT(node); - if (!node) - return; - - // inspect() will implicitly call ElementsPanel's focusedNodeChanged() and the hover feedback will be stopped there. - inspect(node); -} - - -void InspectorController::windowScriptObjectAvailable() -{ - if (!m_page || !enabled()) - return; - - v8::HandleScope handle_scope; - v8::Handle<v8::Context> context = V8Proxy::GetContext(m_page->mainFrame()); - v8::Context::Scope scope(context); - - // InspectorController.idl exposes the methods of InspectorController to JavaScript - v8::Handle<v8::Object> global = context->Global(); - v8::Handle<v8::Value> inspectorController = V8Proxy::ToV8Object(V8ClassIndex::INSPECTORCONTROLLER, this); - global->Set(v8::String::New("InspectorController"), inspectorController); -} - -void InspectorController::scriptObjectReady() -{ - if (!m_page || !enabled()) - return; - - v8::HandleScope handle_scope; - v8::Handle<v8::Context> context = V8Proxy::GetContext(m_page->mainFrame()); - v8::Context::Scope scope(context); - - v8::Handle<v8::Object> global = context->Global(); - v8::Handle<v8::Object> inspector = v8::Handle<v8::Object>(v8::Object::Cast(*global->Get(v8::String::New("WebInspector")))); - setScriptObject(inspector); - - // Make sure our window is visible now that the page loaded - m_client->showWindow(); -} - -void InspectorController::show() -{ - if (!enabled()) - return; - - ++bug1228513::g_totalNumShow; - - if (!m_page) { - m_page = m_client->createPage(); - if (!m_page) - return; - m_page->setParentInspectorController(this); - - // showWindow() will be called after the page loads in scriptObjectReady() - return; - } - - showWindow(); -} - -void InspectorController::showPanel(SpecialPanels panel) -{ - if (!enabled()) - return; - - show(); - - if (!hasScriptObject()) { - m_showAfterVisible = panel; - return; - } - - if (panel == CurrentPanel) - return; - - const char* showFunctionName; - switch (panel) { - case ConsolePanel: - showFunctionName = "showConsole"; - break; - case DatabasesPanel: - showFunctionName = "showDatabasesPanel"; - break; - case ElementsPanel: - showFunctionName = "showElementsPanel"; - break; - case ProfilesPanel: - showFunctionName = "showProfilesPanel"; - break; - case ResourcesPanel: - showFunctionName = "showResourcesPanel"; - break; - case ScriptsPanel: - showFunctionName = "showScriptsPanel"; - break; - default: - ASSERT_NOT_REACHED(); - showFunctionName = 0; - } - - if (windowVisible() && showFunctionName) { - v8::HandleScope handle_scope; - v8::Handle<v8::Context> context = V8Proxy::GetContext(m_page->mainFrame()); - v8::Context::Scope scope(context); - - // TODO(ojan): Use showFunctionName here. For some reason some of these - // are not functions (e.g. showElementsPanel). - v8::Handle<v8::Value> showFunction = m_scriptObject->Get(v8::String::New("showConsole")); - ASSERT(showFunction->IsFunction()); - - v8::Handle<v8::Function> func(v8::Function::Cast(*showFunction)); - func->Call(m_scriptObject, 0, NULL); - } else { - m_client->showWindow(); - } -} - -void InspectorController::close() -{ - if (!enabled()) - return; - - ++bug1228513::g_totalNumClose; - -#if ENABLE(JAVASCRIPT_DEBUGGER) - stopDebugging(); -#endif - closeWindow(); - if (m_page) { - v8::HandleScope handle_scope; - v8::Handle<v8::Context> context = V8Proxy::GetContext(m_page->mainFrame()); - v8::Context::Scope scope(context); - setScriptObject(v8::Handle<v8::Object>()); - } - - m_page = 0; -} - -void InspectorController::showWindow() -{ - ASSERT(enabled()); - m_client->showWindow(); -} - -void InspectorController::closeWindow() -{ - m_client->closeWindow(); -} - -static void addHeaders(v8::Handle<v8::Object> object, const HTTPHeaderMap& headers) -{ - ASSERT_ARG(object, !object.IsEmpty()); - HTTPHeaderMap::const_iterator end = headers.end(); - for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) { - v8::Handle<v8::String> field = v8::String::New(FromWebCoreString(it->first), it->first.length()); - object->Set(field, v8StringOrNull(it->second)); - } -} - -static v8::Handle<v8::Object> scriptObjectForRequest(const InspectorResource* resource) -{ - v8::Handle<v8::Object> object = v8::Object::New(); - addHeaders(object, resource->requestHeaderFields); - return object; -} - -static v8::Handle<v8::Object> scriptObjectForResponse(const InspectorResource* resource) -{ - v8::Handle<v8::Object> object = v8::Object::New(); - addHeaders(object, resource->responseHeaderFields); - return object; -} - -void InspectorController::addScriptResource(InspectorResource* resource) -{ - ASSERT_ARG(resource, resource); - ASSERT(trackResources()); - ASSERT(hasScriptObject()); - if (!hasScriptObject()) - return; - - // Acquire the context so we can create V8 objects - v8::HandleScope handle_scope; - v8::Handle<v8::Context> context = V8Proxy::GetContext(m_page->mainFrame()); - v8::Context::Scope scope(context); - - v8::Handle<v8::Value> resourceConstructor = m_scriptObject->Get(v8::String::New("Resource")); - ASSERT(resourceConstructor->IsFunction()); - - v8::Handle<v8::Value> arguments[] = { - scriptObjectForRequest(resource), - v8StringOrNull(resource->requestURL.string()), - v8StringOrNull(resource->requestURL.host()), - v8StringOrNull(resource->requestURL.path()), - v8StringOrNull(resource->requestURL.lastPathComponent()), - v8::Number::New(resource->identifier), - (m_mainResource == resource)?v8::True():v8::False(), - (resource->cached)?v8::True():v8::False(), - }; - - v8::Handle<v8::Object> object = SafeAllocation::NewInstance(v8::Handle<v8::Function>::Cast(resourceConstructor), 8, arguments); - - resource->setScriptObject(object); - - ASSERT(!object.IsEmpty()); - - v8::Handle<v8::Value> addResourceFunction = m_scriptObject->Get(v8::String::New("addResource")); - ASSERT(addResourceFunction->IsFunction()); - - v8::Handle<v8::Value> addArguments[] = { object }; - (v8::Function::Cast(*addResourceFunction))->Call(m_scriptObject, 1, addArguments); -} - -void InspectorController::addAndUpdateScriptResource(InspectorResource* resource) -{ - ASSERT_ARG(resource, resource); - ASSERT(trackResources()); - - addScriptResource(resource); - updateScriptResourceResponse(resource); - updateScriptResource(resource, resource->length); - updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime); - updateScriptResource(resource, resource->finished, resource->failed); -} - -void InspectorController::removeScriptResource(InspectorResource* resource) -{ - ASSERT(hasScriptObject()); - if (!hasScriptObject()) - return; - - ASSERT(resource); - ASSERT(resource->hasScriptObject()); - if (!resource || !resource->hasScriptObject()) - return; - - v8::HandleScope handle_scope; - v8::Handle<v8::Context> context = V8Proxy::GetContext(m_page->mainFrame()); - v8::Context::Scope scope(context); - - v8::Handle<v8::Value> removeResourceFunction = m_scriptObject->Get(v8::String::New("removeResource")); - ASSERT(removeResourceFunction->IsFunction()); - v8::Handle<v8::Value> args[] = { resource->scriptObject }; - (v8::Function::Cast(*removeResourceFunction))->Call(m_scriptObject, 1, args); - - resource->setScriptObject(v8::Handle<v8::Object>()); -} - -static void updateResourceRequest(InspectorResource* resource, const ResourceRequest& request) -{ - resource->requestHeaderFields = request.httpHeaderFields(); - resource->requestURL = request.url(); -} - -static void updateResourceResponse(InspectorResource* resource, const ResourceResponse& response) -{ - resource->expectedContentLength = response.expectedContentLength(); - resource->mimeType = response.mimeType(); - resource->responseHeaderFields = response.httpHeaderFields(); - resource->responseStatusCode = response.httpStatusCode(); - resource->suggestedFilename = response.suggestedFilename(); -} - -void InspectorController::updateScriptResourceRequest(InspectorResource* resource) -{ - ASSERT(resource->hasScriptObject()); - ASSERT(trackResources()); - if (!resource->hasScriptObject()) - return; - - // Acquire the context so we can create V8 objects - v8::HandleScope handle_scope; - v8::Handle<v8::Context> context = V8Proxy::GetContext(m_page->mainFrame()); - v8::Context::Scope scope(context); - - resource->scriptObject->Set(v8::String::New("url"), v8StringOrNull(resource->requestURL.string())); - resource->scriptObject->Set(v8::String::New("domain"), v8StringOrNull(resource->requestURL.host())); - resource->scriptObject->Set(v8::String::New("path"), v8StringOrNull(resource->requestURL.path())); - resource->scriptObject->Set(v8::String::New("lastPathComponent"), v8StringOrNull(resource->requestURL.lastPathComponent())); - resource->scriptObject->Set(v8::String::New("requestHeaders"), scriptObjectForRequest(resource)); - resource->scriptObject->Set(v8::String::New("mainResource"), (m_mainResource == resource)?v8::True():v8::False()); -} - -void InspectorController::updateScriptResourceResponse(InspectorResource* resource) -{ - ASSERT(resource->hasScriptObject()); - ASSERT(trackResources()); - if (!resource->hasScriptObject()) - return; - - // Acquire the context so we can create V8 objects - v8::HandleScope handle_scope; - v8::Handle<v8::Context> context = V8Proxy::GetContext(m_page->mainFrame()); - v8::Context::Scope scope(context); - - resource->scriptObject->Set(v8::String::New("mimeType"), v8StringOrNull(resource->mimeType)); - resource->scriptObject->Set(v8::String::New("suggestedFilename"), v8StringOrNull(resource->suggestedFilename)); - resource->scriptObject->Set(v8::String::New("expectedContentLength"), v8::Number::New(resource->expectedContentLength)); - resource->scriptObject->Set(v8::String::New("statusCode"), v8::Number::New(resource->responseStatusCode)); - resource->scriptObject->Set(v8::String::New("responseHeaders"), scriptObjectForResponse(resource)); - resource->scriptObject->Set(v8::String::New("type"), v8::Number::New(resource->type())); -} - -void InspectorController::updateScriptResourceType(InspectorResource* resource) -{ - notImplemented(); -} - -void InspectorController::updateScriptResource(InspectorResource* resource, int length) -{ - ASSERT(resource->hasScriptObject()); - ASSERT(trackResources()); - if (!resource->hasScriptObject()) - return; - - // Acquire the context so we can create V8 objects - v8::HandleScope handle_scope; - v8::Handle<v8::Context> context = V8Proxy::GetContext(m_page->mainFrame()); - v8::Context::Scope scope(context); - - m_scriptObject->Set(v8::String::New("contentLength"), v8::Number::New(length)); -} - -void InspectorController::updateScriptResource(InspectorResource* resource, bool finished, bool failed) -{ - ASSERT(resource->hasScriptObject()); - ASSERT(trackResources()); - if (!resource->hasScriptObject()) - return; - - v8::HandleScope handle_scope; - v8::Handle<v8::Context> context = V8Proxy::GetContext(m_page->mainFrame()); - v8::Context::Scope scope(context); - - resource->scriptObject->Set(v8::String::New("failed"), (failed)?v8::True():v8::False()); - resource->scriptObject->Set(v8::String::New("finished"), (finished)?v8::True():v8::False()); -} - -void InspectorController::updateScriptResource(InspectorResource* resource, double startTime, double responseReceivedTime, double endTime) -{ - ASSERT(resource->hasScriptObject()); - ASSERT(trackResources()); - if (!resource->hasScriptObject()) - return; - - v8::HandleScope handle_scope; - v8::Handle<v8::Context> context = V8Proxy::GetContext(m_page->mainFrame()); - v8::Context::Scope scope(context); - - resource->scriptObject->Set(v8::String::New("startTime"), v8::Number::New(startTime)); - resource->scriptObject->Set(v8::String::New("responseReceivedTime"), v8::Number::New(responseReceivedTime)); - resource->scriptObject->Set(v8::String::New("endTime"), v8::Number::New(endTime)); -} - -void InspectorController::populateScriptObjects() -{ - ResourcesMap::iterator resourcesEnd = m_resources.end(); - for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it) - addAndUpdateScriptResource(it->second.get()); - - unsigned messageCount = m_consoleMessages.size(); - for (unsigned i = 0; i < messageCount; ++i) - addScriptConsoleMessage(m_consoleMessages[i]); - - // TODO(ojan): Call populateInterface javascript function here. - // Need to add it to the IDL and whatnot. -} - -void InspectorController::addScriptConsoleMessage(const ConsoleMessage* message) -{ - ASSERT_ARG(message, message); - - if (!hasScriptObject()) - return; - - v8::HandleScope handle_scope; - v8::Handle<v8::Context> context = V8Proxy::GetContext(m_page->mainFrame()); - - if (context.IsEmpty()) - return; - - v8::Context::Scope scope(context); - - v8::Handle<v8::Value> consoleMessageProperty = - m_scriptObject->Get(v8::String::New("ConsoleMessage")); - ASSERT(!consoleMessageProperty.IsEmpty() && consoleMessageProperty->IsFunction()); - - if (consoleMessageProperty.IsEmpty() || !consoleMessageProperty->IsFunction()) - return; - v8::Handle<v8::Function> consoleMessageConstructor = - v8::Handle<v8::Function>::Cast(consoleMessageProperty); - - v8::Handle<v8::Value> addMessageToConsole = - m_scriptObject->Get(v8::String::New("addMessageToConsole")); - ASSERT(!addMessageToConsole.IsEmpty() && addMessageToConsole->IsFunction()); - - if (addMessageToConsole.IsEmpty() || !addMessageToConsole->IsFunction()) - return; - - // Create an instance of WebInspector.ConsoleMessage passing the variable - // number of arguments available. - static unsigned kArgcFixed = 6; - unsigned argc = kArgcFixed + message->arguments.size(); - v8::Handle<v8::Value> *args = new v8::Handle<v8::Value>[argc]; - if (args == 0) - return; - unsigned i = 0; - args[i++] = v8::Number::New(message->source); - args[i++] = v8::Number::New(message->level); - args[i++] = v8::Number::New(message->line); - args[i++] = v8StringOrNull(message->url); - args[i++] = v8::Number::New(message->groupLevel); - args[i++] = v8::Number::New(message->repeatCount); - ASSERT(kArgcFixed == i); - for (unsigned i = 0; i < message->arguments.size(); ++i) { - args[kArgcFixed + i] = message->arguments[i].v8Value(); - } - - v8::Handle<v8::Object> consoleMessage = - SafeAllocation::NewInstance(consoleMessageConstructor, argc, args); - delete[] args; - if (consoleMessage.IsEmpty()) - return; - - v8::Handle<v8::Value> args2[] = { consoleMessage }; - (v8::Function::Cast(*addMessageToConsole))->Call(m_scriptObject, 1, args2); -} - -void InspectorController::resetScriptObjects() -{ - if (!hasScriptObject()) - return; - - ResourcesMap::iterator resourcesEnd = m_resources.end(); - for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it) { - InspectorResource* resource = it->second.get(); - resource->setScriptObject(v8::Handle<v8::Object>()); - } - -#if ENABLE(DATABASE) - DatabaseResourcesSet::iterator databasesEnd = m_databaseResources.end(); - for (DatabaseResourcesSet::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it) { - InspectorDatabaseResource* resource = (*it).get(); - resource->setScriptObject(); - } -#endif - - v8::HandleScope handle_scope; - v8::Handle<v8::Context> context = V8Proxy::GetContext(m_page->mainFrame()); - v8::Context::Scope scope(context); - - v8::Handle<v8::Value> reset = m_scriptObject->Get(v8::String::New("reset")); - ASSERT(reset->IsFunction()); - - v8::Handle<v8::Function> func(v8::Function::Cast(*reset)); - func->Call(m_scriptObject, 0, NULL); -} - -void InspectorController::pruneResources(ResourcesMap* resourceMap, DocumentLoader* loaderToKeep) -{ - ASSERT_ARG(resourceMap, resourceMap); - - ResourcesMap mapCopy(*resourceMap); - ResourcesMap::iterator end = mapCopy.end(); - for (ResourcesMap::iterator it = mapCopy.begin(); it != end; ++it) { - InspectorResource* resource = (*it).second.get(); - if (resource == m_mainResource) - continue; - - if (!loaderToKeep || resource->loader != loaderToKeep) { - removeResource(resource); - if (windowVisible() && resource->hasScriptObject()) - removeScriptResource(resource); - } - } -} - -void InspectorController::didCommitLoad(DocumentLoader* loader) -{ - if (!enabled()) - return; - - ASSERT(m_inspectedPage); - - if (loader->frame() == m_inspectedPage->mainFrame()) { - m_client->inspectedURLChanged(loader->url().string()); - deleteAllValues(m_consoleMessages); - m_consoleMessages.clear(); - m_groupLevel = 0; - -#if ENABLE(DATABASE) - m_databaseResources.clear(); -#endif - - if (windowVisible()) { - resetScriptObjects(); - - if (!loader->isLoadingFromCachedPage()) { - // We don't add the main resource until its load is committed. This is - // needed to keep the load for a user-entered URL from showing up in the - // list of resources for the page they are navigating away from. - if (trackResources() && m_mainResource) - addAndUpdateScriptResource(m_mainResource.get()); - } else { - // Pages loaded from the page cache are committed before - // m_mainResource is the right resource for this load, so we - // clear it here. It will be re-assigned in - // identifierForInitialRequest. - m_mainResource = 0; - } - } - } - - if (trackResources()) { - for (Frame* frame = loader->frame(); frame; frame = frame->tree()->traverseNext(loader->frame())) - if (ResourcesMap* resourceMap = m_frameResources.get(frame)) - pruneResources(resourceMap, loader); - } -} - -void InspectorController::frameDetachedFromParent(Frame* frame) -{ - if (!enabled()) - return; - if (ResourcesMap* resourceMap = m_frameResources.get(frame)) - removeAllResources(resourceMap); -} - -void InspectorController::addResource(InspectorResource* resource) -{ - ASSERT(trackResources()); - m_resources.set(resource->identifier, resource); - m_knownResources.add(resource->requestURL.string()); - - Frame* frame = resource->frame.get(); - ResourcesMap* resourceMap = m_frameResources.get(frame); - if (resourceMap) - resourceMap->set(resource->identifier, resource); - else { - resourceMap = new ResourcesMap; - resourceMap->set(resource->identifier, resource); - m_frameResources.set(frame, resourceMap); - } -} - -void InspectorController::removeResource(InspectorResource* resource) -{ - m_resources.remove(resource->identifier); - - Frame* frame = resource->frame.get(); - ResourcesMap* resourceMap = m_frameResources.get(frame); - if (!resourceMap) { - ASSERT_NOT_REACHED(); - return; - } - - resourceMap->remove(resource->identifier); - if (resourceMap->isEmpty()) { - m_frameResources.remove(frame); - delete resourceMap; - } -} - -void InspectorController::didLoadResourceFromMemoryCache(DocumentLoader* loader, const ResourceRequest& request, const ResourceResponse& response, int length) -{ - if (!enabled() || !trackResources()) - return; - - // If the resource URL is already known, we don't need to add it again since this is just a cached load. - if (m_knownResources.contains(request.url().string())) - return; - - RefPtr<InspectorResource> resource = InspectorResource::create(m_nextIdentifier--, loader, loader->frame()); - resource->finished = true; - - updateResourceRequest(resource.get(), request); - updateResourceResponse(resource.get(), response); - - resource->length = length; - resource->cached = true; - resource->startTime = currentTime(); - resource->responseReceivedTime = resource->startTime; - resource->endTime = resource->startTime; - - ASSERT(m_inspectedPage); - - if (loader->frame() == m_inspectedPage->mainFrame() && request.url() == loader->requestURL()) - m_mainResource = resource; - - addResource(resource.get()); - - if (windowVisible()) - addAndUpdateScriptResource(resource.get()); -} - -void InspectorController::identifierForInitialRequest(unsigned long identifier, DocumentLoader* loader, const ResourceRequest& request) -{ - if (!enabled() || !trackResources()) - return; - - RefPtr<InspectorResource> resource = InspectorResource::create(identifier, loader, loader->frame()); - - updateResourceRequest(resource.get(), request); - - if (loader->frame() == m_inspectedPage->mainFrame() && request.url() == loader->requestURL()) - m_mainResource = resource; - - addResource(resource.get()); - - if (windowVisible() && loader->isLoadingFromCachedPage() && resource == m_mainResource) - addAndUpdateScriptResource(resource.get()); -} - -void InspectorController::willSendRequest(DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse) -{ - if (!enabled() || !trackResources()) - return; - - InspectorResource* resource = m_resources.get(identifier).get(); - if (!resource) - return; - - resource->startTime = currentTime(); - - if (!redirectResponse.isNull()) { - updateResourceRequest(resource, request); - updateResourceResponse(resource, redirectResponse); - } - - if (resource != m_mainResource && windowVisible()) { - if (!resource->hasScriptObject()) - addScriptResource(resource); - else - updateScriptResourceRequest(resource); - - updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime); - - if (!redirectResponse.isNull()) - updateScriptResourceResponse(resource); - } -} - -void InspectorController::didReceiveResponse(DocumentLoader*, unsigned long identifier, const ResourceResponse& response) -{ - if (!enabled() || !trackResources()) - return; - - InspectorResource* resource = m_resources.get(identifier).get(); - if (!resource) - return; - - updateResourceResponse(resource, response); - - resource->responseReceivedTime = currentTime(); - - if (windowVisible() && resource->hasScriptObject()) { - updateScriptResourceResponse(resource); - updateScriptResource(resource, resource->startTime, resource->responseReceivedTime, resource->endTime); - } -} - -void InspectorController::didReceiveContentLength(DocumentLoader*, unsigned long identifier, int lengthReceived) -{ - if (!enabled() || !trackResources()) - return; - - InspectorResource* resource = m_resources.get(identifier).get(); - if (!resource) - return; - - resource->length += lengthReceived; - - if (windowVisible() && resource->hasScriptObject()) - updateScriptResource(resource, resource->length); -} - -void InspectorController::didFinishLoading(DocumentLoader* loader, unsigned long identifier) -{ - if (!enabled() || !trackResources()) - return; - - RefPtr<InspectorResource> resource = m_resources.get(identifier); - if (!resource) - return; - - removeResource(resource.get()); - - resource->finished = true; - resource->endTime = currentTime(); - - addResource(resource.get()); - - if (windowVisible() && resource->hasScriptObject()) { - updateScriptResource(resource.get(), resource->startTime, resource->responseReceivedTime, resource->endTime); - updateScriptResource(resource.get(), resource->finished); - } -} - -void InspectorController::didFailLoading(DocumentLoader* loader, unsigned long identifier, const ResourceError& /*error*/) -{ - if (!enabled() || !trackResources()) - return; - - RefPtr<InspectorResource> resource = m_resources.get(identifier); - if (!resource) - return; - - removeResource(resource.get()); - - resource->finished = true; - resource->failed = true; - resource->endTime = currentTime(); - - addResource(resource.get()); - - if (windowVisible() && resource->hasScriptObject()) { - updateScriptResource(resource.get(), resource->startTime, resource->responseReceivedTime, resource->endTime); - updateScriptResource(resource.get(), resource->finished, resource->failed); - } -} - -void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identifier, const String& sourceString) -{ - notImplemented(); -} - -#if ENABLE(DATABASE) -void InspectorController::didOpenDatabase(Database* database, const String& domain, const String& name, const String& version) -{ - if (!enabled()) - return; - - RefPtr<InspectorDatabaseResource> resource = InspectorDatabaseResource::create(database, domain, name, version); - - m_databaseResources.add(resource); - - if (windowVisible()) - addDatabaseScriptResource(resource.get()); -} -#endif - -void InspectorController::moveWindowBy(float x, float y) const -{ - if (!m_page || !enabled()) - return; - - FloatRect frameRect = m_page->chrome()->windowRect(); - frameRect.move(x, y); - m_page->chrome()->setWindowRect(frameRect); -} - -static void drawOutlinedRect(GraphicsContext& context, const IntRect& rect, const Color& fillColor) -{ - static const int outlineThickness = 1; - static const Color outlineColor(62, 86, 180, 228); - - IntRect outline = rect; - outline.inflate(outlineThickness); - - context.clearRect(outline); - - context.save(); - context.clipOut(rect); - context.fillRect(outline, outlineColor); - context.restore(); - - context.fillRect(rect, fillColor); -} - -static void drawHighlightForBoxes(GraphicsContext& context, const Vector<IntRect>& lineBoxRects, const IntRect& contentBox, const IntRect& paddingBox, const IntRect& borderBox, const IntRect& marginBox) -{ - static const Color contentBoxColor(125, 173, 217, 128); - static const Color paddingBoxColor(125, 173, 217, 160); - static const Color borderBoxColor(125, 173, 217, 192); - static const Color marginBoxColor(125, 173, 217, 228); - - if (!lineBoxRects.isEmpty()) { - for (size_t i = 0; i < lineBoxRects.size(); ++i) - drawOutlinedRect(context, lineBoxRects[i], contentBoxColor); - return; - } - - if (marginBox != borderBox) - drawOutlinedRect(context, marginBox, marginBoxColor); - if (borderBox != paddingBox) - drawOutlinedRect(context, borderBox, borderBoxColor); - if (paddingBox != contentBox) - drawOutlinedRect(context, paddingBox, paddingBoxColor); - drawOutlinedRect(context, contentBox, contentBoxColor); -} - -static inline void convertFromFrameToMainFrame(Frame* frame, IntRect& rect) -{ - rect = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(rect)); -} - -void InspectorController::drawNodeHighlight(GraphicsContext& context) const -{ - if (!m_highlightedNode) - return; - - RenderObject* renderer = m_highlightedNode->renderer(); - Frame* containingFrame = m_highlightedNode->document()->frame(); - if (!renderer || !containingFrame) - return; - - IntRect contentBox = renderer->absoluteContentBox(); - IntRect boundingBox = renderer->absoluteBoundingBoxRect(); - - // FIXME: Should we add methods to RenderObject to obtain these rects? - IntRect paddingBox(contentBox.x() - renderer->paddingLeft(), contentBox.y() - renderer->paddingTop(), contentBox.width() + renderer->paddingLeft() + renderer->paddingRight(), contentBox.height() + renderer->paddingTop() + renderer->paddingBottom()); - IntRect borderBox(paddingBox.x() - renderer->borderLeft(), paddingBox.y() - renderer->borderTop(), paddingBox.width() + renderer->borderLeft() + renderer->borderRight(), paddingBox.height() + renderer->borderTop() + renderer->borderBottom()); - IntRect marginBox(borderBox.x() - renderer->marginLeft(), borderBox.y() - renderer->marginTop(), borderBox.width() + renderer->marginLeft() + renderer->marginRight(), borderBox.height() + renderer->marginTop() + renderer->marginBottom()); - - convertFromFrameToMainFrame(containingFrame, contentBox); - convertFromFrameToMainFrame(containingFrame, paddingBox); - convertFromFrameToMainFrame(containingFrame, borderBox); - convertFromFrameToMainFrame(containingFrame, marginBox); - convertFromFrameToMainFrame(containingFrame, boundingBox); - - Vector<IntRect> lineBoxRects; - if (renderer->isInline() || (renderer->isText() && !m_highlightedNode->isSVGElement())) { - // FIXME: We should show margins/padding/border for inlines. - renderer->addLineBoxRects(lineBoxRects); - } - - for (unsigned i = 0; i < lineBoxRects.size(); ++i) - convertFromFrameToMainFrame(containingFrame, lineBoxRects[i]); - - if (lineBoxRects.isEmpty() && contentBox.isEmpty()) { - // If we have no line boxes and our content box is empty, we'll just draw our bounding box. - // This can happen, e.g., with an <a> enclosing an <img style="float:right">. - // FIXME: Can we make this better/more accurate? The <a> in the above case has no - // width/height but the highlight makes it appear to be the size of the <img>. - lineBoxRects.append(boundingBox); - } - - ASSERT(m_inspectedPage); - - FrameView* view = m_inspectedPage->mainFrame()->view(); - FloatRect overlayRect = view->visibleContentRect(); - - if (!overlayRect.contains(boundingBox) && !boundingBox.contains(enclosingIntRect(overlayRect))) { - Element* element; - if (m_highlightedNode->isElementNode()) - element = static_cast<Element*>(m_highlightedNode.get()); - else - element = static_cast<Element*>(m_highlightedNode->parent()); - element->scrollIntoViewIfNeeded(); - overlayRect = view->visibleContentRect(); - } - - context.translate(-overlayRect.x(), -overlayRect.y()); - - drawHighlightForBoxes(context, lineBoxRects, contentBox, paddingBox, borderBox, marginBox); -} - -// TODO(dglazkov): These next three methods should be easy to implement or gain -// for free when we unfork inspector - -void InspectorController::count(const String& title, unsigned lineNumber, const String& sourceID) -{ - notImplemented(); -} - -void InspectorController::startTiming(const String& title) -{ - notImplemented(); -} - -bool InspectorController::stopTiming(const String& title, double& elapsed) -{ - elapsed = 0; - notImplemented(); - return false; -} - -} // namespace WebCore diff --git a/webkit/port/page/inspector/InspectorController.idl b/webkit/port/page/inspector/InspectorController.idl deleted file mode 100644 index 690ade2..0000000 --- a/webkit/port/page/inspector/InspectorController.idl +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2008 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. - -/* if ENABLE(DATABASE), there should be a databaseTableNames method. */ - -module core { - interface InspectorController { - void addSourceToFrame(in unsigned long identifier, in Node frame); - Node getResourceDocumentNode(in unsigned long identifier); - void highlightDOMNode(in Node node); - void hideDOMNodeHighlight(); - void loaded(); - [v8implname=close] void windowUnloading(); - void attach(); - void detach(); - void search(in Node node, in DOMString query); - DOMWindow inspectedWindow(); - DOMString platform(); - DOMString localizedStringsURL(); - - /* TODO(ojan): add these. These are in trunk webkit. - #if ENABLE(DATABASE) - { "databaseTableNames", databaseTableNames, kJSPropertyAttributeNone }, - #endif - { "moveByUnrestricted", moveByUnrestricted, kJSPropertyAttributeNone }, - { "wrapCallback", wrapCallback, kJSPropertyAttributeNone }, - { "startDebuggingAndReloadInspectedPage", WebCore::startDebuggingAndReloadInspectedPage, kJSPropertyAttributeNone }, - { "stopDebugging", WebCore::stopDebugging, kJSPropertyAttributeNone }, - { "debuggerAttached", WebCore::debuggerAttached, kJSPropertyAttributeNone }, - */ - }; -} diff --git a/webkit/port/page/inspector/debugger.css b/webkit/port/page/inspector/debugger.css deleted file mode 100644 index ed9df2f..0000000 --- a/webkit/port/page/inspector/debugger.css +++ /dev/null @@ -1,35 +0,0 @@ -/** - * 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/webkit/port/page/inspector/debugger.html b/webkit/port/page/inspector/debugger.html deleted file mode 100644 index f6bb917..0000000 --- a/webkit/port/page/inspector/debugger.html +++ /dev/null @@ -1,31 +0,0 @@ -<!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="DebuggerConsole.js"></script> - <script type="text/javascript" src="DebuggerIPC.js"></script> - <script type="text/javascript" src="DebuggerShell.js"></script> - </head> - - <body onload="onLoad();"> - - <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' - type="text" /> - </div> - - </body> -</html> |