diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
commit | 09911bf300f1a419907a9412154760efd0b7abc3 (patch) | |
tree | f131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/resources | |
parent | 586acc5fe142f498261f52c66862fa417c3d52d2 (diff) | |
download | chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2 |
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/resources')
-rw-r--r-- | chrome/browser/resources/about_memory.html | 687 | ||||
-rw-r--r-- | chrome/browser/resources/about_plugins.html | 209 | ||||
-rw-r--r-- | chrome/browser/resources/about_stats.html | 316 | ||||
-rw-r--r-- | chrome/browser/resources/about_version.html | 47 | ||||
-rw-r--r-- | chrome/browser/resources/browser_resources.vcproj | 109 | ||||
-rw-r--r-- | chrome/browser/resources/debugger_shell.js | 1246 | ||||
-rw-r--r-- | chrome/browser/resources/gear.png | bin | 0 -> 357 bytes | |||
-rw-r--r-- | chrome/browser/resources/help.gif | bin | 0 -> 205 bytes | |||
-rw-r--r-- | chrome/browser/resources/incognito_tab.html | 31 | ||||
-rw-r--r-- | chrome/browser/resources/new_tab.html | 624 | ||||
-rw-r--r-- | chrome/browser/resources/phishing_icon.png | bin | 0 -> 4645 bytes | |||
-rw-r--r-- | chrome/browser/resources/safe_browsing_malware_block.html | 102 | ||||
-rw-r--r-- | chrome/browser/resources/safe_browsing_phishing_block.html | 103 | ||||
-rw-r--r-- | chrome/browser/resources/ssl_error.html | 22 |
14 files changed, 3496 insertions, 0 deletions
diff --git a/chrome/browser/resources/about_memory.html b/chrome/browser/resources/about_memory.html new file mode 100644 index 0000000..406a9d0 --- /dev/null +++ b/chrome/browser/resources/about_memory.html @@ -0,0 +1,687 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> + +<!-- +about:memory template page +--> +<html id="t"> + <head> + <title>About Memory</title> + +<style type="text/css"> +body { + font-size: 84%; + font-family: Arial, Helvetica, sans-serif; + padding: 0.75em; + margin: 0; + min-width: 45em; +} + +h1 { + font-size: 110%; + font-weight: bold; + color: #4a8ee6; + letter-spacing: -1px; + padding: 0; + margin: 0; +} +h2 { + font-size: 110%; + letter-spacing: -1px; + font-weight: normal; + color: #4a8ee6; + padding: 0; + margin: 0; + padding: 0.5em 1em; + color: #3a75bd; + margin-left: -38px; + padding-left: 38px; + + border-top: 1px solid #3a75bd; + padding-top: 0.5em; + +} +h2:first-child { + border-top: 0; + padding-top: 0; +} +span.th { + padding-left: 0.35em; +} +a { + color: black; +} + +div#header { + padding: 0.75em 1em; + padding-top: 0.6em; + padding-left: 0; + margin-bottom: 0.75em; + position: relative; + overflow: hidden; + background: #5296de; + -webkit-background-size: 100%; + border: 1px solid #3a75bd; + -webkit-border-radius: 6px; + color: white; + text-shadow: 0 0 2px black; +} +div#header h1 { + padding-left: 37px; + margin: 0; + display: inline; + background: url('gear.png') 12px 60% no-repeat; + color: white; +} +div#header p { + font-size: 84%; + font-style: italic; + padding: 0; + margin: 0; + color: white; + padding-left: 0.4em; + display: inline; +} +div#header div.navigation { + position: absolute; + top: 0; + right: 1em; + line-height: 3.5em; + font-size: 92%; +} +div#header select { + font-size: 100%; + font-family: Arial, Helvetica, sans-serif; + border: 1px solid #3a75bd; + line-height: 140%; + color: #315d94; +} +div#header select option { + padding: 0 0.2em; +} + +div#sidebar { + display: none; + float: left; + margin-left: 26px; + width: 45em; + min-height: 20em; + padding: 0.75em; + padding-top: 0; + + border-right: 1px solid #cfcfcf; +} +div#content { + margin-left: 0px; +} + +div.viewOptions { + float: right; + font-size: 92%; + color: #5f5f5f; + margin-top: 1em; +} +hr { + visibility: hidden; + display: inline; + padding: 0 0.5em; +} +div.viewOptions input { + font-family: Arial, Helvetica, sans-serif; + font-size: 100%; + border: 1px solid #b5b5b5; + -webkit-border-radius: 6px; + padding: 0.3em 0.4em; +} +div.viewOptions input:focus { + border-color: white; +} + +.k { + opacity: 0.4; + font-weight: normal; + padding-left: 0.1em; +} + +.legend { + font-size: 84%; + padding: 0; + padding-top: 0.4em; + margin-top: 2em; + text-align: right; + line-height: 140%; + color: #7f7f7f; +} +.legend h3 { + padding: 0; + padding-right: 0.5em; + margin: 0; + font-weight: normal; + color: black; + display: inline; + font-size: 100%; +} +.legend .swatch { + opacity: 0.66; + padding: 0 0.5em; + display: inline-block; + margin-right: 0.2em; + height: 0.9em; +} +.legend .swatch.heavyUse { + background: #cc0000; +} + +table.list { + width: 100%; + line-height: 200%; + border-collapse: collapse; + font-size: 84%; + table-layout: fixed; +} +table.list:not([class*='filtered']) tr:nth-child(odd) td { + background: #eff3ff; +} +.hidden { + display: none; +} +table.list th { + padding: 0 0.5em; + vertical-align: top; + font-weight: bold; + color: #315d94; + color: black; + white-space: nowrap; +} +table.list .firstRow th { + text-align: left; + line-height: 100%; +} +table.list .secondRow * { + text-align: left; + border-bottom: 1px solid #b5c6de; +} +table.list td { + padding: 0 0.5em; + vertical-align: top; + line-height: 1.4em; + padding-top: 0.35em; +} +table.list tr td:nth-last-child(1), +table.list tr th:nth-last-child(1) { + padding-right: 1em; +} +table.list:not([class*='filtered']) .tab .name { + padding-left: 1.5em; +} + +table.list .name { + width: 100%; +} + +table.list .name div { + height: 1.6em; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +table.list .pid { + width: 4em; + text-align: right; +} +table.list .pid .th { + padding: 0; +} +table.list .type { + width: 5em; +} +table.list .number { + width: 7em; + text-align: right; +} +table.list .total { + font-weight: bold; +} +table.list .total .name { + color: #315d94; + text-align: right; +} +table.list .total td { + border-top: 1px solid #b5c6de; + background: white !important; +} +table.list .noResults { + display: none; +} +table.list.noResults .noResults { + display: table-row; +} +table.list .noResults td { + text-align: center; + padding: 3em 0; + color: #3f3f3f; +} + +.heavyUse { + color: #cc0000; + font-weight: bold; +} + +table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(2), +table.list#memoryDetails tr:not([class*='firstRow']) > *:nth-child(5), +table.list#memoryDetails tr.firstRow th:nth-child(2), +table.list#memoryDetails tr.firstRow th:nth-child(3) { + border-right: 1px solid #b5c6de; +} + +table.list#browserComparison tr:not([class*='firstRow']) > *:nth-child(1), +table.list#browserComparison tr:not([class*='firstRow']) > *:nth-child(4), +table.list#browserComparison tr.firstRow th:nth-child(1), +table.list#browserComparison tr.firstRow th:nth-child(2) { + border-right: 1px solid #b5c6de; +} +table.list#browserComparison .name { + padding-left: 25px; + background-position: 5px center; + background-repeat: no-repeat; +} + +div.help { + display: inline-block; + width: 14px; + margin: -1px 0; + height: 14px; + background: url('help.gif') center bottom no-repeat; + opacity: 0.33; +} +div.help:hover { + opacity: 1; +} +div.help div { + display: none; +} +#helpTooltip { + z-index: 1000; + position: absolute; + background: #d6e8ff; + padding: 0.3em 0.8em; + max-width: 30em; + -webkit-box-shadow: 3px 3px 4px rgba(0, 0, 0, 0.33); + border: 1px solid #a8cfff; + -webkit-border-radius: 0; + line-height: 140%; + font-size: 92%; +} +#helpTooltip p { + margin: 0.6em 0; +} +div.otherbrowsers { + font-family: Arial, Helvetica, sans-serif; + font-size: 84%; + width: 100%; + text-align: center; +} +</style> +<script> +function reload() { + if (document.getElementById('helpTooltip')) + return; + history.go(0); +} + +function formatNumber(str) { + str += ''; + var x = str.split('.'); + var x1 = x[0]; + var x2 = x.length > 1 ? '.' + x[1] : ''; + var regex = /(\d+)(\d{3})/; + while (regex.test(x1)) { + x1 = x1.replace(regex, '$1' + ',' + '$2'); + } + return x1; +} + +function addToSum(id, value) { + var target = document.getElementById(id); + var sum = parseInt(target.innerHTML); + sum += parseInt(value); + target.innerHTML = sum; +} + +function handleHelpTooltipMouseOver(event) { + var el = document.createElement('div'); + el.id = 'helpTooltip'; + el.innerHTML = event.toElement.getElementsByTagName('div')[0].innerHTML; + el.style.top = 0; + el.style.left = 0; + el.style.visibility = 'hidden'; + document.body.appendChild(el); + + var width = el.offsetWidth; + var height = el.offsetHeight; + + if (event.pageX - width - 50 + document.body.scrollLeft >= 0 ) { + el.style.left = (event.pageX - width - 20) + 'px'; + } else { + el.style.left = (event.pageX + 20) + 'px'; + } + + + if (event.pageY - height - 50 + document.body.scrollTop >= 0) { + el.style.top = (event.pageY - height - 20) + 'px'; + } else { + el.style.top = (event.pageY + 20) + 'px'; + } + + el.style.visibility = 'visible'; +} + +function handleHelpTooltipMouseOut(event) { + var el = document.getElementById('helpTooltip'); + el.parentNode.removeChild(el); +} + +function enableHelpTooltips() { + var helpEls = document.getElementsByClassName('help'); + + for (var i = 0, helpEl; helpEl = helpEls[i]; i++) { + helpEl.onmouseover = handleHelpTooltipMouseOver; + helpEl.onmouseout = handleHelpTooltipMouseOut; + } +} + +//setInterval("reload()", 10000); +</script> +</head> +<body> + <div id='header'> + <h1> + About memory + </h1> + <p> + Measuring memory usage in a multi-process browser + </p> + </div> + + <div id='content'> + <h2> + Summary + <div class='help'> + <div> + <p> + Summary of memory used by currently active browsers. + For browsers which use multiple processes, memory reflects + aggregate memory used across all browser processes.<p> + For chrome, processes used to to display diagnostics + information (such as this "about:memory") are excluded. + </p> + </div> + </div> + </h2> + + <table class='list' id='browserComparison'> + <colgroup> + <col class='name' /> + <col class='number' /> + <col class='number' /> + <col class='number' /> + <col class='number' /> + <col class='number' /> + </colgroup> + <tr class='firstRow doNotFilter'> + <th> + </th> + <th colspan='3'> + Memory + <div class='help'> + <div> + <p> + <strong>Memory</strong> + </p> + <p> + <strong>Private:</strong> + Resident memory size that is not shared with any other process. + This is the best indicator of browser memory resource usage. + </p> + <p> + <strong>Shared:</strong> + Resident memory size that is currently shared with 2 or more processes. + Note: For browsers using multiple processes, if we simply added the shared memory + of each individual process, this value would be inflated. Therefore, this value + is computed as an approximate value for shared memory in each of the browser's + processes. Note also that shared memory varies depending on what other processes + are running on the system, and may be difficult to measure reproducibly. + </p> + <p> + <strong>Total:</strong> + The sum of the private + shared resident memory sizes. + </p> + </div> + </div> + </th> + <th colspan='2'> + Virtual memory + <div class='help'> + <div> + <p> + <strong>Virtual memory</strong> + </p> + <p> + <strong>Private:</strong> + The resident and paged bytes committed for use by only this process. + </p> + <p> + <strong>Mapped:</strong> + Total bytes allocated by this process that are mapped into the + view of a section, backed by either system pagefile or file system. This + is primarily memory-mapped files. + </p> + </div> + </div> + </th> + </tr> + <tr class='secondRow doNotFilter'> + <th class='name'> + Browser + </th> + <th class='name'> + Private + </th> + </th> + <th class='number'> + Shared + </th> + <th class='number'> + Total + </th> + <th class='number'> + Private + </th> + <th class='number'> + Mapped + </th> + </tr> + <tr jsselect="browsers"> + <td class='name'> + <div> + <strong jscontent="name"></strong> <span jscontent="version"></span> + </div> + </td> + <td class='number'> + <span class='th' jscontent="formatNumber(ws_priv + ws_shareable - ws_shared)"></span><span class='k'>k</span> + </td> + <td class='number'> + <span class='th' jscontent="formatNumber(ws_shared / processes)"></span><span class='k'>k</span> + </td> + <td class='number'> + <span class='th' jscontent="formatNumber(ws_priv + ws_shareable - ws_shared + (ws_shared / processes))"></span><span class='k'>k</span> + </td> + <td class='number'> + <span class='th' jscontent="formatNumber(comm_priv)"></span><span class='k'>k</span> + </td> + <td class='number'> + <span class='th' jscontent="formatNumber(comm_map)"></span><span class='k'>k</span> + </td> + </tr> + </table> + <div class=otherbrowsers jsdisplay="browsers.length == 1"> + Note: If other browsers (IE, Firefox, Opera, Safari) are running, + I'll show their memory details here. + </div> + + <br /><br /><br /> + + <h2> + Processes + <div class='help'> + <div> + <p> + Details of memory usage for each of Chrome's processes. + </p> + </div> + </div> + </h2> + + <table class='list' id='memoryDetails'> + <colgroup> + <col class='pid' /> + <col class='name' /> + <col class='number' /> + <col class='number' /> + <col class='number' /> + <col class='number' /> + <col class='number' /> + </colgroup> + <tr class='firstRow doNotFilter'> + <th> + </th> + <th> + </th> + <th colspan='3'> + Memory + </th> + <th colspan='2'> + Virtual memory + </th> + + </tr> + <tr class='secondRow doNotFilter'> + <th class='pid'> + PID + </th> + <th class='name'> + Name + </th> + <th class='number'> + Private + </th> + <th class='number'> + Shared + </th> + <th class='number'> + Total + </th> + <th class='number'> + Private + </th> + <th class='number'> + Mapped + </th> + </tr> + + <tr jsselect="browzr_data"> + <td class='pid'> + <span class='th' jscontent="pid"></span> + </td> + <td class='name'> + <div> + Browser + </div> + </td> + <td class='number'> + <span class='th' jseval="addToSum('tot_ws_priv', $this.ws_priv + $this.ws_shareable - $this.ws_shared)" jscontent="ws_priv + ws_shareable - ws_shared"></span><span class='k'>k</span> + </td> + <td class='number'> + <span class='th' jscontent="ws_shared"></span><span class='k'>k</span> + </td> + <td class='number'> + <span class='th' jseval="addToSum('tot_ws_tot', $this.ws_priv + $this.ws_shareable)" jscontent="ws_priv + ws_shareable"></span><span class='k'>k</span> + </td> + <td class='number'> + <span class='th' jseval="addToSum('tot_comm_priv', $this.comm_priv)" jscontent="comm_priv"></span><span class='k'>k</span> + </td> + <td class='number'> + <span class='th' jseval="addToSum('tot_comm_map', $this.comm_map)" jscontent="comm_map"></span><span class='k'>k</span> + </td> + </tr> + <tr jsselect="renderer_data"> + <td class='pid'> + <span class='th' jscontent="pid"></span> + </td> + <td class='name'> + <div jscontent="renderer_id"></div> + <div jsselect="titles"> + <span jscontent="$this"></span><br> + </div> + </td> + <td class='number'> + <span class='th' jseval="addToSum('tot_ws_priv', $this.ws_priv + $this.ws_shareable - $this.ws_shared)" jscontent="ws_priv + ws_shareable - ws_shared"></span><span class='k'>k</span> + </td> + <td class='number'> + <span class='th' jscontent="ws_shared"></span><span class='k'>k</span> + </td> + <td class='number'> + <span class='th' jseval="addToSum('tot_ws_tot', $this.ws_priv + $this.ws_shareable)" jscontent="ws_priv + ws_shareable"></span><span class='k'>k</span> + </td> + <td class='number'> + <span class='th' jseval="addToSum('tot_comm_priv', $this.comm_priv)" jscontent="comm_priv"></span><span class='k'>k</span> + </td> + <td class='number'> + <span class='th' jseval="addToSum('tot_comm_map', $this.comm_map)" jscontent="comm_map"></span><span class='k'>k</span> + </td> + </tr> + <tr class='total doNotFilter'> + <td class='pid'> + </td> + <td class='name'> + Σ + </td> + <td class='number'> + <span class='th' id="tot_ws_priv">0</span><span class='k'>k</span> + </td> + <td class='number'> + </td> + <td class='number'> + <span class='th' id="tot_ws_tot">0</span><span class='k'>k</span> + </td> + <td class='number'> + <span class='th' id="tot_comm_priv">0</span><span class='k'>k</span> + </td> + <td class='number'> + <div class='help'> + <div> + <p> + This is an approximation. Conceptually, this is the total + amount of in-memory pages for the entire logical Chrome + application, without double counting shared pages (e.g. + mapped + DLLs, SharedMemory bitmaps, etc.) across the browser and + renderers. + </p> + </div> + </div> + <span class='th' id="tot_comm_map">0</span><span class='k'>k</span> + </td> + </tr> + + <tr class='noResults'> + <td colspan='99'> + No results found. + </td> + </tr> + </table> + </div> +</body> +<script> + enableHelpTooltips(); +</script> +</html> diff --git a/chrome/browser/resources/about_plugins.html b/chrome/browser/resources/about_plugins.html new file mode 100644 index 0000000..eb0cad7 --- /dev/null +++ b/chrome/browser/resources/about_plugins.html @@ -0,0 +1,209 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> + +<!-- +A modified version of the about:plugins page found in Mozilla. The license of +the original file is below. +--> + +<!-- ***** BEGIN LICENSE BLOCK ***** + - Version: MPL 1.1/GPL 2.0/LGPL 2.1 + - + - The contents of this file are subject to the Mozilla Public License Version + - 1.1 (the "License"); you may not use this file except in compliance with + - the License. You may obtain a copy of the License at + - http://www.mozilla.org/MPL/ + - + - Software distributed under the License is distributed on an "AS IS" basis, + - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + - for the specific language governing rights and limitations under the + - License. + - + - The Original Code is mozilla.org Code. + - + - The Initial Developer of the Original Code is + - Netscape Communications Corporation. + - Portions created by the Initial Developer are Copyright (C) 1998 + - the Initial Developer. All Rights Reserved. + - + - Contributor(s): + - Mark Olson <maolson@earthlink.net> + - Alexey Chernyak <alexeyc@bigfoot.com> + - Frank Tang <ftang@netscape.com> + - Mike Connelly <mozilla@shepherdstown.com> + - Robert Kaiser <kairo@kairo.at> + - + - Alternatively, the contents of this file may be used under the terms of + - either the GNU General Public License Version 2 or later (the "GPL"), or + - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + - in which case the provisions of the GPL or the LGPL are applicable instead + - of those above. If you wish to allow use of your version of this file only + - under the terms of either the GPL or the LGPL, and not to allow others to + - use your version of this file under the terms of the MPL, indicate your + - decision by deleting the provisions above and replace them with the notice + - and other provisions required by the LGPL or the GPL. If you do not delete + - the provisions above, a recipient may use your version of this file under + - the terms of any one of the MPL, the GPL or the LGPL. + - + - ***** END LICENSE BLOCK ***** --> + +<html id="t"> +<head> +<title jscontent="title"></title> +<style> +body { + background-color: Window; + color: WindowText; + font: message-box; +} + +div#outside { + text-align: justify; + width: 90%; + margin-left: 5%; + margin-right: 5%; +} + +div#plugs { + text-align: center; + font-size: xx-large; + font-weight: bold; +} + +div#noplugs { + font-size: x-large; + font-weight: bold; +} + +div.plugname { + margin-top: 2em; + margin-bottom: 1em; + font-size: large; + text-align: left; + font-weight: bold; +} + +dl { + margin: 0px 0px 3px 0px; +} + +table { + background-color: Window; + color: WindowText; + font: message-box; + text-align: left; + width: 100%; + border: 1px solid ThreeDShadow; + border-spacing: 0px; +} + +th { + text-align: center; + background-color: Highlight; + color: HighlightText; +} + +th + th, +td + td { + border-left: 1px dotted ThreeDShadow; +} + +td { + text-align: left; + border-top: 1px dotted ThreeDShadow; +} + +th, td { + padding: 3px; +} + +th.type, th.suff { + width: 20%; +} + +th.desc { + width: 50%; +} + +th.enabled { + width: 10%; +} +</style> +</head> +<body> +<div id="outside"> +<script type="application/x-javascript"> + + /* JavaScript to enumerate and display all installed plug-ins + + * First, refresh plugins in case anything has been changed recently in + * prefs: (The "false" argument tells refresh not to reload or activate + * any plug-ins that would be active otherwise. In contrast, one would + * use "true" in the case of ASD instead of restarting) + */ + + navigator.plugins.refresh(false); + + var numPlugins = navigator.plugins.length; + + if (numPlugins > 0) + document.writeln('<div id="plugs" jscontent="headingPlugs"><\/div>'); + else + document.writeln('<div id="noplugs" jscontent="headingNoPlugs"><\/div>'); + + for (var i = 0; i < numPlugins; i++) + { + var plugin = navigator.plugins[i]; + + if (plugin) + { + document.write("<div class=\"plugname\">"); + document.write(plugin.name); + document.writeln("<\/div>"); + + document.writeln('<dl><dd><span jscontent="filename"><\/span> '); + document.write(plugin.filename); + document.writeln("<\/dd><dd>"); + document.write(plugin.description); + document.writeln("<\/dd><\/dl>"); + + document.writeln('<table class="contenttable">'); + document.writeln("<thead>"); + document.writeln('<tr><th class="type" jscontent="mimetype"><\/th>'); + document.writeln('<th class="desc" jscontent="description"><\/th>'); + document.writeln('<th class="suff" jscontent="suffixes"><\/th>'); + document.writeln('<th class="enabled" jscontent="enabled"><\/th><\/tr>'); + document.writeln("<\/thead>"); + document.writeln("<tbody>"); + + var numTypes = plugin.length; + var mimetype; + var enabled; + var enabledPlugin; + for (var j = 0; j < numTypes; j++) + { + mimetype = plugin[j]; + + if (mimetype) + { + enabled = "enabled_no"; + enabledPlugin = mimetype.enabledPlugin; + if (enabledPlugin && (enabledPlugin.filename == plugin.filename)) + enabled = "enabled_yes"; + + document.writeln("<tr>"); + document.writeln("<td>" + mimetype.type + "<\/td>"); + document.writeln("<td>" + mimetype.description + "<\/td>"); + document.writeln("<td>" + mimetype.suffixes + "<\/td>"); + document.writeln('<td jscontent="' + enabled + '"><\/td>'); + document.writeln("<\/tr>"); + } + } + + document.write("<\/tbody>"); + document.write("<\/table>"); + } + } +</script> +</div> +</body> +</html> diff --git a/chrome/browser/resources/about_stats.html b/chrome/browser/resources/about_stats.html new file mode 100644 index 0000000..8354fe5 --- /dev/null +++ b/chrome/browser/resources/about_stats.html @@ -0,0 +1,316 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> + +<html id="t"> + <head> + <title>About Stats</title> + +<style type="text/css"> +body { + border-top: 10px solid #3B85E3; + color: #333; + font-family: Verdana,Arial,Helvetica,sans-serif; +} +body, td { + font-size: 11px; +} +a:link, a:visited { + color: #2C3EBA; + text-decoration: none; +} +a:hover { + color: red; + text-decoration: underline; +} +h1 { + border-left: 10px solid #FFF; + font-size: 16px; + font-weight: bold; + margin: 0; + padding: 0.2em; + color: #3B85E3; +} +h2 { + border-left: 10px solid #FFF; + font-size: 11px; + font-weight: normal; + margin: 0; + padding: 0 6em 0.2em 0.2em; +} +.details { + margin: 0.4em 1.9em 0 1.2em; + padding: 0 0.4em 0.3em 0; + white-space: nowrap; +} +.details .outer { + padding-right: 0; + vertical-align: top; +} +.details .top { + border-top: 2px solid #333; + font-weight: bold; + margin-top: 0.4em; +} +.details .header2 { + font-weight: bold; + padding-left: 0.9em; +} +.details .key { + padding-left: 1.1em; + vertical-align: top; +} +.details .value { + text-align: right; + color: #333; + font-weight: bold; +} +.details .zebra { + background: #EEE; +} +.lower { + text-transform: lowercase; +} +</style> +<script> + +/* Counter accessor for Name Node. */ +function getCounterNameFromCounterNode(node) { + return node.childNodes[1]; +} + +/* Counter accessor for Value Node. */ +function getCounterValueFromCounterNode(node) { + return node.childNodes[3]; +} + +/* Counter accessor for Delta Node. */ +function getCounterDeltaFromCounterNode(node) { + return node.childNodes[5]; +} + +/* Timer accessor for Name Node. */ +function getTimerNameFromTimerNode(node) { + return node.childNodes[1]; +} + +/* Timer accessor for Value Node. */ +function getTimerValueFromTimerNode(node) { + return node.childNodes[3]; +} + +/* Timer accessor for Time Node. */ +function getTimerTimeFromTimerNode(node) { + return node.childNodes[5]; +} + +/* Timer accessor for Average Time Node. */ +function getTimerAvgTimeFromTimerNode(node) { + return node.childNodes[7]; +} + +/* Do the filter work. Hide all nodes matching node.*/ +function filterMatching(text, nodelist, functionToGetNameNode) { + var showAll = text.length == 0; + for (var i = 0, node; node = nodelist[i]; i++) { + var name = functionToGetNameNode(node).innerHTML.toLowerCase(); + if (showAll || name.indexOf(text) >= 0) { + node.style.display = "table-row"; + } else { + node.style.display = "none"; + } + } +} + +/* Hides or shows counters based on the user's current filter selection. */ +function doFilter() { + var filter = document.getElementById("filter"); + var text = filter.value.toLowerCase(); + var nodes = document.getElementsByName("counter"); + filterMatching(text, nodes, getCounterNameFromCounterNode); + var nodes = document.getElementsByName("timer"); + filterMatching(text, nodes, getTimerNameFromTimerNode); +} + +/* Colors the counters based on increasing or decreasing value. */ +function doColor() { + var nodes = document.getElementsByName("counter"); + for (var i = 0, node; node = nodes[i]; i++) { + var child = getCounterDeltaFromCounterNode(node); + var delta = child.innerHTML; + if (delta > 0) { + child.style.color = "Green"; + } else if (delta == 0) { + child.style.color = "Black"; + } else { + child.style.color = "Red"; + } + } +} + +/* Counters with no values are null. Remove them. */ +function removeNullValues() { + var nodes = document.getElementsByName("counter"); + for (var i = nodes.length - 1; i >= 0; i--) { + var node = nodes[i]; + var value = getCounterValueFromCounterNode(node).innerHTML; + if (value == "null") { + node.parentNode.removeChild(node); + } + } + var nodes = document.getElementsByName("timer"); + for (var i = 0, node; node = nodes[i]; i++) { + var value_node = getTimerValueFromTimerNode(node); + if (value_node.innerHTML == "null") { + value_node.innerHTML = ""; + } + } +} + +/* Compute the average time for timers */ +function computeTimes() { + var nodes = document.getElementsByName("timer"); + for (var i = 0, node; node = nodes[i]; i++) { + var count = getTimerValueFromTimerNode(node).innerHTML; + if (count.length > 0) { + var time = getTimerTimeFromTimerNode(node).innerHTML; + var avg = getTimerAvgTimeFromTimerNode(node); + avg.innerHTML = Math.round(time / count * 100) / 100; + } + } +} + +/* All the work we do onload. */ +function onLoadWork() { + doColor(); + removeNullValues(); + computeTimes(); + document.getElementById("filter").focus(); +} + +// The function should only be used as the event handler +// on a table cell element. To use it, put it in a <td> element: +// <td onclick="sort('string')" ...> +// +// The function sorts rows after the row with onclick event handler. +// +// type: the data type, 'string', 'number' +function sort_table(type){ + var cell = event.target; + var cnum = cell.cellIndex; + + var row = cell.parentNode; + var start_index = row.rowIndex + 1; + + var tbody = row.parentNode; + var table = tbody.parentNode; + + var rows = new Array(); + + var indexes = new Array(); + // skip the first row + for (var i = start_index; i < table.rows.length; i++) + rows.push(table.rows[i]); + + // a, b are strings + function compare_strings(a,b) { + if (a == b) return 0; + if (a < b) return -1; + return 1; + } + + // a, b are numbers + function compare_numbers(a,b) { + var x = isNaN(a) ? 0 : a; + var y = isNaN(b) ? 0 : b; + return x - y; + } + + var sort_func = undefined; + if (type === 'string') { + sort_func = function(a, b) { + var x = a.cells[cnum].innerText; + var y = b.cells[cnum].innerText; + return compare_strings(x, y); + } ; + + } else if (type === 'number') { + sort_func = function(a, b) { + var x = parseFloat(a.cells[cnum].innerText); + var y = parseFloat(b.cells[cnum].innerText); + return compare_numbers(x, y); + } + } + + rows.sort(sort_func); + + // change tables + if (cell._reverse) { + for (var i = rows.length - 1; i >= 0; i--) + tbody.appendChild(rows[i]); + cell._reverse = false; + } else { + for (var i = 0; i < rows.length; i++) + tbody.appendChild(rows[i]); + cell._reverse = true; + } +} + +</script> +</head> +<body onload="onLoadWork()"> + <div style="float: right"> + <br>Filter: <input id="filter" type="text" value="" onkeyup="doFilter()"> + </div> + <h1 class="lower">About Stats</h1> + <h2>Shhh! This page is secret!</h2><br/> + <table class="details" cellspacing="0" cellpadding="0" border="0"> + <tbody> + <tr> + <td class="outer"> + <table cellspacing="0" cellpadding="0" border="0"> + <tbody> + <tr> + <td class="top" width="100">Counters</td> + <td class="top value" colspan=2></td> + </tr> + <tr> + <td class="header2 lower" width="200" onclick="sort_table('string')">name</td> + <td class="header2 lower" onclick="sort_table('number')">value</td> + <td class="header2 lower" onclick="sort_table('number')">delta</td> + </tr> + <tr jsselect="counters" name="counter"> + <td class="key" width="200" jscontent="name"></td> + <td class="value" jscontent="value"></td> + <td class="value" jscontent="delta"></td> + </tr> + </tbody> + </table> + </td> + <td width="15"/> + <td class="outer"> + <table cellspacing="0" cellpadding="0" border="0"> + <tbody> + <tr> + <td class="top" width="100">Timers</td> + <td class="top value"></td> + <td class="top value" colspan=3></td> + </tr> + <tr> + <td class="header2 lower" width="200" onclick="sort_table('string')">name</td> + <td class="header2 lower" onclick="sort_table('number')">count</td> + <td class="header2 lower" onclick="sort_table('number')">time (ms)</td> + <td class="header2 lower" onclick="sort_table('number')">avg time (ms)</td> + </tr> + <tr jsselect="timers" name="timer"> + <td class="key" width="200" jscontent="name"></td> + <td class="value" jscontent="value"></td> + <td class="value" jscontent="time"></td> + <td class="value"></td> + </tr> + </tbody> + </table> + </td> + </tr> + </tbody> + </table><br/> +</body> +</html> diff --git a/chrome/browser/resources/about_version.html b/chrome/browser/resources/about_version.html new file mode 100644 index 0000000..b56b3dd --- /dev/null +++ b/chrome/browser/resources/about_version.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> + +<!-- +about:version template page +--> + +<html id="t"> +<head> +<title jscontent="title"></title> +<style type="text/css"> +body { + background-color: Window; + color: WindowText; + font: message-box; +} +#outer { + text-align: left; +} +#name { + font-weight: bold; + font-size: 1.2em; +} +#logo { + float: left; + padding-right: 20px; + padding-bottom: 200px; +} +#useragent { + white-space: nowrap; + font-face: fixed; + font-size: 0.8em; +} +</style> +</head> +<body> +<!-- TODO: figure out a way to embed a real image --> +<img id="logo" src="http://www.google.com/intl/en_ALL/images/logo.gif" /> +<div id="outer"> +<div id="name" jscontent="name"></div> +<div id="version"><span jscontent="version"></span> (<span jscontent="cl"></span>)</div> +<div id="official" jscontent="official"></div> +<div id="company" jscontent="company"></div> +<div id="copyright" jscontent="copyright"></div> +<div id="useragent" jscontent="useragent"></div> +</div> +</body> +</html> diff --git a/chrome/browser/resources/browser_resources.vcproj b/chrome/browser/resources/browser_resources.vcproj new file mode 100644 index 0000000..a0a0b69 --- /dev/null +++ b/chrome/browser/resources/browser_resources.vcproj @@ -0,0 +1,109 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="8.00" + Name="browser_resources" + ProjectGUID="{B95AB527-F7DB-41E9-AD91-EB51EE0F56BE}" + RootNamespace="browser_resources" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + <ToolFile + RelativePath="..\..\tools\build\win\flattened_html_file.rules" + /> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + ConfigurationType="10" + InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\debug.vsprops" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="Flattened HTML Resource" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + ConfigurationType="10" + InheritedPropertySheets="$(SolutionDir)..\build\common.vsprops;$(SolutionDir)..\build\release.vsprops" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="Flattened HTML Resource" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <File + RelativePath=".\about_memory.html" + > + </File> + <File + RelativePath=".\about_stats.html" + > + </File> + <File + RelativePath=".\new_tab.html" + > + </File> + <File + RelativePath=".\incognito_tab.html" + > + </File> + <File + RelativePath=".\safe_browsing_malware_block.html" + > + </File> + <File + RelativePath=".\safe_browsing_phishing_block.html" + > + </File> + <File + RelativePath="..\security\resources\ssl_error.html" + > + </File> + <File + RelativePath="..\security\resources\ssl_roadblock.html" + > + </File> + <File + RelativePath="..\security\resources\ssl_roadblock_background.png" + > + </File> + <File + RelativePath="..\security\resources\ssl_roadblock_icon.png" + > + </File> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/chrome/browser/resources/debugger_shell.js b/chrome/browser/resources/debugger_shell.js new file mode 100644 index 0000000..4685896 --- /dev/null +++ b/chrome/browser/resources/debugger_shell.js @@ -0,0 +1,1246 @@ +// Copyright 2008 Google Inc. +// All Rights Reserved. + +// TODO(erikkay): look into how this can be split up into multiple files +// It's currently loaded explicitly by Chrome, so maybe I need an "include" +// or "source" builtin to allow a core source file to reference multiple +// sub-files. + +/** + * @fileoverview Shell objects and global helper functions for Chrome + * automation shell / debugger. This file is loaded into the global namespace + * of the interactive shell, so users can simply call global functions + * directly. + * @author erikkay@google.com (Erik Kay) + */ + +/** + * 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) { + var json = '{'; + for (var key in obj) { + 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. + * @see http://wiki/Main/V8Debugger + */ +DebugCommand.prototype.toJSONProtocol = function() { + 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 simple commands which have no arguments. + * @see DebugCommand.commands + * @param {string} str The arguments to be parsed. + * @return -1 for usage error, 1 for success + */ +DebugCommand.parseSimpleCommand_ = function(str) { + return str.length ? -1 : 1; +}; + +/** + * 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. + * @see http://wiki/Main/V8Debugger + * @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.type = "shell"; + return 0; + } 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. + * @see http://wiki/Main/V8Debugger + * @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. + * @see http://wiki/Main/V8Debugger + * @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. + * @see http://wiki/Main/V8Debugger + * @param {Object} msg - the V8 debugger response object + */ +DebugCommand.responseClear_ = function(msg) { + shell_.clearedBreakpoint(parseInt(msg.command.arguments.breakpoint)); +} + +/** + * 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. + * @see http://wiki/Main/V8Debugger + * @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 + " " + 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. + * @see http://wiki/Main/V8Debugger + * @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. + * @see http://wiki/Main/V8Debugger + * @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. + * @see http://wiki/Main/V8Debugger + * @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. + * @see http://wiki/Main/V8Debugger + * @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) { + this.type = "request"; + } else if (ret < 0) { + 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.parseSimpleCommand_, + '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 = []; + this.debug = false; + this.last_msg = undefined; + this.last_command = 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; + chrome.setDebuggerReady(this.ready); + } +}; + +DebugShell.prototype.set_running = function(running) { + if (running != this.running) { + this.running = running; + chrome.setDebuggerBreak(!this.running); + } +}; + +/** + * Execute a constructed DebugCommand object if possible, otherwise pend. + * @param cmd {DebugCommand} - command to execute + */ +DebugShell.prototype.process_command = function(cmd) { + if (this.current_command) { + this.pending_commands.push(cmd); + dprint("pending command: " + DebugCommand.toJSON(cmd)); + } else if (cmd.type == "shell") { + if (cmd.user_command == "break") { + if (this.running) { + this.tab.debugBreak(); + this.set_ready(false); + } else { + print(">>already paused"); + } + } + this.last_command = cmd; + } else if (cmd.type == "request") { + // If the page is running, then the debugger isn't listening to certain + // requests. + var cmd_info = DebugCommand.commands[cmd.user_command]; + if (this.running && !cmd_info['while_running']) { + print(cmd.user_command + " can only be run while paused"); + } else { + this.current_command = cmd; + cmd.sendToDebugger(this.tab); + this.set_ready(false); + } + } + this.last_command = cmd; +}; + +/** + * 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); + this.set_ready(true); + 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) { + 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. + print(location); + } + } + if (source) + print(source); + this.last_break_location = location; + } +}; + +/** + * 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; + this.process_command(cmd); + } + } else { + print(">>not connected to a tab"); + } +}; + +/** + * Called by Chrome Shell when a response to a previous command has been + * received. + */ +DebugShell.prototype.response = function(str) { + var msg; + try { + dprint("received: " + str); + msg = eval('(' + str + ')'); + this.last_msg = msg; + } catch (error) { + print(error.toString(), str); + return; + } + if (msg.type == "event") { + ev = msg["event"] + if (ev == "break") { + this.event_break(msg); + } else if (ev == "exception") { + this.event_exception(msg); + } else if (ev == "attach") { + var title = this.tab.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); + } + } 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); + if (this.pending_commands.length) { + this.process_command(this.pending_commands.shift()); + } + } +}; + +/** + * 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 + * 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"); +} + +/** + * Global function to enter the debugger using DebugShell. + * User can access this in the external shell by simply typing "debug()". + * This is called by the Chrome Shell when the shell attaches to a tab. + * @param {Object} opt_tab - which tab is to be debugged. This is an internal + * Chrome object. + */ +function debug(opt_tab) { + shell(new DebugShell(opt_tab || chrome.browser[0].tab[0])); +}; + +/** + * 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; +} diff --git a/chrome/browser/resources/gear.png b/chrome/browser/resources/gear.png Binary files differnew file mode 100644 index 0000000..3dce105 --- /dev/null +++ b/chrome/browser/resources/gear.png diff --git a/chrome/browser/resources/help.gif b/chrome/browser/resources/help.gif Binary files differnew file mode 100644 index 0000000..f49c094 --- /dev/null +++ b/chrome/browser/resources/help.gif diff --git a/chrome/browser/resources/incognito_tab.html b/chrome/browser/resources/incognito_tab.html new file mode 100644 index 0000000..6d34646 --- /dev/null +++ b/chrome/browser/resources/incognito_tab.html @@ -0,0 +1,31 @@ +<html id="t" jsvalues="dir:textdirection"> +<head> +<title jscontent="title"></title> +<style type="text/css"> +body { + margin:10px 8px 10px 8px; +} +.icon { + float:right; + margin:0px 6px 0px 3px; +} +.content { + -webkit-border-radius: 5px 5px; + background-color:#eee; + color:black; + padding:10px 10px 10px 10px; + font-family:arial; + font-size:84%; + max-width:600px; + margin-left:auto; + margin-right:auto; +} +</style> +</head> +<body> +<div class="content"> + <img src="../../app/theme/otr_icon_standalone.png" class="icon" /> + <span jseval="this.innerHTML = $this.content;"></span> +</div> +</body> +</html> diff --git a/chrome/browser/resources/new_tab.html b/chrome/browser/resources/new_tab.html new file mode 100644 index 0000000..133b8b6 --- /dev/null +++ b/chrome/browser/resources/new_tab.html @@ -0,0 +1,624 @@ +<html id="t" jsvalues="dir:textdirection;newsession:newsession"> +<!-- + This page is optimized for perceived performance. Our enemies are the time + taken for the backend to generate our data, and the time taken to parse + and render the starting HTML/CSS content of the page. This page is + designed to let Chrome do both of those things in parallel. + + 1. Defines temporary content callback functions + 2. Fires off requests for content (these can come back 20-150ms later) + 3. Defines basic functions (handlers) + 4. Renders a fast-parse hard-coded version of itself (this can take 20-50ms) + 5. Defines the full content-rendering functions + + If the requests for content come back before the content-rendering functions + are defined, the data is held until those functions are defined. +--> +<script type="text/javascript"> +/* Logging info for benchmarking purposes. */ +var log = []; +function logEvent(name) { + log.push([name, new Date().getTime()]); +} + +// Basic functions to send, receive, store and process the data from our +// backend. +var unprocessedData = { + mostVisitedPages : false, + searchURLs : false, + recentlyBookmarked : false, + recentlyClosedTabs : false +} + +var renderFunctionsDefined = false; + +/** + * If the functions that can render content are defined, render + * the content for any data we've received so far. + */ +function processData() { + if (renderFunctionsDefined) { + if (unprocessedData.mostVisitedPages) { + renderMostVisitedPages(unprocessedData.mostVisitedPages); + unprocessedData.mostVisitedPages = false; + } + if (unprocessedData.searchURLs) { + renderSearchURLs(unprocessedData.searchURLs); + unprocessedData.searchURLs = false; + } + if (unprocessedData.recentlyBookmarked) { + renderRecentlyBookmarked(unprocessedData.recentlyBookmarked); + unprocessedData.recentlyBookmarked = false; + } + if (unprocessedData.recentlyClosedTabs) { + renderRecentlyClosedTabs(unprocessedData.recentlyClosedTabs); + unprocessedData.recentlyClosedTabs = false; + } + } +} + +function mostVisitedPages(data) { + logEvent('received most visited pages'); + unprocessedData.mostVisitedPages = data; + processData(); +} + +function searchURLs(data) { + logEvent('received search URLs'); + unprocessedData.searchURLs = data; + processData(); +} + +function recentlyBookmarked(data) { + logEvent('received recently bookmarked data'); + unprocessedData.recentlyBookmarked = data; + processData(); +} + +function recentlyClosedTabs(data) { + logEvent('received recently closed tabs'); + unprocessedData.recentlyClosedTabs = data; + processData(); +} + +chrome.send("getMostVisited"); +chrome.send("getMostSearched"); +chrome.send("getRecentlyBookmarked"); +chrome.send("getRecentlyClosedTabs"); + +function handleWindowResize() { + if (!document.body || document.body.clientWidth < 10) { + // We're probably a background tab, so don't do anything. + return; + } + + if (document.body.className == 'small' && document.body.clientWidth >= 885) { + document.body.className = ''; + } else if (document.body.className == '' && document.body.clientWidth <= 865) { + document.body.className = 'small'; + } +} + +function handleInputFocus() { + if (!this.deftext) { + this.deftext = this.value; + } + + if (this.value == this.deftext) { + this.className = ''; + this.value = ''; + } +} + +function handleInputBlur() { + if (!this.value) { + this.className = 'hint'; + this.value = this.deftext; + } +} + +function handleDOMContentLoaded() { + logEvent('domcontentloaded fired'); + + if (document.getElementById('motd').innerHTML) { + document.getElementById('motd').style.display = 'block'; + } +} + +logEvent('log start'); +</script> +<head> +<title jscontent="title"></title> +<style type="text/css"> +body { + font-family:arial; + background-color:white; + font-size:84%; + margin:0px; +} +html[newsession='true'] #main { + opacity:0.0; + -webkit-transition:all 0.4s; +} +html[newsession='true'] #main.visible { + /* unfortunately, 1.0 results in no animation */ + opacity:0.999; +} +#main { + margin-left:auto; + margin-right:auto; + margin-top:10px; +} +td { + font-size:84%; +} +form { + padding: 0; + margin: 0; +} +.section { + padding:3px 0px 5px 0px; + margin-bottom:30px; +} +.section-title { + color:#000; + line-height:19pt; + font-size:110%; + font-weight:bold; + margin-bottom:4px; +} +#mostvisitedsection { + margin:0px 5px 0px 0px; +} +#mostvisited td { + padding:0px 10px 10px 0px; +} +html[dir='rtl'] #mostvisited td { + padding:0px 0px 10px 10px; +} +.most-visited-text { + width:548px; /* thumbnail + td * 3 - 2*padding - 2*margin */ + padding:20px; + margin:15px; + background-color:white; + -webkit-box-shadow: 5px 5px 10px #ccc; + -webkit-transition:all 0.12s; +} +#motd { + background-color:#ffc; + padding:5px; + margin-bottom:9px; + width:610px; + -webkit-transition:all 0.12s; +} +.thumbnail-title { + background-image:url(chrome-resource://favicon/); + display:block; + background-repeat:no-repeat; + background-size:16px; + background-position:0px 1px; + width:172px; /* thumbnail - padding */ + margin-top:6px; /* line up favicons with search favicons */ + padding:1px 0px 4px 22px; + overflow: hidden; + text-overflow: ellipsis; + text-decoration:none; + -webkit-transition:all 0.12s; +} +html[dir='rtl'] .thumbnail-title { + background-position:right; + padding-left:0px; + padding-right:22px; +} +.thumbnail { + width:195px; + height:136px; + border:1px solid #ccc; + background-color:#eee; + -webkit-transition:all 0.12s; +} +a.thumbnail { + border:1px solid #abe; +} + +.small #motd { + width:480px; +} +.small .thumbnail-title { + width:127px; +} +.small .thumbnail { + width:150px; + height:113px; +} +.small .most-visited-text { + width:430px; + padding:15px; + margin:12px; +} + +.recent-bookmark { + display:block; + background-repeat:no-repeat; + background-size:16px; + background-position:0px 1px; + padding:1px 0px 0px 22px; + margin:3px 0px 3px 0px; + min-height:16pt; + line-height:16px; + overflow: hidden; + text-overflow: ellipsis; + text-decoration:underline; +} +html[dir='rtl'] .recent-bookmark { + background-position:right; + padding-left:0px; + padding-right:22px; +} +a { + color:#0000cc; + text-decoration:underline; + white-space: nowrap; +} +a.manage { + color:#77c; + margin-left: 5px; + margin-right: 5px; + font-size:84%; + line-height:19pt; + text-decoration:underline; +} +html[dir='rtl'] #managesearcheslink { + float: left; +} +.sidebar { + width: 207px; + padding:3px 10px 3px 9px; + -webkit-border-radius:5px 5px; + margin-bottom:10px; +} +#searches { + background-color:#e1ecfe; +} +#recentlyBookmarked { + background-color:#e1ecfe; +} +#recentlyClosedTabs { + background-color:#fff1a8; +} +#searches input { + border:1px solid #7f9db9; + background-repeat: no-repeat; + background-position:4px center; + padding-left: 23px; + min-height:24px; + width:206px; + margin-bottom:8px; + display:block; +} +html[dir='rtl'] #searches input { + background-position: right; + padding-right: 23px; +} +#searches input.hint { + color:#aaa; +} +.footer { + border-top:1px solid #ccc; + padding-top:4px; + font-size:8pt; +} +</style> +</head> +<body onload="logEvent('body onload fired');"> +<script> +// We apply the size class here so that we don't trigger layout animations onload. +handleWindowResize(); +window.addEventListener('resize', handleWindowResize, true); +document.addEventListener('DOMContentLoaded', handleDOMContentLoaded); +</script> + +<table id="main" cellpadding="0" cellspacing="0" border="0"> + <tr> + <td valign="top"> + <div id="mostvisitedsection" class="section"> + <div id="motd" jscontent="motd" style="display:none;"></div> + <div id="mostvisited" style="position:relative;"> + <div class="section-title" jscontent="mostvisited"></div> + <div id="mostvisitedintro" style="display:none;"> + <div class="most-visited-text" style="position:absolute;" jseval="this.innerHTML = $this.mostvisitedintro;"></div> + <table> + <tr> + <td><div class="thumbnail"> </div></td> + <td><div class="thumbnail"></div></td> + <td><div class="thumbnail"> </div></td> + </tr> + <tr> + <td><div class="thumbnail"> </div></td> + <td><div class="thumbnail"></div></td> + <td><div class="thumbnail"> </div></td> + </tr> + </table> + </div> + <table id="mostvisitedtable"> + <!-- This content forces the view to the correct width and provides a + preview of what's to load to reduce white-flash. Users who get + the mostvisitedintro will see a brief flash of this content. We + only use one row so that we may avoid flashing extra rows when + the user has only one row of items --> + <tr> + <td> + <div class="thumbnail-title"> </div> + <div class="thumbnail"></div> + </td> + <td> + <div class="thumbnail-title"> </div> + <div class="thumbnail"></div> + </td> + <td> + <div class="thumbnail-title"> </div> + <div class="thumbnail"></div> + </td> + </tr> + </table> + </div> + <a href="#" + class="manage" + onclick="chrome.send('showHistoryPage'); return false"> + <span jscontent="showhistory"></span> »</a> + </div> + </td> + <td valign="top" width="230"> + <div align="right"> + <img src="../../app/theme/product_logo.png" + width="145" height="52" style="padding-bottom:8px;" /> + </div> + <div id="searches" class="sidebar"> + <div class="section-title" jscontent="searches"></div> + <form onsubmit="chrome.send('searchHistoryPage', [this.search.value]); return false;"> + <input type="text" class="hint" + name="search" + style="background-image:url(chrome-resource://favicon/);" + jsvalues="value:searchhistory" + onfocus="handleInputFocus.apply(this);" + onblur="handleInputBlur.apply(this);" /> + </form> + <div id='searches-entries'></div> + </div> + + <div id="recentlyBookmarked" class="sidebar" style="display:none"> + <span class="section-title" jscontent="bookmarks"></span> + </div> + + <div id="recentlyClosedTabs" class="sidebar" style="display:none"> + <div class="section-title" jscontent="closedtabs"></div> + <div id="recentlyClosedContainer"></div> + </div> + </td> + </tr> +</table> + +<script type="text/javascript"> +logEvent('start of second script block'); + +/* Return a DOM element with tag name |elem| and attributes |attrs|. */ +function DOM(elem, attrs) { + var elem = document.createElement(elem); + for (var attr in attrs) { + elem[attr] = attrs[attr]; + } + return elem; +} + +/* Return the DOM element for a "most visited" entry. + |page| should be an object with "title" and "url" fields. */ +function makeMostVisitedDOM(page) { + /* The HTML we want looks like this: + <a class="most-visited-item" href="URL" title="gmail.com"> + <div class="thumbnail-title" style="background-image:url(faviconurl);">gmail.com</div> + <img class="thumbnail" style="background-image:url(thumbnailurl);" /> + </a> + */ + var root = DOM('a', {href:page.url, className:'most-visited-item', title:page.title}); + + /* Create the thumbnail */ + var img_thumbnail = DOM('img', {className:'thumbnail'}); + img_thumbnail.setAttribute('onload', "logEvent('image loaded');"); + img_thumbnail.src = 'chrome-resource://thumb/' + page.url; + + /* Create the title */ + var div_title = DOM('div', {className:'thumbnail-title'}); + div_title.style.backgroundImage = + 'url("chrome-resource://favicon/' + page.url + '")'; + div_title.appendChild(document.createTextNode(page.title)); + + root.appendChild(div_title); + root.appendChild(img_thumbnail); + + return root; +} + +/* This function is called by the browser with the most visited pages list. + |pages| is a list of page objects, which have url and title attributes. */ +function renderMostVisitedPages(pages) { + logEvent('renderMostVisitedPages called: ' + pages.length); + + document.getElementById("main").className = 'visible'; + var table = document.getElementById("mostvisitedtable"); + table.innerHTML = ''; + + // Show the most visited helptext if most visited is still useless. This is + // a crappy heuristic. + if (pages.length < 3) { + document.getElementById("mostvisitedintro").style.display = "block"; + return; + } + + document.getElementById('mostvisitedintro').style.display = 'none'; + + // Create the items and add them to rows. + var rows = []; + var rowNum = -1; + for (var i = 0, page; page = pages[i]; ++i) { + if (i % 3 == 0) { + rowNum += 1; + rows[rowNum] = DOM('tr', {}); + } + + var dom = makeMostVisitedDOM(page); + + var cell = DOM('td'); + cell.appendChild(dom); + + rows[rowNum].appendChild(cell); + + logEvent('mostVisitedPage : ' + i); + } + + // Add the rows to the table. + for (var i = 0, row; row = rows[i]; i++) { + table.appendChild(row); + } + + logEvent('renderMostVisitedPages done'); +} + +function makeSearchURL(url) { + /* The HTML we want looks like this: + <form> + <input type="text" class="hint" + style="background-image:url(chrome-resource://favicon/"+url+");" + value="Search Wikipedia" + onfocus="handleInputFocus();" + onblur="handleInputBlur();" /> + </form> + */ + var input = DOM('input', {type:'text', + className:'hint', + value:url.short_name}); + input.keyword = url.keyword; + + if (url.favIconURL) { + input.style.backgroundImage = + 'url("chrome-resource://favicon/iconurl/' + url.favIconURL + '")'; + } else { + input.style.backgroundImage = + 'url("chrome-resource://favicon/http://' + url.short_name + '")'; + } + + input.onfocus = handleInputFocus; + input.onblur = handleInputBlur; + + var form = DOM('form'); + form.onsubmit = function() { + chrome.send('doSearch', [input.keyword, input.value]); + return false; + }; + form.appendChild(input); + + return form; +} + +/* This function is called by the browser when the list of search URLs is + available. |urls| is a list of objects with |name| attributes. */ +function renderSearchURLs(urls) { + logEvent('renderSearchURLs called: ' + urls.length); + var container = document.getElementById('searches-entries'); + container.innerHTML = ''; // Clear out any previous contents. + if (urls.length > 0) { + document.getElementById('searches').style.display = 'block'; + for (var i = 0; i < urls.length; ++i) { + container.appendChild(makeSearchURL(urls[i])); + } + } + + logEvent('renderSearchURLs done'); +} + +/* This function is called by the browser when the list of recently bookmarked + URLs is available. |entries| is a list of objects with title and url + attributes. */ +function renderRecentlyBookmarked(entries) { + logEvent('renderRecentlyBookmarked called: ' + entries.length); + var container = document.getElementById('recentlyBookmarked'); + + if (entries.length > 0) { + container.style.display = 'block'; + for (var i = 0, entry = entries[0]; entry = entries[i]; ++i) { + var link = DOM('a', {href: entry.url, className:'recent-bookmark', title:entry.title}); + link.style.backgroundImage = + 'url("chrome-resource://favicon/' + entry.url + '")'; + link.appendChild(document.createTextNode(entry.title)); + container.appendChild(link); + } + } + + logEvent('renderRecentlyBookmarked done'); +} + +/* This function adds incoming information about tabs to the new tab UI. */ +function renderRecentlyClosedTabs(entries) { + logEvent('renderRecentlyClosedTabs begin'); + var section = document.getElementById('recentlyClosedTabs'); + var container = document.getElementById('recentlyClosedContainer'); + + /* recentlyClosedTabs is called on every internal event which + affects tab history to make sure things are up to + date. Therefore, reset the recentlyClosedTabs state on every + call. */ + section.style.display = 'none'; + while(container.hasChildNodes()) { + container.removeChild(container.firstChild); + } + + if (entries.length > 0) { + section.style.display = 'block'; + + for (var i = 0; entry = entries[i]; ++i) { + var link = DOM('a', {href:entry.url, className:'recent-bookmark', title:entry.title}); + + link.onclick = function(sessionId) { + return function() { + /* This is a hack because chrome.send is hardcoded to only + accept arrays of strings. */ + chrome.send('reopenTab', [sessionId.toString()]); + return false; + } + }(entry.sessionId); + + link.style.backgroundImage = 'url("chrome-resource://favicon/' + entry.url + '")'; + link.appendChild(document.createTextNode(entry.title)); + container.appendChild(link); + } + } + + logEvent('renderRecentlyClosedTabs done'); +} + +function viewLog() { + var lines = []; + var start = log[0][1]; + + for (var i = 0; i < log.length; i++) { + lines.push((log[i][1] - start) + ': ' + log[i][0]); + } + + var lognode = document.createElement('pre'); + lognode.appendChild(document.createTextNode(lines.join("\n"))); + document.body.appendChild(lognode); +} + +logEvent('end of second script block'); + +// We've got all the JS we need, render any unprocessed data. +renderFunctionsDefined = true; +processData(); + +// In case renderMostVisitedItems doesn't come back quickly enough, begin +// the first-run fade-in. If it has started or if this is not a first +// run new tab, this will be a no-op. +setTimeout(function(){document.getElementById('main').className = 'visible'}, + 1000); +</script> +</body> +</html> diff --git a/chrome/browser/resources/phishing_icon.png b/chrome/browser/resources/phishing_icon.png Binary files differnew file mode 100644 index 0000000..b23e76b --- /dev/null +++ b/chrome/browser/resources/phishing_icon.png diff --git a/chrome/browser/resources/safe_browsing_malware_block.html b/chrome/browser/resources/safe_browsing_malware_block.html new file mode 100644 index 0000000..1e815ea --- /dev/null +++ b/chrome/browser/resources/safe_browsing_malware_block.html @@ -0,0 +1,102 @@ +<html id="template_root" jsvalues="dir:textdirection"> +<head> +<title jscontent="title"></title> +<style type="text/css"> +body { + background-color:#500; + font-family:arial; + margin:0px; +} +.background { + position:absolute; + width:100%; + height:100%; +} +.cell { + padding:40px; +} +.box { + width:80%; + background-color:white; + color:black; + font-size:10pt; + line-height:16pt; + text-align:left; + padding:20px; + position:relative; + -webkit-box-shadow:3px 3px 8px #200; + -webkit-border-radius:5px; +} +html[dir='rtl'] .box { + text-align:right; +} + +.icon { + position:absolute; +} +.title { + margin:0px 87px 0px; + font-size:18pt; + margin-bottom:6pt; + font-weight:bold; + color:#660000; +} +.main { + margin:0px 90px 0px; +} +.submission { + margin:15px 5px 15px 0px; + padding:0px; +} +input { + margin:0px; +} +.proceedbutton { +} +.helpbutton { + float:right; +} +.example { + margin: 30px 90px 0px; + border-top:1px solid #ccc; + padding-top:6px; +} +.moreinfotitle { + margin-left:5px; + margin-right:5px; +} +</style> + +<script> + function sendCommand(cmd) { + window.domAutomationController.setAutomationId(1); + window.domAutomationController.send(cmd); + } + + function agreed(form) { + form.continue_button.disabled = !form.continue_button.disabled; + } +</script> +</head> +<body oncontextmenu="return false;"> +<div class="background"><img src="../security/resources/ssl_roadblock_background.png" width="100%" height="100%" alt="background" /></div> +<table width="100%" cellspacing="0" cellpadding="0"> + <td class="cell" valign="middle" align="center"> + <div class="box"> + <div class="icon"><img src="phishing_icon.png" alt="Malware Icon" /></div> + <div class="title" jscontent="headLine"></div> + <div class="main" jseval="this.innerHTML = $this.description1;"></div> + <div class="main" jseval="this.innerHTML = $this.description2;"></div> + <div class="main"><a href="" jscontent="description3" onclick="sendCommand(2); return false;"></a></div> + <div class="main"> + <form class="submission"> + <input name="checky" type="checkbox" onclick="agreed(this.form)"> <span jscontent="confirm_text"></span> + <input type="button" name="continue_button" jsvalues="value:continue_button" disabled="true" onclick="sendCommand(1)"><br> + <input type="button" name="back_button" jsvalues="value:back_button" onclick="sendCommand(0)"> + </form> + </div> + </div> + </td> +</table> +</body> +</html> diff --git a/chrome/browser/resources/safe_browsing_phishing_block.html b/chrome/browser/resources/safe_browsing_phishing_block.html new file mode 100644 index 0000000..2731f82 --- /dev/null +++ b/chrome/browser/resources/safe_browsing_phishing_block.html @@ -0,0 +1,103 @@ +<html id="template_root" jsvalues="dir:textdirection"> +<head> +<title jscontent="title"></title> +<style type="text/css"> +body { + background-color:#500; + font-family:arial; + margin:0px; +} +.background { + position:absolute; + width:100%; + height:100%; +} +.cell { + padding:40px; +} +.box { + width:80%; + background-color:white; + color:black; + font-size:10pt; + line-height:16pt; + text-align:left; + padding:20px; + position:relative; + -webkit-box-shadow:3px 3px 8px #200; + -webkit-border-radius:5px; +} +html[dir='rtl'] .box { + text-align:right; +} +.icon { + position:absolute; +} +.title { + margin: 0px 87px 0px; + font-size:18pt; + margin-bottom:6pt; + font-weight:bold; + color:#660000; +} +.main { + margin:0px 90px 0px; +} +.submission { + margin:15px 5px 15px 0px; + padding:0px; +} +input { + margin:0px; +} +.proceedbutton { +} +.helpbutton { + float:right; +} +html[dir='rtl'] .helpbutton { + float:left; +} +.example { + margin: 30px 90px 0px; + border-top:1px solid #ccc; + padding-top:6px; +} +.moreinfotitle { + margin-left:5px; + margin-right:5px; +} +</style> + +<script> + function sendCommand(cmd) { + window.domAutomationController.setAutomationId(1); + window.domAutomationController.send(cmd); + } + + function agreed(form) { + form.continue_button.disabled = !form.continue_button.disabled; + } +</script> +</head> +<body oncontextmenu="return false;"> +<div class="background"><img src="../security/resources/ssl_roadblock_background.png" width="100%" height="100%" alt="background" /></div> +<table width="100%" cellspacing="0" cellpadding="0"> + <td class="cell" valign="middle" align="center"> + <div class="box"> + <div class="icon"><img src="phishing_icon.png" alt="Phishing Warning Icon" /></div> + <div class="title" jscontent="headLine"></div> + <div class="main" jseval="this.innerHTML = $this.description1;"></div> + <div class="main"><a href="" jscontent="description2" onclick="sendCommand(2); return false;"></a></div> + <div class="main"> + <form class="submission"> + <input type="button" name="continue_button" jsvalues="value:continue_button" onclick="sendCommand(1)"> + <input type="button" name="back_button" jsvalues="value:back_button" onclick="sendCommand(0)"> + </form> + </div> + <div class="main"><a href="" onclick="sendCommand(3); return false;" jscontent="report_error"></a></div> + </div> + </td> +</table> +</body> +</html> diff --git a/chrome/browser/resources/ssl_error.html b/chrome/browser/resources/ssl_error.html new file mode 100644 index 0000000..fe6414a --- /dev/null +++ b/chrome/browser/resources/ssl_error.html @@ -0,0 +1,22 @@ +<html id="template_root"> + +<head> + <title jscontent="title"></title> + <script> + function sendCommand(cmd) { + window.domAutomationController.setAutomationId(1); + window.domAutomationController.send(cmd); + } + </script> +</head> + +<body> + <h1 jscontent="headLine"></h1> + <div jscontent="description"></div> + <form a=""> + <input type="button" jsvalues="value:proceed" onClick="sendCommand(1);"/> + <input type="button" jsvalues="value:leave" onClick="sendCommand(0);"/> + </form> + +</body> +</html> |