Merge mozilla-central to mozilla-inbound

This commit is contained in:
Ed Morley 2012-06-01 16:58:27 +01:00
commit d522af1b80
115 changed files with 3926 additions and 967 deletions

View File

@ -1048,10 +1048,12 @@ pref("devtools.debugger.remote-autoconnect", false);
pref("devtools.debugger.remote-connection-retries", 3);
pref("devtools.debugger.remote-timeout", 3000);
// The default Debugger UI height
// The default Debugger UI settings
pref("devtools.debugger.ui.height", 250);
pref("devtools.debugger.ui.remote-win.width", 900);
pref("devtools.debugger.ui.remote-win.height", 400);
pref("devtools.debugger.ui.stackframes-width", 200);
pref("devtools.debugger.ui.variables-width", 300);
// Enable the style inspector
pref("devtools.styleinspector.enabled", true);

View File

@ -552,3 +552,16 @@ statuspanel[inactive][previoustype=overLink] {
/* highlighter */
%include highlighter.css
html|*#gcli-tooltip-frame,
html|*#gcli-output-frame,
#gcli-output,
#gcli-tooltip {
overflow-x: hidden;
}
.gclitoolbar-input-node,
.gclitoolbar-complete-node,
.gclitoolbar-prompt {
direction: ltr;
}

View File

@ -1034,8 +1034,10 @@
tooltiptext="&devToolbarCloseButton.tooltiptext;"/>
#endif
<stack class="gclitoolbar-stack-node" flex="1">
<description class="gclitoolbar-prompt">&#187;</description>
<description class="gclitoolbar-complete-node"/>
<hbox class="gclitoolbar-prompt">
<label class="gclitoolbar-prompt-label">&#187;</label>
</hbox>
<hbox class="gclitoolbar-complete-node"/>
<textbox class="gclitoolbar-input-node" rows="1"/>
</stack>
<toolbarbutton id="developer-toolbar-webconsole"

View File

@ -5,10 +5,23 @@
let EXPORTED_SYMBOLS = [ ];
Components.utils.import("resource:///modules/devtools/gcli.jsm");
Components.utils.import("resource:///modules/HUDService.jsm");
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource:///modules/devtools/gcli.jsm");
Cu.import("resource:///modules/HUDService.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Components.utils.import("resource:///modules/devtools/GcliTiltCommands.jsm", {});
Cu.import("resource:///modules/devtools/GcliTiltCommands.jsm", {});
XPCOMUtils.defineLazyGetter(this, "Services", function () {
var obj = {};
Cu.import("resource://gre/modules/Services.jsm", obj);
return obj.Services;
});
XPCOMUtils.defineLazyGetter(this, "LayoutHelpers", function () {
var obj = {};
Cu.import("resource:///modules/devtools/LayoutHelpers.jsm", obj);
return obj.LayoutHelpers;
});
/**
@ -31,6 +44,129 @@ gcli.addCommand({
});
/**
* 'screenshot' command
*/
gcli.addCommand({
name: "screenshot",
description: gcli.lookup("screenshotDesc"),
manual: gcli.lookup("screenshotManual"),
returnType: "string",
params: [
{
name: "filename",
type: "string",
description: gcli.lookup("screenshotFilenameDesc"),
manual: gcli.lookup("screenshotFilenameManual")
},
{
name: "delay",
type: { name: "number", min: 0 },
defaultValue: 0,
description: gcli.lookup("screenshotDelayDesc"),
manual: gcli.lookup("screenshotDelayManual")
},
{
name: "fullpage",
type: "boolean",
defaultValue: false,
description: gcli.lookup("screenshotFullPageDesc"),
manual: gcli.lookup("screenshotFullPageManual")
},
{
name: "node",
type: "node",
defaultValue: null,
description: gcli.lookup("inspectNodeDesc"),
manual: gcli.lookup("inspectNodeManual")
}
],
exec: function Command_screenshot(args, context) {
var document = context.environment.contentDocument;
if (args.delay > 0) {
var promise = context.createPromise();
document.defaultView.setTimeout(function Command_screenshotDelay() {
let reply = this.grabScreen(document, args.filename);
promise.resolve(reply);
}.bind(this), args.delay * 1000);
return promise;
}
else {
return this.grabScreen(document, args.filename, args.fullpage, args.node);
}
},
grabScreen:
function Command_screenshotGrabScreen(document, filename, fullpage, node) {
let window = document.defaultView;
let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
let left = 0;
let top = 0;
let width;
let height;
if (!fullpage) {
if (!node) {
left = window.scrollX;
top = window.scrollY;
width = window.innerWidth;
height = window.innerHeight;
} else {
let rect = LayoutHelpers.getRect(node, window);
top = rect.top;
left = rect.left;
width = rect.width;
height = rect.height;
}
} else {
width = window.innerWidth + window.scrollMaxX;
height = window.innerHeight + window.scrollMaxY;
}
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext("2d");
ctx.drawWindow(window, left, top, width, height, "#fff");
let data = canvas.toDataURL("image/png", "");
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
// Check there is a .png extension to filename
if (!filename.match(/.png$/i)) {
filename += ".png";
}
// If the filename is relative, tack it onto the download directory
if (!filename.match(/[\\\/]/)) {
let downloadMgr = Cc["@mozilla.org/download-manager;1"]
.getService(Ci.nsIDownloadManager);
let tempfile = downloadMgr.userDownloadsDirectory;
tempfile.append(filename);
filename = tempfile.path;
}
try {
file.initWithPath(filename);
} catch (ex) {
return "Error saving to " + filename;
}
let ioService = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
let Persist = Ci.nsIWebBrowserPersist;
let persist = Cc["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"]
.createInstance(Persist);
persist.persistFlags = Persist.PERSIST_FLAGS_REPLACE_EXISTING_FILES |
Persist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
let source = ioService.newURI(data, "UTF8", null);
persist.saveURI(source, null, null, null, null, file);
return "Saved to " + filename;
}
});
/**
* 'console' command
*/
@ -51,13 +187,13 @@ gcli.addCommand({
let hud = HUDService.getHudReferenceById(context.environment.hudId);
// Use a timeout so we also clear the reporting of the clear command
let threadManager = Components.classes["@mozilla.org/thread-manager;1"]
.getService(Components.interfaces.nsIThreadManager);
let threadManager = Cc["@mozilla.org/thread-manager;1"]
.getService(Ci.nsIThreadManager);
threadManager.mainThread.dispatch({
run: function() {
hud.gcliterm.clearOutput();
}
}, Components.interfaces.nsIThread.DISPATCH_NORMAL);
}, Ci.nsIThread.DISPATCH_NORMAL);
}
});
@ -135,9 +271,8 @@ gcli.addCommand({
}
],
exec: function(args, context) {
let hud = HUDService.getHudReferenceById(context.environment.hudId);
let StyleEditor = hud.gcliterm.document.defaultView.StyleEditor;
StyleEditor.openChrome(args.resource.element, args.line);
let win = HUDService.currentContext();
win.StyleEditor.openChrome(args.resource.element, args.line);
}
});
@ -160,7 +295,7 @@ gcli.addCommand({
returnType: "html",
exec: function(args, context) {
let win = HUDService.currentContext();
let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
let dbg = win.DebuggerUI.getDebugger();
if (!dbg) {
return gcli.lookup("breakaddDebuggerStopped");
}
@ -206,7 +341,7 @@ gcli.addCommand({
name: "selection",
data: function() {
let win = HUDService.currentContext();
let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
let dbg = win.DebuggerUI.getDebugger();
let files = [];
if (dbg) {
let scriptsView = dbg.contentWindow.DebuggerView.Scripts;
@ -229,7 +364,7 @@ gcli.addCommand({
exec: function(args, context) {
args.type = "line";
let win = HUDService.currentContext();
let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
let dbg = win.DebuggerUI.getDebugger();
if (!dbg) {
return gcli.lookup("breakaddDebuggerStopped");
}
@ -261,7 +396,7 @@ gcli.addCommand({
min: 0,
max: function() {
let win = HUDService.currentContext();
let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
let dbg = win.DebuggerUI.getDebugger();
if (!dbg) {
return gcli.lookup("breakaddDebuggerStopped");
}
@ -274,7 +409,7 @@ gcli.addCommand({
returnType: "html",
exec: function(args, context) {
let win = HUDService.currentContext();
let dbg = win.DebuggerUI.getDebugger(win.gBrowser.selectedTab);
let dbg = win.DebuggerUI.getDebugger();
if (!dbg) {
return gcli.lookup("breakaddDebuggerStopped");
}

View File

@ -2,23 +2,17 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
.gclichrome-output {
max-width: 350px;
}
.gclichrome-tooltip {
max-width: 350px;
}
.gcli-help-name {
text-align: end;
}
.gcli-out-shortcut,
.gcli-help-synopsis {
cursor: pointer;
display: inline-block;
}
.gcli-out-shortcut:before,
.gcli-help-synopsis:before {
content: '\bb';
}
@ -34,8 +28,9 @@
width: 100%;
}
.gcli-menu-error {
overflow: hidden;
white-space: nowrap;
.gcli-menu-name,
.gcli-out-shortcut,
.gcli-help-synopsis {
direction: ltr;
}

View File

@ -4157,7 +4157,7 @@ var ResourceCache = {
* Drop all cache entries. Helpful to prevent memory leaks
*/
clear: function() {
ResourceCache._cached = {};
ResourceCache._cached = [];
}
};
@ -8082,7 +8082,7 @@ define("text!gcli/commands/help_list.html", [], "\n" +
" <tr foreach=\"command in ${getMatchingCommands()}\"\n" +
" onclick=\"${onclick}\" ondblclick=\"${ondblclick}\">\n" +
" <th class=\"gcli-help-name\">${command.name}</th>\n" +
" <td class=\"gcli-help-arrow\">&#x2192;</td>\n" +
" <td class=\"gcli-help-arrow\">-</td>\n" +
" <td>\n" +
" ${command.description}\n" +
" <span class=\"gcli-out-shortcut\" data-command=\"help ${command.name}\">help ${command.name}</span>\n" +

View File

@ -15,6 +15,7 @@ include $(topsrcdir)/config/rules.mk
_BROWSER_TEST_FILES = \
browser_gcli_break.js \
browser_gcli_commands.js \
browser_gcli_edit.js \
browser_gcli_inspect.js \
browser_gcli_integrate.js \
browser_gcli_pref.js \
@ -26,6 +27,10 @@ _BROWSER_TEST_FILES = \
_BROWSER_TEST_PAGES = \
browser_gcli_break.html \
browser_gcli_inspect.html \
resources_inpage.js \
resources_inpage1.css \
resources_inpage2.css \
resources.html \
$(NULL)
libs:: $(_BROWSER_TEST_FILES)

View File

@ -0,0 +1,145 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that the edit command works
const TEST_URI = TEST_BASE_HTTP + "resources.html";
function test() {
DeveloperToolbarTest.test(TEST_URI, function(browser, tab) {
testEditStatus(browser, tab);
// Bug 759853
// testEditExec(browser, tab); // calls finish()
finish();
});
}
function testEditStatus(browser, tab) {
DeveloperToolbarTest.checkInputStatus({
typed: "edit",
markup: "VVVV",
status: "ERROR",
emptyParameters: [ " <resource>", " [line]" ],
});
DeveloperToolbarTest.checkInputStatus({
typed: "edit i",
markup: "VVVVVI",
status: "ERROR",
directTabText: "nline-css",
emptyParameters: [ " [line]" ],
});
DeveloperToolbarTest.checkInputStatus({
typed: "edit c",
markup: "VVVVVI",
status: "ERROR",
directTabText: "ss#style2",
emptyParameters: [ " [line]" ],
});
DeveloperToolbarTest.checkInputStatus({
typed: "edit http",
markup: "VVVVVIIII",
status: "ERROR",
directTabText: "://example.com/browser/browser/devtools/commandline/test/resources_inpage1.css",
arrowTabText: "",
emptyParameters: [ " [line]" ],
});
DeveloperToolbarTest.checkInputStatus({
typed: "edit page1",
markup: "VVVVVIIIII",
status: "ERROR",
directTabText: "",
arrowTabText: "http://example.com/browser/browser/devtools/commandline/test/resources_inpage1.css",
emptyParameters: [ " [line]" ],
});
DeveloperToolbarTest.checkInputStatus({
typed: "edit page2",
markup: "VVVVVIIIII",
status: "ERROR",
directTabText: "",
arrowTabText: "http://example.com/browser/browser/devtools/commandline/test/resources_inpage2.css",
emptyParameters: [ " [line]" ],
});
DeveloperToolbarTest.checkInputStatus({
typed: "edit stylez",
markup: "VVVVVEEEEEE",
status: "ERROR",
directTabText: "",
arrowTabText: "",
emptyParameters: [ " [line]" ],
});
DeveloperToolbarTest.checkInputStatus({
typed: "edit css#style2",
markup: "VVVVVVVVVVVVVVV",
status: "VALID",
directTabText: "",
emptyParameters: [ " [line]" ],
});
DeveloperToolbarTest.checkInputStatus({
typed: "edit css#style2 5",
markup: "VVVVVVVVVVVVVVVVV",
status: "VALID",
directTabText: "",
emptyParameters: [ ],
});
DeveloperToolbarTest.checkInputStatus({
typed: "edit css#style2 0",
markup: "VVVVVVVVVVVVVVVVE",
status: "ERROR",
directTabText: "",
emptyParameters: [ ],
});
DeveloperToolbarTest.checkInputStatus({
typed: "edit css#style2 -1",
markup: "VVVVVVVVVVVVVVVVEE",
status: "ERROR",
directTabText: "",
emptyParameters: [ ],
});
}
var windowListener = {
onOpenWindow: function(win) {
// Wait for the window to finish loading
let win = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow);
win.addEventListener("load", function onLoad() {
win.removeEventListener("load", onLoad, false);
win.close();
}, false);
win.addEventListener("unload", function onUnload() {
win.removeEventListener("unload", onUnload, false);
Services.wm.removeListener(windowListener);
finish();
}, false);
},
onCloseWindow: function(win) { },
onWindowTitleChange: function(win, title) { }
};
function testEditExec(browser, tab) {
Services.wm.addListener(windowListener);
var style2 = browser.contentDocument.getElementById("style2");
DeveloperToolbarTest.exec({
typed: "edit css#style2",
args: {
resource: function(resource) {
return resource.element.ownerNode == style2;
},
line: 1
},
completed: true,
blankOutput: true,
});
}

View File

@ -95,7 +95,7 @@ function testPrefStatus() {
DeveloperToolbarTest.checkInputStatus({
typed: "pref show devtools.toolbar.ena",
markup: "VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV",
markup: "VVVVVVVVVVIIIIIIIIIIIIIIIIIIII",
directTabText: "bled",
status: "ERROR",
emptyParameters: [ ]
@ -103,7 +103,7 @@ function testPrefStatus() {
DeveloperToolbarTest.checkInputStatus({
typed: "pref show hideIntro",
markup: "VVVVVVVVVVVVVVVVVVV",
markup: "VVVVVVVVVVIIIIIIIII",
directTabText: "",
arrowTabText: "devtools.gcli.hideIntro",
status: "ERROR",

View File

@ -2,6 +2,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const TEST_BASE_HTTP = "http://example.com/browser/browser/devtools/commandline/test/";
const TEST_BASE_HTTPS = "https://example.com/browser/browser/devtools/commandline/test/";
let console = (function() {
let tempScope = {};
Components.utils.import("resource:///modules/devtools/Console.jsm", tempScope);
@ -83,57 +86,69 @@ let DeveloperToolbarTest = {
* emptyParameters: [ "<message>" ], // Still to type
* directTabText: "o", // Simple completion text
* arrowTabText: "", // When the completion is not an extension
* markup: "VVVIIIEEE", // What state should the error markup be in
* });
*/
checkInputStatus: function DTT_checkInputStatus(test) {
if (test.typed) {
DeveloperToolbar.display.inputter.setInput(test.typed);
checkInputStatus: function DTT_checkInputStatus(tests) {
let display = DeveloperToolbar.display;
if (tests.typed) {
display.inputter.setInput(tests.typed);
}
else {
ok(false, "Missing typed for " + JSON.stringify(test));
return;
ok(false, "Missing typed for " + JSON.stringify(tests));
return;
}
if (test.cursor) {
DeveloperToolbar.display.inputter.setCursor(test.cursor)
if (tests.cursor) {
display.inputter.setCursor(tests.cursor)
}
if (test.status) {
is(DeveloperToolbar.display.requisition.getStatus().toString(),
test.status,
"status for " + test.typed);
if (tests.status) {
is(display.requisition.getStatus().toString(),
tests.status, "status for " + tests.typed);
}
if (test.emptyParameters == null) {
test.emptyParameters = [];
if (tests.emptyParameters == null) {
tests.emptyParameters = [];
}
let completer = DeveloperToolbar.display.completer;
let realParams = completer.emptyParameters;
is(realParams.length, test.emptyParameters.length,
'emptyParameters.length for \'' + test.typed + '\'');
let realParams = display.completer.emptyParameters;
is(realParams.length, tests.emptyParameters.length,
'emptyParameters.length for \'' + tests.typed + '\'');
if (realParams.length === test.emptyParameters.length) {
if (realParams.length === tests.emptyParameters.length) {
for (let i = 0; i < realParams.length; i++) {
is(realParams[i].replace(/\u00a0/g, ' '), test.emptyParameters[i],
'emptyParameters[' + i + '] for \'' + test.typed + '\'');
is(realParams[i].replace(/\u00a0/g, ' '), tests.emptyParameters[i],
'emptyParameters[' + i + '] for \'' + tests.typed + '\'');
}
}
if (test.directTabText) {
is(completer.directTabText, test.directTabText,
'directTabText for \'' + test.typed + '\'');
if (tests.directTabText) {
is(display.completer.directTabText, tests.directTabText,
'directTabText for \'' + tests.typed + '\'');
}
else {
is(completer.directTabText, '', 'directTabText for \'' + test.typed + '\'');
is(display.completer.directTabText, '',
'directTabText for \'' + tests.typed + '\'');
}
if (test.arrowTabText) {
is(completer.arrowTabText, ' \u00a0\u21E5 ' + test.arrowTabText,
'arrowTabText for \'' + test.typed + '\'');
if (tests.arrowTabText) {
is(display.completer.arrowTabText, ' \u00a0\u21E5 ' + tests.arrowTabText,
'arrowTabText for \'' + tests.typed + '\'');
}
else {
is(completer.arrowTabText, '', 'arrowTabText for \'' + test.typed + '\'');
is(display.completer.arrowTabText, '',
'arrowTabText for \'' + tests.typed + '\'');
}
if (tests.markup) {
let cursor = tests.cursor ? tests.cursor.start : tests.typed.length;
let statusMarkup = display.requisition.getInputStatusMarkup(cursor);
let actualMarkup = statusMarkup.map(function(s) {
return Array(s.string.length + 1).join(s.status.toString()[0]);
}).join('');
is(tests.markup, actualMarkup, 'markup for ' + tests.typed);
}
},
@ -151,11 +166,11 @@ let DeveloperToolbarTest = {
* blankOutput: true, // Special checks when there is no output
* });
*/
exec: function DTT_exec(test) {
test = test || {};
exec: function DTT_exec(tests) {
tests = tests || {};
if (test.typed) {
DeveloperToolbar.display.inputter.setInput(test.typed);
if (tests.typed) {
DeveloperToolbar.display.inputter.setInput(tests.typed);
}
let typed = DeveloperToolbar.display.inputter.getInputState().typed;
@ -163,7 +178,7 @@ let DeveloperToolbarTest = {
is(typed, output.typed, 'output.command for: ' + typed);
if (test.completed !== false) {
if (tests.completed !== false) {
ok(output.completed, 'output.completed false for: ' + typed);
}
else {
@ -172,36 +187,41 @@ let DeveloperToolbarTest = {
// ok(!output.completed, 'output.completed true for: ' + typed);
}
if (test.args != null) {
is(Object.keys(test.args).length, Object.keys(output.args).length,
if (tests.args != null) {
is(Object.keys(tests.args).length, Object.keys(output.args).length,
'arg count for ' + typed);
Object.keys(output.args).forEach(function(arg) {
let expectedArg = test.args[arg];
let expectedArg = tests.args[arg];
let actualArg = output.args[arg];
if (Array.isArray(expectedArg)) {
if (!Array.isArray(actualArg)) {
ok(false, 'actual is not an array. ' + typed + '/' + arg);
return;
}
is(expectedArg.length, actualArg.length,
'array length: ' + typed + '/' + arg);
for (let i = 0; i < expectedArg.length; i++) {
is(expectedArg[i], actualArg[i],
'member: "' + typed + '/' + arg + '/' + i);
}
if (typeof expectedArg === 'function') {
ok(expectedArg(actualArg), 'failed test func. ' + typed + '/' + arg);
}
else {
is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
if (Array.isArray(expectedArg)) {
if (!Array.isArray(actualArg)) {
ok(false, 'actual is not an array. ' + typed + '/' + arg);
return;
}
is(expectedArg.length, actualArg.length,
'array length: ' + typed + '/' + arg);
for (let i = 0; i < expectedArg.length; i++) {
is(expectedArg[i], actualArg[i],
'member: "' + typed + '/' + arg + '/' + i);
}
}
else {
is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg);
}
}
});
}
let displayed = DeveloperToolbar.outputPanel._div.textContent;
if (test.outputMatch) {
if (tests.outputMatch) {
function doTest(match, against) {
if (!match.test(against)) {
ok(false, "html output for " + typed + " against " + match.source +
@ -210,17 +230,17 @@ let DeveloperToolbarTest = {
info(against);
}
}
if (Array.isArray(test.outputMatch)) {
test.outputMatch.forEach(function(match) {
if (Array.isArray(tests.outputMatch)) {
tests.outputMatch.forEach(function(match) {
doTest(match, displayed);
});
}
else {
doTest(test.outputMatch, displayed);
doTest(tests.outputMatch, displayed);
}
}
if (test.blankOutput != null) {
if (tests.blankOutput != null) {
if (!/^$/.test(displayed)) {
ok(false, "html output for " + typed + " (textContent sent to info)");
info("Actual textContent");
@ -260,6 +280,8 @@ let DeveloperToolbarTest = {
if (appMenuItem) {
appMenuItem.hidden = true;
}
// leakHunt({ DeveloperToolbar: DeveloperToolbar });
});
// a.k.a: Services.prefs.setBoolPref("devtools.toolbar.enabled", true);
@ -289,3 +311,158 @@ let DeveloperToolbarTest = {
});
},
};
/**
* Memory leak hunter. Walks a tree of objects looking for DOM nodes.
* Usage:
* leakHunt({
* thing: thing,
* otherthing: otherthing
* });
*/
var noRecurse = [
/^string$/, /^number$/, /^boolean$/, /^null/, /^undefined/,
/^Window$/, /^Document$/,
/^XULDocument$/, /^XULElement$/,
/^DOMWindow$/, /^HTMLDocument$/, /^HTML.*Element$/
];
var hide = [ /^string$/, /^number$/, /^boolean$/, /^null/, /^undefined/ ];
function leakHunt(root, path, seen) {
path = path || [];
seen = seen || [];
try {
var output = leakHuntInner(root, path, seen);
output.forEach(function(line) {
dump(line + '\n');
});
}
catch (ex) {
dump(ex + '\n');
}
}
function leakHuntInner(root, path, seen) {
var prefix = new Array(path.length).join(' ');
var reply = [];
function log(msg) {
reply.push(msg);
}
var direct
try {
direct = Object.keys(root);
}
catch (ex) {
log(prefix + ' Error enumerating: ' + ex);
return reply;
}
for (var prop in root) {
var newPath = path.slice();
newPath.push(prop);
prefix = new Array(newPath.length).join(' ');
var data;
try {
data = root[prop];
}
catch (ex) {
log(prefix + prop + ' Error reading: ' + ex);
continue;
}
var recurse = true;
var message = getType(data);
if (matchesAnyPattern(message, hide)) {
continue;
}
if (message === 'function' && direct.indexOf(prop) == -1) {
continue;
}
if (message === 'string') {
var extra = data.length > 10 ? data.substring(0, 9) + '_' : data;
message += ' "' + extra.replace(/\n/g, "|") + '"';
recurse = false;
}
else if (matchesAnyPattern(message, noRecurse)) {
message += ' (no recurse)'
recurse = false;
}
else if (seen.indexOf(data) !== -1) {
message += ' (already seen)';
recurse = false;
}
if (recurse) {
seen.push(data);
var lines = leakHuntInner(data, newPath, seen);
if (lines.length == 0) {
if (message !== 'function') {
log(prefix + prop + ' = ' + message + ' { }');
}
}
else {
log(prefix + prop + ' = ' + message + ' {');
lines.forEach(function(line) {
reply.push(line);
});
log(prefix + '}');
}
}
else {
log(prefix + prop + ' = ' + message);
}
}
return reply;
}
function matchesAnyPattern(str, patterns) {
var match = false;
patterns.forEach(function(pattern) {
if (str.match(pattern)) {
match = true;
}
});
return match;
}
function getType(data) {
if (data === null) {
return 'null';
}
if (data === undefined) {
return 'undefined';
}
var type = typeof data;
if (type === 'object' || type === 'Object') {
type = getCtorName(data);
}
return type;
}
function getCtorName(aObj) {
try {
if (aObj.constructor && aObj.constructor.name) {
return aObj.constructor.name;
}
}
catch (ex) {
return 'UnknownObject';
}
// If that fails, use Objects toString which sometimes gives something
// better than 'Object', and at least defaults to Object if nothing better
return Object.prototype.toString.call(aObj).slice(8, -1);
}

View File

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html>
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<head>
<meta charset="utf-8">
<title>Resources</title>
<script type="text/javascript" id="script1">
window.addEventListener('load', function() {
var pid = document.getElementById('pid');
var div = document.createElement('div');
div.id = 'divid';
div.classList.add('divclass');
div.appendChild(document.createTextNode('div'));
div.setAttribute('data-a1', 'div');
pid.parentNode.appendChild(div);
});
</script>
<script src="resources_inpage.js"></script>
<link rel="stylesheet" type="text/css" href="resources_inpage1.css"/>
<link rel="stylesheet" type="text/css" href="resources_inpage2.css"/>
<style type="text/css">
p { color: #800; }
div { color: #008; }
h4 { color: #080; }
h3 { color: #880; }
</style>
</head>
<body>
<style type="text/css" id=style2>
.pclass { background-color: #FEE; }
.divclass { background-color: #EEF; }
.h4class { background-color: #EFE; }
.h3class { background-color: #FFE; }
</style>
<p class="pclass" id="pid" data-a1="p">paragraph</p>
<script>
var pid = document.getElementById('pid');
var h4 = document.createElement('h4');
h4.id = 'h4id';
h4.classList.add('h4class');
h4.appendChild(document.createTextNode('h4'));
h4.setAttribute('data-a1', 'h4');
pid.parentNode.appendChild(h4);
</script>
</body>
</html>

View File

@ -0,0 +1,12 @@
// This script is used from within browser_gcli_edit.html
window.addEventListener('load', function() {
var pid = document.getElementById('pid');
var h3 = document.createElement('h3');
h3.id = 'h3id';
h3.classList.add('h3class');
h3.appendChild(document.createTextNode('h3'));
h3.setAttribute('data-a1', 'h3');
pid.parentNode.appendChild(h3);
});

View File

@ -0,0 +1,11 @@
@charset "utf-8";
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
#pid { border-top: 2px dotted #F00; }
#divid { border-top: 2px dotted #00F; }
#h4id { border-top: 2px dotted #0F0; }
#h3id { border-top: 2px dotted #FF0; }

View File

@ -0,0 +1,11 @@
@charset "utf-8";
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
*[data-a1=p] { border-left: 4px solid #F00; }
*[data-a1=div] { border-left: 4px solid #00F; }
*[data-a1=h4] { border-left: 4px solid #0F0; }
*[data-a1=h3] { border-left: 4px solid #FF0; }

View File

@ -12,6 +12,7 @@ const Cu = Components.utils;
const DBG_XUL = "chrome://browser/content/debugger.xul";
const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties";
const REMOTE_PROFILE_NAME = "_remote-debug";
const TAB_SWITCH_NOTIFICATION = "debugger-tab-switch";
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
Cu.import("resource://gre/modules/Services.jsm");
@ -31,6 +32,7 @@ function DebuggerUI(aWindow) {
}
DebuggerUI.prototype = {
/**
* Called by the DebuggerPane to update the Debugger toggle switches with the
* debugger state.
@ -39,7 +41,7 @@ DebuggerUI.prototype = {
let selectedTab = this.chromeWindow.getBrowser().selectedTab;
let command = this.chromeWindow.document.getElementById("Tools:Debugger");
if (this.getDebugger(selectedTab) != null) {
if (this.getDebugger()) {
command.setAttribute("checked", "true");
} else {
command.removeAttribute("checked");
@ -51,13 +53,18 @@ DebuggerUI.prototype = {
* @return DebuggerPane if the debugger is started, null if it's stopped.
*/
toggleDebugger: function DUI_toggleDebugger() {
let tab = this.chromeWindow.gBrowser.selectedTab;
let scriptDebugger = this.getDebugger();
let selectedTab = this.chromeWindow.gBrowser.selectedTab;
if (tab._scriptDebugger) {
tab._scriptDebugger.close();
if (scriptDebugger) {
if (scriptDebugger.ownerTab !== selectedTab) {
this.showTabSwitchNotification();
return scriptDebugger;
}
scriptDebugger.close();
return null;
}
return new DebuggerPane(this, tab);
return new DebuggerPane(this, selectedTab);
},
/**
@ -65,10 +72,10 @@ DebuggerUI.prototype = {
* @return RemoteDebuggerWindow if the debugger is started, null if stopped.
*/
toggleRemoteDebugger: function DUI_toggleRemoteDebugger() {
let win = this.chromeWindow;
let remoteDebugger = this.getRemoteDebugger();
if (win._remoteDebugger) {
win._remoteDebugger.close();
if (remoteDebugger) {
remoteDebugger.close();
return null;
}
return new RemoteDebuggerWindow(this);
@ -79,21 +86,22 @@ DebuggerUI.prototype = {
* @return ChromeDebuggerProcess if the debugger is started, null if stopped.
*/
toggleChromeDebugger: function DUI_toggleChromeDebugger(aOnClose, aOnRun) {
let win = this.chromeWindow;
let chromeDebugger = this.getChromeDebugger();
if (win._chromeDebugger) {
win._chromeDebugger.close();
if (chromeDebugger) {
chromeDebugger.close();
return null;
}
return new ChromeDebuggerProcess(win, aOnClose, aOnRun, true);
return new ChromeDebuggerProcess(this.chromeWindow, aOnClose, aOnRun, true);
},
/**
* Get the debugger for a specified tab.
* Get the current script debugger.
* @return DebuggerPane if a debugger exists for the tab, null otherwise.
*/
getDebugger: function DUI_getDebugger(aTab) {
return '_scriptDebugger' in aTab ? aTab._scriptDebugger : null;
getDebugger: function DUI_getDebugger() {
let win = this.chromeWindow;
return '_scriptDebugger' in win ? win._scriptDebugger : null;
},
/**
@ -120,6 +128,52 @@ DebuggerUI.prototype = {
*/
get preferences() {
return DebuggerPreferences;
},
/**
* Currently, there can only be one debugger per tab.
* Show an asynchronous notification which asks the user to switch the
* script debugger to the current tab if it's already open in another one.
*/
showTabSwitchNotification: function DUI_showTabSwitchNotification()
{
let gBrowser = this.chromeWindow.gBrowser;
let selectedBrowser = gBrowser.selectedBrowser;
let nbox = gBrowser.getNotificationBox(selectedBrowser);
let notification = nbox.getNotificationWithValue(TAB_SWITCH_NOTIFICATION);
if (notification) {
nbox.removeNotification(notification);
return;
}
let buttons = [{
id: "debugger.confirmTabSwitch.buttonSwitch",
label: L10N.getStr("confirmTabSwitch.buttonSwitch"),
accessKey: L10N.getStr("confirmTabSwitch.buttonSwitch.accessKey"),
callback: function DUI_notificationButtonSwitch() {
gBrowser.selectedTab = this.getDebugger().ownerTab;
}.bind(this)
}, {
id: "debugger.confirmTabSwitch.buttonOpen",
label: L10N.getStr("confirmTabSwitch.buttonOpen"),
accessKey: L10N.getStr("confirmTabSwitch.buttonOpen.accessKey"),
callback: function DUI_notificationButtonOpen() {
this.getDebugger().close();
this.toggleDebugger();
}.bind(this)
}];
let message = L10N.getStr("confirmTabSwitch.message");
let imageURL = "chrome://browser/skin/Info.png";
notification = nbox.appendNotification(
message, TAB_SWITCH_NOTIFICATION,
imageURL, nbox.PRIORITY_WARNING_HIGH, buttons, null);
// Make sure this is not a transient notification, to avoid the automatic
// transient notification removal.
notification.persistence = -1;
}
};
@ -133,6 +187,7 @@ DebuggerUI.prototype = {
*/
function DebuggerPane(aDebuggerUI, aTab) {
this._globalUI = aDebuggerUI;
this._win = aDebuggerUI.chromeWindow;
this._tab = aTab;
this._initServer();
@ -155,9 +210,9 @@ DebuggerPane.prototype = {
* Creates and initializes the widgets containing the debugger UI.
*/
_create: function DP__create() {
this._tab._scriptDebugger = this;
this._win._scriptDebugger = this;
let gBrowser = this._tab.linkedBrowser.getTabBrowser();
let gBrowser = this._win.gBrowser;
let ownerDocument = gBrowser.parentNode.ownerDocument;
this._splitter = ownerDocument.createElement("splitter");
@ -193,10 +248,11 @@ DebuggerPane.prototype = {
* Closes the debugger, removing child nodes and event listeners.
*/
close: function DP_close() {
if (!this._tab) {
if (!this._win) {
return;
}
delete this._tab._scriptDebugger;
delete this._win._scriptDebugger;
this._win = null;
this._tab = null;
DebuggerPreferences.height = this._frame.height;
@ -213,6 +269,14 @@ DebuggerPane.prototype = {
this._globalUI.refreshCommand();
},
/**
* Gets the tab owning this debugger instance.
* @return XULElement
*/
get ownerTab() {
return this._tab;
},
/**
* Gets the debugger content window.
* @return nsIDOMWindow if a debugger window exists, null otherwise

View File

@ -48,6 +48,7 @@ let DebuggerController = {
this._isInitialized = true;
window.removeEventListener("DOMContentLoaded", this._startupDebugger, true);
DebuggerView.initializePanes();
DebuggerView.initializeEditor();
DebuggerView.StackFrames.initialize();
DebuggerView.Properties.initialize();
@ -69,6 +70,7 @@ let DebuggerController = {
this._isDestroyed = true;
window.removeEventListener("unload", this._shutdownDebugger, true);
DebuggerView.destroyPanes();
DebuggerView.destroyEditor();
DebuggerView.Scripts.destroy();
DebuggerView.StackFrames.destroy();
@ -659,15 +661,6 @@ StackFrames.prototype = {
let objClient = this.activeThread.pauseGrip(aObject);
objClient.getPrototypeAndProperties(function SF_onProtoAndProps(aResponse) {
// Add __proto__.
if (aResponse.prototype.type !== "null") {
let properties = { "__proto__ ": { value: aResponse.prototype } };
aVar.addProperties(properties);
// Expansion handlers must be set after the properties are added.
this._addExpander(aVar["__proto__ "], aResponse.prototype);
}
// Sort all of the properties before adding them, for better UX.
let properties = {};
for each (let prop in Object.keys(aResponse.ownProperties).sort()) {
@ -680,6 +673,14 @@ StackFrames.prototype = {
this._addExpander(aVar[prop], aResponse.ownProperties[prop].value);
}
// Add __proto__.
if (aResponse.prototype.type !== "null") {
let properties = { "__proto__ ": { value: aResponse.prototype } };
aVar.addProperties(properties);
// Expansion handlers must be set after the properties are added.
this._addExpander(aVar["__proto__ "], aResponse.prototype);
}
aVar.fetched = true;
}.bind(this));
},
@ -1419,6 +1420,46 @@ XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() {
*/
let Prefs = {
/**
* Gets the preferred stackframes pane width.
* @return number
*/
get stackframesWidth() {
if (this._sfrmWidth === undefined) {
this._sfrmWidth = Services.prefs.getIntPref("devtools.debugger.ui.stackframes-width");
}
return this._sfrmWidth;
},
/**
* Sets the preferred stackframes pane width.
* @return number
*/
set stackframesWidth(value) {
Services.prefs.setIntPref("devtools.debugger.ui.stackframes-width", value);
this._sfrmWidth = value;
},
/**
* Gets the preferred variables pane width.
* @return number
*/
get variablesWidth() {
if (this._varsWidth === undefined) {
this._varsWidth = Services.prefs.getIntPref("devtools.debugger.ui.variables-width");
}
return this._varsWidth;
},
/**
* Sets the preferred variables pane width.
* @return number
*/
set variablesWidth(value) {
Services.prefs.setIntPref("devtools.debugger.ui.variables-width", value);
this._varsWidth = value;
},
/**
* Gets a flag specifying if the the debugger should automatically connect to
* the default host and port number.

View File

@ -18,6 +18,17 @@ let DebuggerView = {
*/
editor: null,
/**
* Initializes UI properties for all the displayed panes.
*/
initializePanes: function DV_initializePanes() {
let stackframes = document.getElementById("stackframes");
stackframes.setAttribute("width", Prefs.stackframesWidth);
let variables = document.getElementById("variables");
variables.setAttribute("width", Prefs.variablesWidth);
},
/**
* Initializes the SourceEditor instance.
*/
@ -36,6 +47,17 @@ let DebuggerView = {
this.editor.init(placeholder, config, this._onEditorLoad.bind(this));
},
/**
* Removes the displayed panes and saves any necessary state.
*/
destroyPanes: function DV_destroyPanes() {
let stackframes = document.getElementById("stackframes");
Prefs.stackframesWidth = stackframes.getAttribute("width");
let variables = document.getElementById("variables");
Prefs.variablesWidth = variables.getAttribute("width");
},
/**
* Removes the SourceEditor instance and added breakpoints.
*/
@ -813,6 +835,12 @@ PropertiesView.prototype = {
*/
element.addToHierarchy = this.addScopeToHierarchy.bind(this, element);
// Setup the additional elements specific for a scope node.
element.refresh(function() {
let title = element.getElementsByClassName("title")[0];
title.classList.add("devtools-toolbar");
}.bind(this));
// Return the element for later use if necessary.
return element;
},
@ -1035,12 +1063,12 @@ PropertiesView.prototype = {
// Handle data property and accessor property descriptors.
if (value !== undefined) {
this._addProperty(aVar, [i, value]);
this._addProperty(aVar, [i, value], desc);
}
if (getter !== undefined || setter !== undefined) {
let prop = this._addProperty(aVar, [i]).expand();
prop.getter = this._addProperty(prop, ["get", getter]);
prop.setter = this._addProperty(prop, ["set", setter]);
prop.getter = this._addProperty(prop, ["get", getter], desc);
prop.setter = this._addProperty(prop, ["set", setter], desc);
}
}
}
@ -1054,7 +1082,7 @@ PropertiesView.prototype = {
*
* @param object aVar
* The parent variable element.
* @param {Array} aProperty
* @param array aProperty
* An array containing the key and grip properties, specifying
* the value and/or type & class of the variable (if the type
* is not specified, it will be inferred from the value).
@ -1064,6 +1092,8 @@ PropertiesView.prototype = {
* ["someProp3", { type: "undefined" }]
* ["someProp4", { type: "null" }]
* ["someProp5", { type: "object", class: "Object" }]
* @param object aFlags
* Contans configurable, enumberable or writable flags.
* @param string aName
* Optional, the property name.
* @paarm string aId
@ -1071,7 +1101,7 @@ PropertiesView.prototype = {
* @return object
* The newly created html node representing the added prop.
*/
_addProperty: function DVP__addProperty(aVar, aProperty, aName, aId) {
_addProperty: function DVP__addProperty(aVar, aProperty, aFlags, aName, aId) {
// Make sure the variable container exists.
if (!aVar) {
return null;
@ -1109,7 +1139,15 @@ PropertiesView.prototype = {
if ("undefined" !== typeof pKey) {
// Use a key element to specify the property name.
nameLabel.className = "key plain";
let className = "";
if (aFlags) {
if (aFlags.configurable === false) { className += "non-configurable "; }
if (aFlags.enumerable === false) { className += "non-enumerable "; }
if (aFlags.writable === false) { className += "non-writable "; }
}
if (pKey === "__proto__ ") { className += "proto "; }
nameLabel.className = className + "key plain";
nameLabel.setAttribute("value", pKey.trim());
title.appendChild(nameLabel);
}

View File

@ -45,7 +45,6 @@
tooltiptext="&debuggerUI.closeButton.tooltip;"
class="devtools-closebutton"/>
#endif
<hbox id="debugger-controls">
<toolbarbutton id="resume"
class="devtools-toolbarbutton"
@ -77,17 +76,11 @@
#endif
</toolbar>
<hbox id="dbg-content" flex="1">
<vbox id="stack" flex="1">
<vbox id="stackframes" class="dbg-default" flex="1"/>
</vbox>
<splitter id="stack-script-splitter"
class="devtools-side-splitter"/>
<vbox id="editor" class="dbg-default" flex="1"/>
<splitter id="script-properties-splitter"
class="devtools-side-splitter"/>
<vbox id="properties" flex="1">
<vbox id="variables" class="dbg-default" flex="1"/>
</vbox>
<vbox id="stackframes"/>
<splitter id="stack-script-splitter" class="devtools-side-splitter"/>
<vbox id="editor" flex="1"/>
<splitter id="script-properties-splitter" class="devtools-side-splitter"/>
<vbox id="variables"/>
</hbox>
</vbox>
</window>

View File

@ -14,6 +14,7 @@ include $(topsrcdir)/config/rules.mk
_BROWSER_TEST_FILES = \
browser_dbg_createRemote.js \
browser_dbg_createChrome.js \
browser_dbg_debugger-tab-switch.js \
browser_dbg_debuggerstatement.js \
browser_dbg_listtabs.js \
browser_dbg_tabactor-01.js \
@ -34,6 +35,7 @@ _BROWSER_TEST_FILES = \
browser_dbg_propertyview-10.js \
browser_dbg_propertyview-edit.js \
browser_dbg_panesize.js \
browser_dbg_panesize-inner.js \
browser_dbg_stack-01.js \
browser_dbg_stack-02.js \
browser_dbg_stack-03.js \

View File

@ -27,7 +27,7 @@ function testCleanExit() {
is(gDebugger.DebuggerController.activeThread.paused, true,
"Should be paused after the debugger statement.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}}, 0);
});

View File

@ -37,7 +37,7 @@ function test() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("resumed", function() {
Services.tm.currentThread.dispatch({ run: function() {
closeDebuggerAndFinish(gTab, true);
closeDebuggerAndFinish(true);
}}, 0);
});

View File

@ -0,0 +1,228 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
let gTab1, gTab2, gTab3, gTab4;
let gPane1, gPane2;
let gNbox;
function test() {
gNbox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
testTab1(function() {
testTab2(function() {
testTab3(function() {
testTab4(function() {
lastTest(function() {
cleanup(function() {
finish();
});
});
});
});
});
});
}
function testTab1(callback) {
gTab1 = addTab(TAB1_URL, function() {
gBrowser.selectedTab = gTab1;
gNbox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
is(gNbox.getNotificationWithValue("debugger-tab-switch"), null,
"Shouldn't have a tab switch notification.");
ok(!DebuggerUI.getDebugger(),
"Shouldn't have a debugger pane for this tab yet.");
info("Toggling a debugger (1).");
gPane1 = DebuggerUI.toggleDebugger();
ok(gPane1, "toggleDebugger() should return a pane.");
is(gPane1.ownerTab, gTab1, "Incorrect tab owner.");
is(DebuggerUI.getDebugger(), gPane1,
"getDebugger() should return the same pane as toggleDebugger().");
gPane1._frame.addEventListener("Debugger:Loaded", function dbgLoaded() {
gPane1._frame.removeEventListener("Debugger:Loaded", dbgLoaded, true);
info("First debugger has finished loading correctly.");
executeSoon(function() {
callback();
});
}, true);
});
}
function testTab2(callback) {
gTab2 = addTab(TAB1_URL, function() {
gBrowser.selectedTab = gTab2;
gNbox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
is(gNbox.getNotificationWithValue("debugger-tab-switch"), null,
"Shouldn't have a tab switch notification yet.");
ok(DebuggerUI.getDebugger(),
"Should already have a debugger pane for another tab.");
gNbox.addEventListener("AlertActive", function active() {
gNbox.removeEventListener("AlertActive", active, true);
executeSoon(function() {
ok(gPane2, "toggleDebugger() should always return a pane.");
is(gPane2.ownerTab, gTab1, "Incorrect tab owner.");
is(DebuggerUI.getDebugger(), gPane1,
"getDebugger() should return the same pane as the first call to toggleDebugger().");
is(DebuggerUI.getDebugger(), gPane2,
"getDebugger() should return the same pane as the second call to toggleDebugger().");
info("Second debugger has not loaded.");
let notification = gNbox.getNotificationWithValue("debugger-tab-switch");
ok(gNbox.currentNotification, "Should have a tab switch notification.");
is(gNbox.currentNotification, notification, "Incorrect current notification.");
info("Notification will be simply closed.");
notification.close();
executeSoon(function() {
callback();
});
});
}, true);
info("Toggling a debugger (2).");
gPane2 = DebuggerUI.toggleDebugger();
});
}
function testTab3(callback) {
gTab3 = addTab(TAB1_URL, function() {
gBrowser.selectedTab = gTab3;
gNbox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
is(gNbox.getNotificationWithValue("debugger-tab-switch"), null,
"Shouldn't have a tab switch notification.");
ok(DebuggerUI.getDebugger(),
"Should already have a debugger pane for another tab.");
gNbox.addEventListener("AlertActive", function active() {
gNbox.removeEventListener("AlertActive", active, true);
executeSoon(function() {
ok(gPane2, "toggleDebugger() should always return a pane.");
is(gPane2.ownerTab, gTab1, "Incorrect tab owner.");
is(DebuggerUI.getDebugger(), gPane1,
"getDebugger() should return the same pane as the first call to toggleDebugger().");
is(DebuggerUI.getDebugger(), gPane2,
"getDebugger() should return the same pane as the second call to toggleDebugger().");
info("Second debugger has not loaded.");
let notification = gNbox.getNotificationWithValue("debugger-tab-switch");
ok(gNbox.currentNotification, "Should have a tab switch notification.");
is(gNbox.currentNotification, notification, "Incorrect current notification.");
gBrowser.tabContainer.addEventListener("TabSelect", function tabSelect() {
gBrowser.tabContainer.removeEventListener("TabSelect", tabSelect, true);
executeSoon(function() {
callback();
});
}, true);
let buttonSwitch = notification.querySelectorAll("button")[0];
buttonSwitch.focus();
EventUtils.sendKey("SPACE");
info("The switch button on the notification was pressed.");
});
}, true);
info("Toggling a debugger (3).");
gPane2 = DebuggerUI.toggleDebugger();
});
}
function testTab4(callback) {
is(gBrowser.selectedTab, gTab1,
"Should've switched to the first debugged tab.");
gTab4 = addTab(TAB1_URL, function() {
gBrowser.selectedTab = gTab4;
gNbox = gBrowser.getNotificationBox(gBrowser.selectedBrowser);
is(gNbox.getNotificationWithValue("debugger-tab-switch"), null,
"Shouldn't have a tab switch notification.");
ok(DebuggerUI.getDebugger(),
"Should already have a debugger pane for another tab.");
gNbox.addEventListener("AlertActive", function active() {
gNbox.removeEventListener("AlertActive", active, true);
executeSoon(function() {
ok(gPane2, "toggleDebugger() should always return a pane.");
is(gPane2.ownerTab, gTab1, "Incorrect tab owner.");
is(DebuggerUI.getDebugger(), gPane1,
"getDebugger() should return the same pane as the first call to toggleDebugger().");
is(DebuggerUI.getDebugger(), gPane2,
"getDebugger() should return the same pane as the second call to toggleDebugger().");
info("Second debugger has not loaded.");
let notification = gNbox.getNotificationWithValue("debugger-tab-switch");
ok(gNbox.currentNotification, "Should have a tab switch notification.");
is(gNbox.currentNotification, notification, "Incorrect current notification.");
let buttonOpen = notification.querySelectorAll("button")[1];
buttonOpen.focus();
EventUtils.sendKey("SPACE");
info("The open button on the notification was pressed.");
executeSoon(function() {
callback();
});
});
}, true);
info("Toggling a debugger (4).");
gPane2 = DebuggerUI.toggleDebugger();
});
}
function lastTest(callback) {
isnot(gBrowser.selectedTab, gTab1,
"Shouldn't have switched to the first debugged tab.");
is(gBrowser.selectedTab, gTab4,
"Should currently be in the fourth tab.");
is(DebuggerUI.getDebugger().ownerTab, gTab4,
"The debugger should be open for the fourth tab.");
is(gNbox.getNotificationWithValue("debugger-tab-switch"), null,
"Shouldn't have a tab switch notification.");
info("Second debugger has loaded.");
executeSoon(function() {
callback();
});
}
function cleanup(callback) {
removeTab(gTab1);
removeTab(gTab2);
removeTab(gTab3);
removeTab(gTab4);
gTab1 = null;
gTab2 = null;
gTab3 = null;
gTab4 = null;
gPane1 = null;
gPane2 = null;
gNbox = null;
callback();
}

View File

@ -36,7 +36,7 @@ function test() {
gDebugger.DebuggerController.activeThread.addOneTimeListener("resumed", function() {
Services.tm.currentThread.dispatch({ run: function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}}, 0);
});

View File

@ -55,7 +55,7 @@ function testLocationChange()
gDebugger.DebuggerController.client.addOneTimeListener("tabAttached", function(aEvent, aPacket) {
ok(true, "Successfully reattached to the tab again.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
});
content.location = TAB1_URL;

View File

@ -0,0 +1,63 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
function test() {
var tab1 = addTab(TAB1_URL, function() {
gBrowser.selectedTab = tab1;
ok(!DebuggerUI.getDebugger(),
"Shouldn't have a debugger pane for this tab yet.");
let pane = DebuggerUI.toggleDebugger();
let someWidth1 = parseInt(Math.random() * 200) + 100;
let someWidth2 = parseInt(Math.random() * 200) + 100;
ok(pane, "toggleDebugger() should return a pane.");
is(DebuggerUI.getDebugger(), pane,
"getDebugger() should return the same pane as toggleDebugger().");
let frame = pane._frame;
let content = pane.contentWindow;
let stackframes;
let variables;
frame.addEventListener("Debugger:Loaded", function dbgLoaded() {
frame.removeEventListener("Debugger:Loaded", dbgLoaded, true);
ok(content.Prefs.stackframesWidth,
"The debugger preferences should have a saved stackframesWidth value.");
ok(content.Prefs.variablesWidth,
"The debugger preferences should have a saved variablesWidth value.");
stackframes = content.document.getElementById("stackframes");
variables = content.document.getElementById("variables");
is(content.Prefs.stackframesWidth, stackframes.getAttribute("width"),
"The stackframes pane width should be the same as the preferred value.");
is(content.Prefs.variablesWidth, variables.getAttribute("width"),
"The variables pane width should be the same as the preferred value.");
stackframes.setAttribute("width", someWidth1);
variables.setAttribute("width", someWidth2);
removeTab(tab1);
}, true);
frame.addEventListener("Debugger:Unloaded", function dbgUnloaded() {
frame.removeEventListener("Debugger:Unloaded", dbgUnloaded, true);
is(content.Prefs.stackframesWidth, stackframes.getAttribute("width"),
"The stackframes pane width should have been saved by now.");
is(content.Prefs.variablesWidth, variables.getAttribute("width"),
"The variables pane width should have been saved by now.");
finish();
}, true);
});
}

View File

@ -8,7 +8,7 @@ function test() {
var tab1 = addTab(TAB1_URL, function() {
gBrowser.selectedTab = tab1;
ok(!DebuggerUI.getDebugger(gBrowser.selectedTab),
ok(!DebuggerUI.getDebugger(),
"Shouldn't have a debugger pane for this tab yet.");
let pane = DebuggerUI.toggleDebugger();
@ -16,7 +16,7 @@ function test() {
ok(pane, "toggleDebugger() should return a pane.");
is(DebuggerUI.getDebugger(gBrowser.selectedTab), pane,
is(DebuggerUI.getDebugger(), pane,
"getDebugger() should return the same pane as toggleDebugger().");
ok(DebuggerUI.preferences.height,

View File

@ -61,7 +61,7 @@ function testResume() {
is(button.getAttribute("tooltiptext"), gDebugger.L10N.getStr("pauseTooltip"),
"Button tooltip should be pause when running.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}}, 0);
});

View File

@ -89,7 +89,7 @@ function testScriptLabelShortening() {
is(vs._scripts.itemCount, 9,
"Didn't get the correct number of scripts in the list.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
});
}

View File

@ -117,7 +117,7 @@ function testSimpleCall() {
"Clicking again the testScope tilte should collapse it.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}}, 0);
});

View File

@ -189,7 +189,7 @@ function testSimpleCall() {
"The scope should have been removed from the parent container tree.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}}, 0);
});

View File

@ -74,7 +74,7 @@ function testSimpleCall() {
"The var should have been removed from the parent container tree.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}}, 0);
});

View File

@ -82,7 +82,7 @@ function testSimpleCall() {
"The var should have been removed from the parent container tree.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}}, 0);
});

View File

@ -129,7 +129,7 @@ function testSimpleCall() {
"The grip information for the localVar5 wasn't set correctly.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}}, 0);
});

View File

@ -105,7 +105,7 @@ function resumeAndFinish() {
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}, true);
gDebugger.DebuggerController.activeThread.resume();

View File

@ -79,36 +79,51 @@ function testFrameParameters()
}
window.clearInterval(intervalID);
is(localNodes[0].querySelector(".property > .title > .key")
.getAttribute("value"), "__proto__",
"Should have the right property name for __proto__.");
.getAttribute("value"), "Array",
"Should have the right property name for Array.");
ok(localNodes[0].querySelector(".property > .title > .value")
.getAttribute("value").search(/object/) != -1,
"Array should be an object.");
is(localNodes[8].querySelector(".value")
.getAttribute("value"), "[object Arguments]",
"Should have the right property value for 'arguments'.");
ok(localNodes[8].querySelector(".property > .title > .value")
.getAttribute("value").search(/object/) != -1,
"Arguments should be an object.");
is(localNodes[8].querySelectorAll(".property > .title > .key")[7]
.getAttribute("value"), "__proto__",
"Should have the right property name for '__proto__'.");
ok(localNodes[8].querySelectorAll(".property > .title > .value")[7]
.getAttribute("value").search(/object/) != -1,
"__proto__ should be an object.");
is(localNodes[8].querySelector(".value").getAttribute("value"),
"[object Arguments]",
"Should have the right property value for 'arguments'.");
is(localNodes[8].querySelectorAll(".property > .title > .key")[7]
.getAttribute("value"), "length",
"Should have the right property name for 'length'.");
is(localNodes[8].querySelectorAll(".property > .title > .value")[7]
.getAttribute("value"), 5,
"Should have the right argument length.");
is(localNodes[10].querySelector(".value").getAttribute("value"), "[object Object]",
is(localNodes[10].querySelector(".value")
.getAttribute("value"), "[object Object]",
"Should have the right property value for 'c'.");
is(localNodes[10].querySelectorAll(".property > .title > .key")[1]
.getAttribute("value"), "a",
"Should have the right property name for 'a'.");
is(localNodes[10].querySelectorAll(".property > .title > .value")[1]
.getAttribute("value"), 1,
is(localNodes[10].querySelectorAll(".property > .title > .key")[0]
.getAttribute("value"), "a",
"Should have the right property name for 'c.a'.");
is(localNodes[10].querySelectorAll(".property > .title > .value")[0]
.getAttribute("value"), "1",
"Should have the right value for 'c.a'.");
is(localNodes[10].querySelectorAll(".property > .title > .key")[1]
.getAttribute("value"), "b",
"Should have the right property name for 'c.b'.");
is(localNodes[10].querySelectorAll(".property > .title > .value")[1]
.getAttribute("value"), "\"beta\"",
"Should have the right value for 'c.b'.");
is(localNodes[10].querySelectorAll(".property > .title > .key")[2]
.getAttribute("value"), "c",
"Should have the right property name for 'c.c'.");
is(localNodes[10].querySelectorAll(".property > .title > .value")[2]
.getAttribute("value"), "true",
"Should have the right value for 'c.c'.");
resumeAndFinish();
}, 100);
}}, 0);
@ -127,7 +142,7 @@ function resumeAndFinish() {
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}, true);
gDebugger.DebuggerController.activeThread.resume();

View File

@ -79,7 +79,7 @@ function resumeAndFinish() {
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}}, 0);
}, true);

View File

@ -90,7 +90,7 @@ function resumeAndFinish() {
is(frames.querySelectorAll(".dbg-stackframe").length, 0,
"Should have no frames.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}}, 0);
}, true);

View File

@ -97,7 +97,7 @@ function testModification(aVar, aCallback, aNewValue, aNewResult) {
function resumeAndFinish() {
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}

View File

@ -136,7 +136,7 @@ function testSwitchRunning()
is(gDebugger.editor.getDebugLocation(), -1,
"editor debugger location is still -1.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}
registerCleanupFunction(function() {

View File

@ -157,7 +157,7 @@ function testScriptSearching() {
is(gScripts.visibleItemsCount, 1,
"Not all the scripts are shown after the search. (20)");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}

View File

@ -116,7 +116,7 @@ function finalCheck() {
is(gScripts.visibleItemsCount, 2,
"Not all the scripts are shown after the search. (3)");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}
function clear() {

View File

@ -35,7 +35,7 @@ function resumeAndFinish() {
addScriptsAndCheckOrder(1, function() {
addScriptsAndCheckOrder(2, function() {
addScriptsAndCheckOrder(3, function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
});
});

View File

@ -68,7 +68,7 @@ function testSelectLine() {
"The correct line is selected.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
});
});

View File

@ -37,7 +37,7 @@ function testSimpleCall() {
"All children should be frames.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}}, 0);
});

View File

@ -68,7 +68,7 @@ function testEvalCall() {
"Second frame should not be selected after click inside the first frame.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}}, 0);
});

View File

@ -48,7 +48,7 @@ function testRecurse() {
"Should have reached the recurse limit.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
});

View File

@ -49,7 +49,7 @@ function testEvalCallResume() {
is(frames.querySelectorAll(".empty").length, 1,
"Should have the empty list explanation.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
}, true);
gDebugger.DebuggerController.activeThread.resume();

View File

@ -98,7 +98,7 @@ function testRecurse()
gDebugger.DebuggerController.activeThread.resume(function() {
is(gDebugger.editor.getDebugLocation(), -1,
"editor debugger location is correct after resume.");
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}

View File

@ -97,7 +97,7 @@ function testSwitchPaused()
"Found the expected editor mode.");
gDebugger.DebuggerController.activeThread.resume(function() {
closeDebuggerAndFinish(gTab);
closeDebuggerAndFinish();
});
}

View File

@ -49,13 +49,13 @@ function removeTab(aTab) {
gBrowser.removeTab(aTab);
}
function closeDebuggerAndFinish(aTab, aRemoteFlag) {
function closeDebuggerAndFinish(aRemoteFlag) {
DebuggerUI.chromeWindow.addEventListener("Debugger:Shutdown", function cleanup() {
DebuggerUI.chromeWindow.removeEventListener("Debugger:Shutdown", cleanup, false);
finish();
}, false);
if (!aRemoteFlag) {
DebuggerUI.getDebugger(aTab).close();
DebuggerUI.getDebugger().close();
} else {
DebuggerUI.getRemoteDebugger().close();
}

View File

@ -3,18 +3,18 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
browser.jar:
* content/browser/inspector.html (highlighter/inspector.html)
content/browser/inspector.html (highlighter/inspector.html)
content/browser/NetworkPanel.xhtml (webconsole/NetworkPanel.xhtml)
content/browser/devtools/HUDService-content.js (webconsole/HUDService-content.js)
* content/browser/scratchpad.xul (scratchpad/scratchpad.xul)
content/browser/scratchpad.js (scratchpad/scratchpad.js)
content/browser/splitview.css (shared/splitview.css)
* content/browser/styleeditor.xul (styleeditor/styleeditor.xul)
content/browser/styleeditor.xul (styleeditor/styleeditor.xul)
content/browser/styleeditor.css (styleeditor/styleeditor.css)
content/browser/devtools/csshtmltree.xul (styleinspector/csshtmltree.xul)
content/browser/devtools/cssruleview.xul (styleinspector/cssruleview.xul)
content/browser/devtools/styleinspector.css (styleinspector/styleinspector.css)
* content/browser/devtools/layoutview/view.xhtml (layoutview/view.xhtml)
content/browser/devtools/layoutview/view.xhtml (layoutview/view.xhtml)
content/browser/devtools/layoutview/view.css (layoutview/view.css)
content/browser/orion.js (sourceeditor/orion/orion.js)
* content/browser/source-editor-overlay.xul (sourceeditor/source-editor-overlay.xul)

View File

@ -1,9 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
#ifdef 0
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
#endif
<!DOCTYPE html [
<!ENTITY % layoutviewDTD SYSTEM "chrome://browser/locale/devtools/layoutview.dtd" >
%layoutviewDTD;

View File

@ -327,6 +327,10 @@ OutputPanel.prototype._onload = function OP_onload()
this._div.classList.add('gcli-row-out');
this._div.setAttribute('aria-live', 'assertive');
let styles = this._toolbar.ownerDocument.defaultView
.getComputedStyle(this._toolbar);
this._div.setAttribute("dir", styles.direction);
this.loaded = true;
if (this._loadCallback) {
this._loadCallback();
@ -501,6 +505,10 @@ TooltipPanel.prototype._onload = function TP_onload()
this.hintElement = this.document.getElementById("gcli-tooltip-root");
this._connector = this.document.getElementById("gcli-tooltip-connector");
let styles = this._toolbar.ownerDocument.defaultView
.getComputedStyle(this._toolbar);
this.hintElement.setAttribute("dir", styles.direction);
this.loaded = true;
if (this._loadCallback) {

View File

@ -10,6 +10,15 @@
# A good criteria is the language in which you'd find the best
# documentation on web development on the web.
# LOCALIZATION NOTE (confirmTabSwitch): The messages displayed for all the
# title and buttons on the notification shown when a user attempts to open a
# debugger in a new tab while a different tab is already being debugged.
confirmTabSwitch.message=Debugger is already open in another tab. Continuing will close the other instance.
confirmTabSwitch.buttonSwitch=Switch to debugged tab
confirmTabSwitch.buttonSwitch.accessKey=S
confirmTabSwitch.buttonOpen=Open anyway
confirmTabSwitch.buttonOpen.accessKey=O
# LOCALIZATION NOTE (remoteDebuggerWindowTitle): The title displayed for the
# remote debugger window.
remoteDebuggerWindowTitle=Remote Debugger

View File

@ -40,6 +40,46 @@ consoleManual=Filter, clear and close the web console
# function of the 'console clear' command.
consoleclearDesc=Clear the console
# LOCALIZATION NOTE (screenshotDesc) A very short description of the
# 'screenshot' command. See screenshotManual for a fuller description of what
# it does. This string is designed to be shown in a menu alongside the
# command name, which is why it should be as short as possible.
screenshotDesc=Save an image of the page
# LOCALIZATION NOTE (screenshotManual) A fuller description of the 'screenshot'
# command, displayed when the user asks for help on what it does.
screenshotManual=Save an PNG image of the entire visible window (optionally after a delay)
# LOCALIZATION NOTE (screenshotFilenameDesc) A very short string to describe
# the 'filename' parameter to the 'screenshot' command, which is displayed in
# a dialog when the user is using this command.
screenshotFilenameDesc=Destination filename
# LOCALIZATION NOTE (screenshotFilenameManual) A fuller description of the
# 'filename' parameter to the 'screenshot' command, displayed when the user
# asks for help on what it does.
screenshotFilenameManual=The name of the file (should have a '.png' extension) to which we write the screenshot.
# LOCALIZATION NOTE (screenshotDelayDesc) A very short string to describe
# the 'delay' parameter to the 'screenshot' command, which is displayed in
# a dialog when the user is using this command.
screenshotDelayDesc=Delay (seconds)
# LOCALIZATION NOTE (screenshotDelayManual) A fuller description of the
# 'delay' parameter to the 'screenshot' command, displayed when the user
# asks for help on what it does.
screenshotDelayManual=The time to wait (in seconds) before the screenshot is taken
# LOCALIZATION NOTE (screenshotFullscreenDesc) A very short string to describe
# the 'fullscreen' parameter to the 'screenshot' command, which is displayed in
# a dialog when the user is using this command.
screenshotFullPageDesc=Entire webpage? (true/false)
# LOCALIZATION NOTE (screenshotFullscreenManual) A fuller description of the
# 'fullscreen' parameter to the 'screenshot' command, displayed when the user
# asks for help on what it does.
screenshotFullPageManual=True if the screenshot should also include parts of the webpage which are outside the current scrolled bounds.
# LOCALIZATION NOTE (inspectDesc) A very short description of the 'inspect'
# command. See inspectManual for a fuller description of what it does. This
# string is designed to be shown in a menu alongside the command name, which

View File

@ -1982,7 +1982,8 @@ panel[dimmed="true"] {
-moz-image-region: rect(0px 32px 16px 16px);
}
#inspector-toolbar {
#inspector-toolbar,
#developer-toolbar {
border-top: 1px solid hsla(210, 8%, 5%, .65);
}
@ -2383,42 +2384,69 @@ html|*#highlighter-nodeinfobar-pseudo-classes {
border-radius: 0 3px 3px 0;
}
.gcli-panel-inner-arrowcontent {
/* Highlight toolbar - Option menu */
#inspector-option-toolbarbutton:-moz-focusring {
outline: 1px dotted hsla(210,30%,85%,0.4);
outline-offset: -2px;
}
html|*#gcli-tooltip-frame,
html|*#gcli-output-frame {
padding: 0;
border-width: 0;
background-color: transparent;
}
#gcli-output,
#gcli-tooltip {
border-width: 0;
background-color: transparent;
margin-bottom: -2px;
}
.gclitoolbar-input-node,
.gclitoolbar-complete-node,
.gclitoolbar-prompt {
font-family: monospace;
margin: 0;
-moz-margin-end: 3px;
-moz-box-align: center;
padding-top: 0;
padding-bottom: 0;
padding-right: 4px;
border: 1px solid transparent;
border-radius: 3px;
text-shadow: none;
}
.gclitoolbar-input-node {
padding-left: 20px;
background-color: transparent;
-moz-appearance: none;
border: none;
padding: 0 0 0 22px;
border-color: hsl(210,11%,10%);
color: hsl(210,30%,85%);
text-shadow: 0 -1px 0 hsla(210,8%,5%,.45);
box-shadow: 0 1px 1px hsla(210,8%,5%,.3) inset,
0 0 0 1px hsla(210,16%,76%,.1) inset,
0 1px 0 hsla(210,16%,76%,.15);
}
.gclitoolbar-complete-node {
padding-left: 21px;
background-color: transparent;
color: transparent;
height: 100%;
line-height: 100%;
padding: 10px 0 0 27px;
margin: 0;
}
.gclitoolbar-prompt {
color: hsl(25,78%,50%);
-moz-appearance: textfield;
padding-left: 4px;
padding-bottom: 2px;
font-size: 150%;
font-weight: bold;
line-height: 100%;
padding-top: 1px;
padding-left: 3px;
color: hsl(210,30%,85%);
background-color: hsl(210,11%,16%);
}
.gclitoolbar-prompt-label,
.gcli-in-incomplete,
.gcli-in-error,
.gcli-in-ontab,
@ -2439,20 +2467,13 @@ html|*#highlighter-nodeinfobar-pseudo-classes {
}
.gcli-in-ontab {
color: hsl(200,40%,70%);
color: hsl(210,0%,35%);
}
.gcli-in-todo {
color: hsl(48,28%,76%);
color: hsl(210,50%,35%);
}
.gcli-in-closebrace {
color: hsl(0,0%,80%);
}
/* Highlight toolbar - Option menu */
#inspector-option-toolbarbutton:-moz-focusring {
outline: 1px dotted hsla(210,30%,85%,0.4);
outline-offset: -2px;
}

View File

@ -118,7 +118,7 @@
margin: -4px;
}
/* Splitter */
/* Splitters */
.devtools-horizontal-splitter {
-moz-appearance: none;
@ -129,3 +129,14 @@
margin-bottom: -3px;
position: relative;
}
.devtools-side-splitter {
-moz-appearance: none;
border: 0;
-moz-border-start: 1px solid black;
min-width: 0;
width: 3px;
background-color: transparent;
-moz-margin-end: -3px;
position: relative;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 B

View File

@ -13,7 +13,7 @@
*/
#dbg-content {
padding: 6px;
padding: 0;
}
/**
@ -52,7 +52,7 @@
}
/**
* Properties elements
* Properties view
*/
#variables {
@ -60,7 +60,7 @@
}
/**
* Generic element details container
* Property element details container
*/
.details {
@ -73,24 +73,17 @@
*/
.scope > .title {
margin-top: 1px;
-moz-margin-start: 1px;
-moz-padding-start: 2px;
background: -moz-linear-gradient(bottom,
rgb(160,175,205) 0,
rgb(120,140,175) 100%);
border-bottom: 1px solid #888;
box-shadow: 0 0 4px #ccc;
text-shadow: 0 1px #777;
text-shadow: 0 1px #222;
color: #fff;
font: -moz-list;
}
.scope > .title > .arrow {
margin-top: -2px;
}
.scope > .title > .name {
padding-top: 2px;
padding-bottom: 2px;
}
.scope > .details {
@ -106,7 +99,7 @@
-moz-margin-start: 1px;
-moz-margin-end: 1px;
margin-top: 2px;
border-bottom: 1px dotted #aaa;
border-bottom: 1px dotted #ccc;
border-radius: 8px;
-moz-transition: background 1s ease-in-out;
background: #fff;
@ -143,8 +136,13 @@
color: #881090;
}
.property > .title > .non-enumerable.key,
.property > .title > .proto.key {
color: #c48bc8;
}
/**
* Property colors
* Property values colors
*/
.token-undefined {
@ -219,7 +217,7 @@
*/
#resume {
list-style-image: url("chrome://browser/skin/devtools/debugger-pause.png");
list-style-image: url("chrome://browser/skin/devtools/debugger-play.png");
-moz-image-region: rect(0px, 16px, 16px, 0px);
}

View File

@ -2,10 +2,44 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#gclichrome-body {
.gcli-body {
margin: 0;
padding: 0;
font: message-box;
color: hsl(210,30%,85%);
}
#gcli-output-root,
#gcli-tooltip-root {
border: 1px solid hsl(210,11%,10%);
box-shadow: 0 1px 0 hsla(209,29%,72%,.25) inset;
background-image: -moz-linear-gradient(top, hsla(209,11%,18%,0.9), hsl(210,11%,16%));
border-radius: 3px;
}
#gcli-output-root {
padding: 5px 10px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
border-bottom: 0;
}
#gcli-tooltip-root {
padding: 5px 0px;
}
#gcli-tooltip-connector {
margin-top: -1px;
margin-left: 8px;
width: 20px;
height: 0;
border-left: 1px solid hsl(210,11%,10%);
border-right: 1px solid hsl(210,11%,10%);
background-color: hsl(210,11%,16%);
}
.gcli-tt-description,
.gcli-tt-error {
padding: 0 10px;
}
.gcli-row-out {
@ -13,6 +47,7 @@
line-height: 1.2em;
border-top: none;
border-bottom: none;
color: hsl(210,30%,85%);
}
.gcli-row-out p,
@ -22,43 +57,35 @@
margin: 5px 0;
}
.gcli-out-shortcut {
border: 1px solid #999;
border-radius: 3px;
padding: 1px 4px 0;
.gcli-row-out h1,
.gcli-row-out h2,
.gcli-row-out h3,
.gcli-row-out h4,
.gcli-row-out h5,
.gcli-row-out th,
.gcli-row-out strong {
color: hsl(210,30%,95%);
}
.gcli-out-shortcut,
.gcli-help-synopsis {
padding: 0 3px;
margin: 0 4px;
font-size: 80%;
font-family: monospace;
cursor: pointer;
vertical-align: bottom;
white-space: pre;
background-color: #fff;
font-weight: normal;
font-size: 90%;
border-radius: 3px;
background-color: hsl(210,11%,16%);
border: 1px solid hsl(210,11%,10%);
}
.gcli-out-shortcut:before {
color: #66F;
content: '\bb';
.gcli-out-shortcut:before,
.gcli-help-synopsis:before {
color: hsl(210,30%,85%);
-moz-padding-end: 2px;
}
/* From: $GCLI/lib/gcli/commands/help.css */
.gcli-help-arrow {
font-size: 70%;
color: #AAA;
}
.gcli-help-synopsis {
font-family: monospace;
font-weight: normal;
padding: 0 3px;
margin: 0 10px;
border: 1px solid #999;
border-radius: 3px;
}
.gcli-help-synopsis:before {
color: #66F;
color: #666;
}
.gcli-help-description {
@ -75,31 +102,22 @@
margin: 10px 0 6px;
}
/* From: $GCLI/lib/gcli/ui/fields/menu.css */
.gcli-menu-name {
-moz-padding-start: 8px;
}
.gcli-menu-desc {
-moz-padding-end: 8px;
color: #999;
color: hsl(210,30%,75%);
}
.gcli-menu-option:hover {
background-color: #EEE;
background-color: hsla(0,100%,100%,.1);
}
.gcli-menu-highlight,
.gcli-menu-highlight.gcli-menu-option:hover {
background-color: #DDD;
}
.gcli-menu-error {
padding: 8px 10px 2px;
font-size: 80%;
color: red;
background-color: hsla(0,0%,0%,.3);
}
.gcli-menu-typed {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 626 B

After

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 B

After

Width:  |  Height:  |  Size: 308 B

View File

@ -152,6 +152,7 @@ browser.jar:
skin/classic/browser/devtools/layoutview.css (devtools/layoutview.css)
skin/classic/browser/devtools/layout-buttons.png (devtools/layout-buttons.png)
skin/classic/browser/devtools/debugger-pause.png (devtools/debugger-pause.png)
skin/classic/browser/devtools/debugger-play.png (devtools/debugger-play.png)
skin/classic/browser/devtools/debugger-step-in.png (devtools/debugger-step-in.png)
skin/classic/browser/devtools/debugger-step-out.png (devtools/debugger-step-out.png)
skin/classic/browser/devtools/debugger-step-over.png (devtools/debugger-step-over.png)

View File

@ -2711,18 +2711,21 @@ panel[dimmed="true"] {
-moz-image-region: rect(0px 32px 16px 16px);
}
#inspector-toolbar {
#inspector-toolbar,
#developer-toolbar {
border-top: 1px solid hsla(210, 8%, 5%, .65);
padding-top: 4px;
padding-bottom: 4px;
}
#inspector-toolbar:-moz-locale-dir(ltr) {
#inspector-toolbar:-moz-locale-dir(ltr),
#developer-toolbar:-moz-locale-dir(ltr) {
padding-left: 2px;
padding-right: 16px; /* use -moz-padding-end when/if bug 631729 gets fixed */
}
#inspector-toolbar:-moz-locale-dir(rtl) {
#inspector-toolbar:-moz-locale-dir(rtl),
#developer-toolbar:-moz-locale-dir(rtl) {
padding-left: 4px;
padding-right: 18px; /* use -moz-padding-end when/if bug 631729 gets fixed */
}
@ -3122,39 +3125,69 @@ html|*#highlighter-nodeinfobar-pseudo-classes {
border-radius: 0 @toolbarbuttonCornerRadius@ @toolbarbuttonCornerRadius@ 0;
}
.gcli-panel-inner-arrowcontent {
/* Highlight toolbar - Option menu */
#inspector-option-toolbarbutton:-moz-focusring {
outline: 1px dotted hsla(210,30%,85%,0.4);
outline-offset: -2px;
}
html|*#gcli-tooltip-frame,
html|*#gcli-output-frame {
padding: 0;
border-width: 0;
background-color: transparent;
}
#gcli-output,
#gcli-tooltip {
border-width: 0;
background-color: transparent;
margin-bottom: -2px;
}
.gclitoolbar-input-node,
.gclitoolbar-complete-node,
.gclitoolbar-prompt {
font-family: Menlo, Monaco, monospace;
margin: 0;
-moz-margin-end: 3px;
-moz-box-align: center;
padding-top: 0;
padding-bottom: 0;
padding-right: 4px;
border: 1px solid transparent;
border-radius: @toolbarbuttonCornerRadius@;
text-shadow: none;
}
.gclitoolbar-input-node {
padding-left: 20px;
background-color: transparent;
-moz-appearance: none;
border: none;
padding: 0 0 0 12px;
border-color: hsl(210,11%,10%);
color: hsl(210,30%,85%);
text-shadow: 0 -1px 0 hsla(210,8%,5%,.45);
box-shadow: 0 1px 1px hsla(210,8%,5%,.3) inset,
0 0 0 1px hsla(210,16%,76%,.1) inset,
0 1px 0 hsla(210,16%,76%,.15);
}
.gclitoolbar-complete-node {
padding-left: 21px;
background-color: transparent;
color: transparent;
height: 100%;
padding: 7px 0 0 18px;
}
.gclitoolbar-prompt {
color: hsl(25,78%,50%);
-moz-appearance: textfield;
padding-left: 4px;
padding-bottom: 2px;
font-size: 150%;
font-weight: bold;
line-height: 100%;
padding-top: 2px;
color: hsl(210,30%,85%);
background-color: hsl(210,11%,16%);
}
.gclitoolbar-prompt-label,
.gcli-in-incomplete,
.gcli-in-error,
.gcli-in-ontab,
@ -3175,20 +3208,13 @@ html|*#highlighter-nodeinfobar-pseudo-classes {
}
.gcli-in-ontab {
color: hsl(200,40%,70%);
color: hsl(210,0%,35%);
}
.gcli-in-todo {
color: hsl(48,28%,76%);
color: hsl(210,50%,35%);
}
.gcli-in-closebrace {
color: hsl(0,0%,80%);
}
/* Highlight toolbar - Option menu */
#inspector-option-toolbarbutton:-moz-focusring {
outline: 1px dotted hsla(210,30%,85%,0.4);
outline-offset: -2px;
}

View File

@ -132,7 +132,7 @@
-moz-image-region: rect(0, 48px, 16px, 32px);
}
/* Splitter */
/* Splitters */
.devtools-horizontal-splitter {
-moz-appearance: none;
@ -144,3 +144,14 @@
margin-bottom: -3px;
position: relative;
}
.devtools-side-splitter {
-moz-appearance: none;
background-image: none;
border: 0;
-moz-border-start: 1px solid black;
min-width: 0;
width: 3px;
-moz-margin-end: -3px;
position: relative;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 B

View File

@ -15,7 +15,7 @@
*/
#dbg-content {
padding: 6px;
padding: 0;
}
/**
@ -54,7 +54,7 @@
}
/**
* Properties elements
* Properties view
*/
#variables {
@ -62,7 +62,7 @@
}
/**
* Generic element details container
* Property element details container
*/
.details {
@ -75,23 +75,17 @@
*/
.scope > .title {
margin-top: 1px;
-moz-margin-start: 1px;
-moz-padding-start: 2px;
background: -moz-linear-gradient(bottom,
rgb(160,175,205) 0,
rgb(120,140,175) 100%);
border-bottom: 1px solid #888;
box-shadow: 0 0 4px #ccc;
text-shadow: 0 1px #777;
text-shadow: 0 1px #222;
color: #fff;
font: -moz-list;
}
.scope > .title > .arrow {
margin-top: -2px;
}
.scope > .title > .name {
padding-top: 4px;
padding-top: 2px;
}
.scope > .details {
@ -107,7 +101,7 @@
-moz-margin-start: 1px;
-moz-margin-end: 1px;
margin-top: 2px;
border-bottom: 1px dotted #aaa;
border-bottom: 1px dotted #ccc;
border-radius: 8px;
-moz-transition: background 1s ease-in-out;
background: #fff;
@ -144,8 +138,13 @@
color: #881090;
}
.property > .title > .non-enumerable.key,
.property > .title > .proto.key {
color: #c48bc8;
}
/**
* Property colors
* Property values colors
*/
.token-undefined {
@ -218,7 +217,7 @@
*/
#resume {
list-style-image: url("chrome://browser/skin/devtools/debugger-pause.png");
list-style-image: url("chrome://browser/skin/devtools/debugger-play.png");
-moz-image-region: rect(0px, 16px, 16px, 0px);
}

View File

@ -2,11 +2,45 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#gclichrome-body {
.gcli-body {
margin: 0;
padding: 0;
font: message-box;
color: #fff;
color: hsl(210,30%,85%);
}
#gcli-output-root,
#gcli-tooltip-root {
border: 1px solid hsl(210,11%,10%);
box-shadow: 0 1px 0 hsla(209,29%,72%,.25) inset;
background-image: url(background-noise-toolbar.png),
-moz-linear-gradient(top, hsla(209,18%,18%,0.9), hsl(210,11%,16%));
border-radius: 3px;
}
#gcli-output-root {
padding: 5px 10px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
border-bottom: 0;
}
#gcli-tooltip-root {
padding: 5px 0px;
}
#gcli-tooltip-connector {
margin-top: -1px;
margin-left: 8px;
width: 20px;
height: 0;
border-left: 1px solid hsl(210,11%,10%);
border-right: 1px solid hsl(210,11%,10%);
background-color: hsl(210,11%,16%);
}
.gcli-tt-description,
.gcli-tt-error {
padding: 0 10px;
}
.gcli-row-out {
@ -27,50 +61,32 @@
.gcli-row-out h1,
.gcli-row-out h2,
.gcli-row-out h3,
.gcli-row-out h4,
.gcli-row-out h5,
.gcli-row-out th,
.gcli-row-out strong {
color: #fff;
color: hsl(210,30%,95%);
}
.gcli-out-shortcut {
border: 1px solid #999;
border-radius: 3px;
padding: 1px 4px 0;
.gcli-out-shortcut,
.gcli-help-synopsis {
padding: 0 3px;
margin: 0 4px;
font-size: 80%;
font-family: Menlo, Monaco, monospace;
cursor: pointer;
vertical-align: bottom;
white-space: pre;
color: #000;
background-color: #fff;
font-weight: normal;
font-size: 90%;
border-radius: 3px;
background-color: hsl(210,11%,16%);
border: 1px solid hsl(210,11%,10%);
}
.gcli-out-shortcut:before {
color: #66F;
content: '\bb';
.gcli-out-shortcut:before,
.gcli-help-synopsis:before {
color: hsl(210,30%,85%);
-moz-padding-end: 2px;
}
/* From: $GCLI/lib/gcli/commands/help.css */
.gcli-help-arrow {
font-size: 70%;
color: #AAA;
}
.gcli-help-synopsis {
font-family: Menlo, Monaco, monospace;
font-weight: normal;
padding: 0 3px;
margin: 0 10px;
border: 1px solid #999;
border-radius: 3px;
color: #000;
}
.gcli-help-synopsis:before {
color: #66F;
color: #666;
}
.gcli-help-description {
@ -87,33 +103,22 @@
margin: 10px 0 6px;
}
/* From: $GCLI/lib/gcli/ui/fields/menu.css */
.gcli-menu-name {
-moz-padding-start: 8px;
}
.gcli-menu-desc {
-moz-padding-end: 8px;
color: #999;
color: hsl(210,30%,75%);
}
.gcli-menu-option:hover {
background-image: url(background-noise-toolbar.png),
-moz-linear-gradient(top, hsl(210,11%,22%), hsl(210,11%,18%));
background-color: hsla(0,100%,100%,.1);
}
.gcli-menu-highlight,
.gcli-menu-highlight.gcli-menu-option:hover {
background-image: url(background-noise-toolbar.png),
-moz-linear-gradient(top, hsl(210,11%,18%), hsl(210,11%,14%));
}
.gcli-menu-error {
padding: 8px 10px 2px;
font-size: 80%;
color: red;
background-color: hsla(0,0%,0%,.3);
}
.gcli-menu-typed {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 626 B

After

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 B

After

Width:  |  Height:  |  Size: 308 B

View File

@ -193,6 +193,7 @@ browser.jar:
skin/classic/browser/devtools/layoutview.css (devtools/layoutview.css)
skin/classic/browser/devtools/layout-buttons.png (devtools/layout-buttons.png)
skin/classic/browser/devtools/debugger-pause.png (devtools/debugger-pause.png)
skin/classic/browser/devtools/debugger-play.png (devtools/debugger-play.png)
skin/classic/browser/devtools/debugger-step-in.png (devtools/debugger-step-in.png)
skin/classic/browser/devtools/debugger-step-out.png (devtools/debugger-step-out.png)
skin/classic/browser/devtools/debugger-step-over.png (devtools/debugger-step-over.png)

View File

@ -2654,7 +2654,8 @@ panel[dimmed="true"] {
-moz-image-region: rect(0px 32px 16px 16px);
}
#inspector-toolbar {
#inspector-toolbar,
#developer-toolbar {
border-top: 1px solid hsla(211,68%,6%,.65) !important;
}
@ -3057,42 +3058,68 @@ html|*#highlighter-nodeinfobar-pseudo-classes {
border-radius: 0 3px 3px 0;
}
.gcli-panel-inner-arrowcontent {
/* Highlight toolbar - Option menu */
#inspector-option-toolbarbutton:-moz-focusring {
outline: 1px dotted hsla(210,30%,85%,0.4);
outline-offset: -2px;
}
html|*#gcli-tooltip-frame,
html|*#gcli-output-frame {
padding: 0;
border-width: 0;
background-color: transparent;
}
#gcli-output,
#gcli-tooltip {
border-width: 0;
background-color: transparent;
margin-bottom: -2px;
}
.gclitoolbar-input-node,
.gclitoolbar-complete-node,
.gclitoolbar-prompt {
font-family: Consolas, Lucida Console, monospace;
margin: 0;
-moz-margin-end: 3px;
-moz-box-align: center;
padding-top: 0;
padding-bottom: 0;
padding-right: 4px;
border: 1px solid transparent;
border-radius: 3px;
text-shadow: none;
}
.gclitoolbar-input-node {
padding-left: 20px;
background-color: transparent;
-moz-appearance: none;
border: none;
padding: 0 0 0 22px;
border-color: hsl(210,24%,10%);
color: hsl(210,30%,85%);
text-shadow: 0 -1px 0 hsla(210,8%,5%,.45);
box-shadow: inset 0 1px 0 hsla(211,68%,6%,.05),
0 0 0 1px hsla(210,40%,83%,.1);
}
.gclitoolbar-complete-node {
padding-left: 21px;
background-color: transparent;
color: transparent;
height: 100%;
line-height: 100%;
padding: 7px 0 0 27px;
margin: 0;
}
.gclitoolbar-prompt {
color: hsl(25,78%,50%);
-moz-appearance: textfield;
padding-left: 4px;
padding-bottom: 2px;
font-size: 150%;
font-weight: bold;
line-height: 100%;
padding-top: 1px;
padding-left: 4px;
color: hsl(210,30%,85%);
background-color: hsl(210,24%,16%);
}
.gclitoolbar-prompt-label,
.gcli-in-incomplete,
.gcli-in-error,
.gcli-in-ontab,
@ -3113,20 +3140,13 @@ html|*#highlighter-nodeinfobar-pseudo-classes {
}
.gcli-in-ontab {
color: hsl(200,40%,70%);
color: hsl(210,0%,35%);
}
.gcli-in-todo {
color: hsl(48,28%,76%);
color: hsl(210,50%,35%);
}
.gcli-in-closebrace {
color: hsl(0,0%,80%);
}
/* Highlight toolbar - Option menu */
#inspector-option-toolbarbutton:-moz-focusring {
outline: 1px dotted hsla(210,30%,85%,0.4);
outline-offset: -2px;
}

View File

@ -140,7 +140,7 @@
-moz-image-region: rect(0, 48px, 16px, 32px);
}
/* Splitter */
/* Splitters */
.devtools-horizontal-splitter {
-moz-appearance: none;
@ -152,3 +152,13 @@
margin-bottom: -3px;
position: relative;
}
.devtools-side-splitter {
border: 0;
-moz-border-start: 1px solid #242b33;
min-width: 0;
width: 3px;
background-color: transparent;
-moz-margin-end: -3px;
position: relative;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 B

View File

@ -13,7 +13,7 @@
*/
#dbg-content {
padding: 6px;
padding: 0;
}
/**
@ -52,7 +52,7 @@
}
/**
* Properties elements
* Properties view
*/
#variables {
@ -60,7 +60,7 @@
}
/**
* Generic element details container
* Property element details container
*/
.details {
@ -73,24 +73,17 @@
*/
.scope > .title {
margin-top: 1px;
-moz-margin-start: 1px;
-moz-padding-start: 2px;
background: -moz-linear-gradient(bottom,
rgb(160,175,205) 0,
rgb(120,140,175) 100%);
border-bottom: 1px solid #888;
box-shadow: 0 0 4px #ccc;
text-shadow: 0 1px #777;
text-shadow: 0 1px #222;
color: #fff;
font: -moz-list;
}
.scope > .title > .arrow {
margin-top: -2px;
}
.scope > .title > .name {
padding-top: 2px;
padding-bottom: 2px;
}
.scope > .details {
@ -106,7 +99,7 @@
-moz-margin-start: 1px;
-moz-margin-end: 1px;
margin-top: 2px;
border-bottom: 1px dotted #aaa;
border-bottom: 1px dotted #ccc;
border-radius: 8px;
-moz-transition: background 1s ease-in-out;
background: #fff;
@ -143,8 +136,13 @@
color: #881090;
}
.property > .title > .non-enumerable.key,
.property > .title > .proto.key {
color: #c48bc8;
}
/**
* Property colors
* Property values colors
*/
.token-undefined {
@ -222,12 +220,12 @@
*/
#resume {
list-style-image: url("chrome://browser/skin/devtools/debugger-play.png");
-moz-image-region: rect(0px, 16px, 16px, 0px);
}
#resume[checked=true] {
-moz-image-region: rect(0px, 32px, 16px, 16px);
list-style-image: url("chrome://browser/skin/devtools/debugger-pause.png");
}
#step-over {

View File

@ -2,10 +2,44 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#gclichrome-body {
.gcli-body {
margin: 0;
padding: 0;
font: message-box;
color: hsl(210,30%,85%);
}
#gcli-output-root,
#gcli-tooltip-root {
border: 1px solid hsl(210,24%,10%);
box-shadow: 0 1px 0 hsla(209,29%,72%,.25) inset;
background-image: -moz-linear-gradient(top, hsla(209,18%,18%,0.9), hsl(210,24%,16%));
border-radius: 3px;
}
#gcli-output-root {
padding: 5px 10px;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
border-bottom: 0;
}
#gcli-tooltip-root {
padding: 5px 0px;
}
#gcli-tooltip-connector {
margin-top: -1px;
margin-left: 8px;
width: 20px;
height: 10px;
border-left: 1px solid hsl(210,24%,10%);
border-right: 1px solid hsl(210,24%,10%);
background-color: hsl(210,24%,16%);
}
.gcli-tt-description,
.gcli-tt-error {
padding: 0 10px;
}
.gcli-row-out {
@ -13,6 +47,7 @@
line-height: 1.2em;
border-top: none;
border-bottom: none;
color: hsl(210,30%,85%);
}
.gcli-row-out p,
@ -22,43 +57,35 @@
margin: 5px 0;
}
.gcli-out-shortcut {
border: 1px solid #999;
border-radius: 3px;
padding: 1px 4px 0;
.gcli-row-out h1,
.gcli-row-out h2,
.gcli-row-out h3,
.gcli-row-out h4,
.gcli-row-out h5,
.gcli-row-out th,
.gcli-row-out strong {
color: hsl(210,30%,95%);
}
.gcli-out-shortcut,
.gcli-help-synopsis {
padding: 0 3px;
margin: 0 4px;
font-size: 80%;
font-family: Consolas, Inconsolata, "Courier New", monospace;
cursor: pointer;
vertical-align: bottom;
white-space: pre;
background-color: #fff;
font-weight: normal;
font-size: 90%;
border-radius: 3px;
background-color: hsl(210,24%,16%);
border: 1px solid hsl(210,24%,10%);
}
.gcli-out-shortcut:before {
color: #66F;
content: '\bb';
.gcli-out-shortcut:before,
.gcli-help-synopsis:before {
color: hsl(210,30%,85%);
-moz-padding-end: 2px;
}
/* From: $GCLI/lib/gcli/commands/help.css */
.gcli-help-arrow {
font-size: 70%;
color: #AAA;
}
.gcli-help-synopsis {
font-family: Consolas, Inconsolata, "Courier New", monospace;
font-weight: normal;
padding: 0 3px;
margin: 0 10px;
border: 1px solid #999;
border-radius: 3px;
}
.gcli-help-synopsis:before {
color: #66F;
color: #666;
}
.gcli-help-description {
@ -75,31 +102,22 @@
margin: 10px 0 6px;
}
/* From: $GCLI/lib/gcli/ui/fields/menu.css */
.gcli-menu-name {
-moz-padding-start: 8px;
}
.gcli-menu-desc {
-moz-padding-end: 8px;
color: #999;
color: hsl(210,30%,75%);
}
.gcli-menu-option:hover {
background-color: #EEE;
background-color: hsla(0,100%,100%,.1);
}
.gcli-menu-highlight,
.gcli-menu-highlight.gcli-menu-option:hover {
background-color: #DDD;
}
.gcli-menu-error {
padding: 8px 10px 2px;
font-size: 80%;
color: red;
background-color: hsla(0,0%,0%,.3);
}
.gcli-menu-typed {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 626 B

After

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 B

After

Width:  |  Height:  |  Size: 308 B

View File

@ -179,6 +179,7 @@ browser.jar:
skin/classic/browser/devtools/layoutview.css (devtools/layoutview.css)
skin/classic/browser/devtools/layout-buttons.png (devtools/layout-buttons.png)
skin/classic/browser/devtools/debugger-pause.png (devtools/debugger-pause.png)
skin/classic/browser/devtools/debugger-play.png (devtools/debugger-play.png)
skin/classic/browser/devtools/debugger-step-in.png (devtools/debugger-step-in.png)
skin/classic/browser/devtools/debugger-step-out.png (devtools/debugger-step-out.png)
skin/classic/browser/devtools/debugger-step-over.png (devtools/debugger-step-over.png)
@ -373,6 +374,7 @@ browser.jar:
skin/classic/aero/browser/devtools/layoutview.css (devtools/layoutview.css)
skin/classic/aero/browser/devtools/layout-buttons.png (devtools/layout-buttons.png)
skin/classic/aero/browser/devtools/debugger-pause.png (devtools/debugger-pause.png)
skin/classic/aero/browser/devtools/debugger-play.png (devtools/debugger-play.png)
skin/classic/aero/browser/devtools/debugger-step-in.png (devtools/debugger-step-in.png)
skin/classic/aero/browser/devtools/debugger-step-out.png (devtools/debugger-step-out.png)
skin/classic/aero/browser/devtools/debugger-step-over.png (devtools/debugger-step-over.png)

View File

@ -255,6 +255,7 @@ _TEST_FILES1 = \
test_DOMException.html \
test_mutationobservers.html \
mutationobserver_dialog.html \
test_bug744830.html \
$(NULL)
_TEST_FILES2 = \

View File

@ -27,7 +27,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=392511
/** Test for Bug 392511 **/
var results = [
"'\"&amp;'",
"\"&quot;&amp;\"",
"\"&quot;&amp;\"",
"\"'&amp;\"",
"\"'&amp;\"",

View File

@ -0,0 +1,126 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=744830
-->
<head>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=166235">Mozilla Bug 166235</a>
<div id="testnodes"><span>hi</span> there <!-- mon ami --></div>
<pre id="test">
<script type="application/javascript">
var t = document.getElementById('testnodes');
is(t.innerHTML,
"<span>hi</span> there <!-- mon ami -->",
"comment nodes should be included");
var PI = document.createProcessingInstruction('foo', 'bar="1.0"');
t.appendChild(PI);
is(t.innerHTML, '<span>hi</span> there <!-- mon ami --><?foo bar="1.0">',
"pi nodes should be included");
t.innerHTML = null;
t.appendChild(document.createElement("textarea"));
t.firstChild.appendChild(document.createTextNode("\nhello"));
// This is the old behavior. Spec requires something else.
is(t.innerHTML, "<textarea>\nhello</textarea>",
"No extra newlines should be inserted to the textarea!");
t.innerHTML = null;
t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg:svg"));
t.firstChild.textContent = "<foo>";
is(t.innerHTML, "<svg>&lt;foo&gt;</svg>");
t.innerHTML = null;
t.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "math:math"));
t.firstChild.textContent = "<foo>";
is(t.innerHTML, "<math>&lt;foo&gt;</math>");
// Prefix is serialized if element isn't HTML/SVG/MathML
t.innerHTML = null;
t.appendChild(document.createElementNS("http://www.example.org", "ex:example"));
t.firstChild.textContent = "<foo>";
is(t.innerHTML, "<ex:example>&lt;foo&gt;</ex:example>");
t.innerHTML = null;
t.appendChild(document.createElementNS("http://www.example.org", "example"));
t.firstChild.textContent = "<foo>";
is(t.innerHTML, "<example>&lt;foo&gt;</example>");
t.firstChild.setAttributeNS("http://www.w3.org/XML/1998/namespace", "xml:lang", "us-en");
is(t.innerHTML, '<example xml:lang="us-en">&lt;foo&gt;</example>');
t.firstChild.setAttributeNS("http://www.w3.org/1999/xlink", "href", "foo");
is(t.innerHTML, '<example xlink:href="foo" xml:lang="us-en">&lt;foo&gt;</example>');
t.firstChild.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", "http://foo");
is(t.innerHTML, '<example xmlns="http://foo" xlink:href="foo" xml:lang="us-en">&lt;foo&gt;</example>');
t.firstChild.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:bar", "http://bar");
is(t.innerHTML, '<example xmlns:bar="http://bar" xmlns="http://foo" xlink:href="foo" xml:lang="us-en">&lt;foo&gt;</example>');
t.firstChild.setAttributeNS("http://www.helloworldns.org", "hello:world", "!");
is(t.innerHTML, '<example hello:world="!" xmlns:bar="http://bar" xmlns="http://foo" xlink:href="foo" xml:lang="us-en">&lt;foo&gt;</example>');
t.firstChild.setAttribute("foo", '-"&\xA0-');
is(t.innerHTML, '<example foo="-&quot;&amp;&nbsp;-" hello:world="!" xmlns:bar="http://bar" xmlns="http://foo" xlink:href="foo" xml:lang="us-en">&lt;foo&gt;</example>');
t.innerHTML = null;
t.appendChild(document.createElement("div"));
t.firstChild.appendChild(document.implementation
.createDocument(null, null, null)
.createCDATASection("foo"));
is(t.innerHTML, '<div>foo</div>');
t.firstChild.textContent = "1&2<3>4\xA0";
is(t.innerHTML, '<div>1&amp;2&lt;3&gt;4&nbsp;</div>');
t.innerHTML = null;
t.appendChild(document.createElement("script"));
t.firstChild.textContent = "1&2<3>4\xA0";
is(t.innerHTML, '<script>1&2<3>4\xA0\u003C/script>');
t.innerHTML = null;
t.appendChild(document.createElement("style"));
t.firstChild.textContent = "1&2<3>4\xA0";
is(t.innerHTML, '<style>1&2<3>4\xA0\u003C/style>');
t.innerHTML = null;
t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg"));
is(t.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
t.firstChild.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "script"));
is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
is(t.innerHTML, '<svg><script>1&amp;2&lt;3&gt;4&nbsp;\u003C/script></svg>');
t.innerHTML = null;
t.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg"));
is(t.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
t.firstChild.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "style"));
is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/2000/svg");
t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
is(t.innerHTML, '<svg><style>1&amp;2&lt;3&gt;4&nbsp;\u003C/style></svg>');
t.innerHTML = null;
t.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "math"));
is(t.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
t.firstChild.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "script"));
is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
is(t.innerHTML, '<math><script>1&amp;2&lt;3&gt;4&nbsp;\u003C/script></math>');
t.innerHTML = null;
t.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "math"));
is(t.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
t.firstChild.appendChild(document.createElementNS("http://www.w3.org/1998/Math/MathML", "style"));
is(t.firstChild.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML");
t.firstChild.firstChild.textContent = "1&2<3>4\xA0";
is(t.innerHTML, '<math><style>1&amp;2&lt;3&gt;4&nbsp;\u003C/style></math>');
</script>
</pre>
</body>
</html>

View File

@ -89,6 +89,7 @@
#include "nsDOMMutationObserver.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/FromParser.h"
#include "mozilla/BloomFilter.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -632,19 +633,609 @@ nsGenericHTMLElement::GetOffsetParent(nsIDOMElement** aOffsetParent)
return NS_OK;
}
// Try to keep the size of StringBuilder close to a jemalloc bucket size.
#define STRING_BUFFER_UNITS 1020
class StringBuilder
{
private:
class Unit
{
public:
Unit() : mType(eUnknown), mLength(0) {}
~Unit()
{
if (mType == eString || mType == eStringWithEncode) {
delete mString;
}
}
enum Type
{
eUnknown,
eAtom,
eString,
eStringWithEncode,
eLiteral,
eTextFragment,
eTextFragmentWithEncode,
};
union
{
nsIAtom* mAtom;
const char* mLiteral;
nsAutoString* mString;
const nsTextFragment* mTextFragment;
};
Type mType;
PRUint32 mLength;
};
public:
StringBuilder() : mLast(this), mLength(0) {}
void Append(nsIAtom* aAtom)
{
Unit* u = AddUnit();
u->mAtom = aAtom;
u->mType = Unit::eAtom;
PRUint32 len = aAtom->GetLength();
u->mLength = len;
mLength += len;
}
template<int N>
void Append(const char (&aLiteral)[N])
{
Unit* u = AddUnit();
u->mLiteral = aLiteral;
u->mType = Unit::eLiteral;
PRUint32 len = N - 1;
u->mLength = len;
mLength += len;
}
template<int N>
void Append(char (&aLiteral)[N])
{
Unit* u = AddUnit();
u->mLiteral = aLiteral;
u->mType = Unit::eLiteral;
PRUint32 len = N - 1;
u->mLength = len;
mLength += len;
}
void Append(const nsAString& aString)
{
Unit* u = AddUnit();
u->mString = new nsAutoString(aString);
u->mType = Unit::eString;
PRUint32 len = aString.Length();
u->mLength = len;
mLength += len;
}
void Append(nsAutoString* aString)
{
Unit* u = AddUnit();
u->mString = aString;
u->mType = Unit::eString;
PRUint32 len = aString->Length();
u->mLength = len;
mLength += len;
}
void AppendWithAttrEncode(nsAutoString* aString, PRUint32 aLen)
{
Unit* u = AddUnit();
u->mString = aString;
u->mType = Unit::eStringWithEncode;
u->mLength = aLen;
mLength += aLen;
}
void Append(const nsTextFragment* aTextFragment)
{
Unit* u = AddUnit();
u->mTextFragment = aTextFragment;
u->mType = Unit::eTextFragment;
PRUint32 len = aTextFragment->GetLength();
u->mLength = len;
mLength += len;
}
void AppendWithEncode(const nsTextFragment* aTextFragment, PRUint32 aLen)
{
Unit* u = AddUnit();
u->mTextFragment = aTextFragment;
u->mType = Unit::eTextFragmentWithEncode;
u->mLength = aLen;
mLength += aLen;
}
bool ToString(nsAString& aOut)
{
if (!aOut.SetCapacity(mLength, fallible_t())) {
return false;
}
for (StringBuilder* current = this; current; current = current->mNext) {
PRUint32 len = current->mUnits.Length();
for (PRUint32 i = 0; i < len; ++i) {
Unit& u = current->mUnits[i];
switch (u.mType) {
case Unit::eAtom:
aOut.Append(nsDependentAtomString(u.mAtom));
break;
case Unit::eString:
aOut.Append(*(u.mString));
break;
case Unit::eStringWithEncode:
EncodeAttrString(*(u.mString), aOut);
break;
case Unit::eLiteral:
aOut.AppendASCII(u.mLiteral, u.mLength);
break;
case Unit::eTextFragment:
u.mTextFragment->AppendTo(aOut);
break;
case Unit::eTextFragmentWithEncode:
EncodeTextFragment(u.mTextFragment, aOut);
break;
default:
MOZ_NOT_REACHED("Unknown unit type?");
}
}
}
return true;
}
private:
Unit* AddUnit()
{
if (mLast->mUnits.Length() == STRING_BUFFER_UNITS) {
new StringBuilder(this);
}
return mLast->mUnits.AppendElement();
}
StringBuilder(StringBuilder* aFirst)
: mLast(nsnull), mLength(0)
{
aFirst->mLast->mNext = this;
aFirst->mLast = this;
}
void EncodeAttrString(const nsAutoString& aValue, nsAString& aOut)
{
const PRUnichar* c = aValue.BeginReading();
const PRUnichar* end = aValue.EndReading();
while (c < end) {
switch (*c) {
case '"':
aOut.AppendLiteral("&quot;");
break;
case '&':
aOut.AppendLiteral("&amp;");
break;
case 0x00A0:
aOut.AppendLiteral("&nbsp;");
break;
default:
aOut.Append(*c);
break;
}
++c;
}
}
void EncodeTextFragment(const nsTextFragment* aValue, nsAString& aOut)
{
PRUint32 len = aValue->GetLength();
if (aValue->Is2b()) {
const PRUnichar* data = aValue->Get2b();
for (PRUint32 i = 0; i < len; ++i) {
const PRUnichar c = data[i];
switch (c) {
case '<':
aOut.AppendLiteral("&lt;");
break;
case '>':
aOut.AppendLiteral("&gt;");
break;
case '&':
aOut.AppendLiteral("&amp;");
break;
case 0x00A0:
aOut.AppendLiteral("&nbsp;");
break;
default:
aOut.Append(c);
break;
}
}
} else {
const char* data = aValue->Get1b();
for (PRUint32 i = 0; i < len; ++i) {
const unsigned char c = data[i];
switch (c) {
case '<':
aOut.AppendLiteral("&lt;");
break;
case '>':
aOut.AppendLiteral("&gt;");
break;
case '&':
aOut.AppendLiteral("&amp;");
break;
case 0x00A0:
aOut.AppendLiteral("&nbsp;");
break;
default:
aOut.Append(c);
break;
}
}
}
}
nsAutoTArray<Unit, STRING_BUFFER_UNITS> mUnits;
nsAutoPtr<StringBuilder> mNext;
StringBuilder* mLast;
// mLength is used only in the first StringBuilder object in the linked list.
PRUint32 mLength;
};
static void
AppendEncodedCharacters(const nsTextFragment* aText, StringBuilder& aBuilder)
{
PRUint32 extraSpaceNeeded = 0;
PRUint32 len = aText->GetLength();
if (aText->Is2b()) {
const PRUnichar* data = aText->Get2b();
for (PRUint32 i = 0; i < len; ++i) {
const PRUnichar c = data[i];
switch (c) {
case '<':
extraSpaceNeeded += ArrayLength("&lt;") - 2;
break;
case '>':
extraSpaceNeeded += ArrayLength("&gt;") - 2;
break;
case '&':
extraSpaceNeeded += ArrayLength("&amp;") - 2;
break;
case 0x00A0:
extraSpaceNeeded += ArrayLength("&nbsp;") - 2;
break;
default:
break;
}
}
} else {
const char* data = aText->Get1b();
for (PRUint32 i = 0; i < len; ++i) {
const unsigned char c = data[i];
switch (c) {
case '<':
extraSpaceNeeded += ArrayLength("&lt;") - 2;
break;
case '>':
extraSpaceNeeded += ArrayLength("&gt;") - 2;
break;
case '&':
extraSpaceNeeded += ArrayLength("&amp;") - 2;
break;
case 0x00A0:
extraSpaceNeeded += ArrayLength("&nbsp;") - 2;
break;
default:
break;
}
}
}
if (extraSpaceNeeded) {
aBuilder.AppendWithEncode(aText, len + extraSpaceNeeded);
} else {
aBuilder.Append(aText);
}
}
static void
AppendEncodedAttributeValue(nsAutoString* aValue, StringBuilder& aBuilder)
{
const PRUnichar* c = aValue->BeginReading();
const PRUnichar* end = aValue->EndReading();
PRUint32 extraSpaceNeeded = 0;
while (c < end) {
switch (*c) {
case '"':
extraSpaceNeeded += ArrayLength("&quot;") - 2;
break;
case '&':
extraSpaceNeeded += ArrayLength("&amp;") - 2;
break;
case 0x00A0:
extraSpaceNeeded += ArrayLength("&nbsp;") - 2;
break;
default:
break;
}
++c;
}
if (extraSpaceNeeded) {
aBuilder.AppendWithAttrEncode(aValue, aValue->Length() + extraSpaceNeeded);
} else {
aBuilder.Append(aValue);
}
}
static void
StartElement(Element* aContent, StringBuilder& aBuilder)
{
nsIAtom* localName = aContent->Tag();
PRInt32 tagNS = aContent->GetNameSpaceID();
aBuilder.Append("<");
if (aContent->IsHTML() || aContent->IsSVG() || aContent->IsMathML()) {
aBuilder.Append(localName);
} else {
aBuilder.Append(aContent->NodeName());
}
PRInt32 count = aContent->GetAttrCount();
for (PRInt32 i = count; i > 0;) {
--i;
const nsAttrName* name = aContent->GetAttrNameAt(i);
PRInt32 attNs = name->NamespaceID();
nsIAtom* attName = name->LocalName();
// Filter out any attribute starting with [-|_]moz
nsDependentAtomString attrNameStr(attName);
if (StringBeginsWith(attrNameStr, NS_LITERAL_STRING("_moz")) ||
StringBeginsWith(attrNameStr, NS_LITERAL_STRING("-moz"))) {
continue;
}
nsAutoString* attValue = new nsAutoString();
aContent->GetAttr(attNs, attName, *attValue);
// Filter out special case of <br type="_moz*"> used by the editor.
// Bug 16988. Yuck.
if (localName == nsGkAtoms::br && tagNS == kNameSpaceID_XHTML &&
attName == nsGkAtoms::type && attNs == kNameSpaceID_None &&
StringBeginsWith(*attValue, NS_LITERAL_STRING("_moz"))) {
delete attValue;
continue;
}
if (NS_LIKELY(attNs == kNameSpaceID_None) ||
(attNs == kNameSpaceID_XMLNS &&
attName == nsGkAtoms::xmlns)) {
aBuilder.Append(" ");
} else if (attNs == kNameSpaceID_XML) {
aBuilder.Append(" xml:");
} else if (attNs == kNameSpaceID_XMLNS) {
aBuilder.Append(" xmlns:");
} else if (attNs == kNameSpaceID_XLink) {
aBuilder.Append(" xlink:");
} else {
nsIAtom* prefix = name->GetPrefix();
if (prefix) {
aBuilder.Append(" ");
aBuilder.Append(prefix);
aBuilder.Append(":");
}
}
aBuilder.Append(attName);
aBuilder.Append("=\"");
AppendEncodedAttributeValue(attValue, aBuilder);
aBuilder.Append("\"");
}
aBuilder.Append(">");
/*
// Per HTML spec we should append one \n if the first child of
// pre/textarea/listing is a textnode and starts with a \n.
// But because browsers haven't traditionally had that behavior,
// we're not changing our behavior either - yet.
if (aContent->IsHTML()) {
if (localName == nsGkAtoms::pre || localName == nsGkAtoms::textarea ||
localName == nsGkAtoms::listing) {
nsIContent* fc = aContent->GetFirstChild();
if (fc &&
(fc->NodeType() == nsIDOMNode::TEXT_NODE ||
fc->NodeType() == nsIDOMNode::CDATA_SECTION_NODE)) {
const nsTextFragment* text = fc->GetText();
if (text && text->GetLength() && text->CharAt(0) == PRUnichar('\n')) {
aBuilder.Append("\n");
}
}
}
}*/
}
static inline bool
ShouldEscape(nsIContent* aParent)
{
if (!aParent || !aParent->IsHTML()) {
return true;
}
static const nsIAtom* nonEscapingElements[] = {
nsGkAtoms::style, nsGkAtoms::script, nsGkAtoms::xmp,
nsGkAtoms::iframe, nsGkAtoms::noembed, nsGkAtoms::noframes,
nsGkAtoms::plaintext,
// Per the current spec noscript should be escaped in case
// scripts are disabled or if document doesn't have
// browsing context. However the latter seems to be a spec bug
// and Gecko hasn't traditionally done the former.
nsGkAtoms::noscript
};
static mozilla::BloomFilter<12, nsIAtom> sFilter;
static bool sInitialized = false;
if (!sInitialized) {
sInitialized = true;
for (PRUint32 i = 0; i < ArrayLength(nonEscapingElements); ++i) {
sFilter.add(nonEscapingElements[i]);
}
}
nsIAtom* tag = aParent->Tag();
if (sFilter.mightContain(tag)) {
for (PRUint32 i = 0; i < ArrayLength(nonEscapingElements); ++i) {
if (tag == nonEscapingElements[i]) {
return false;
}
}
}
return true;
}
static inline bool
IsVoidTag(Element* aElement)
{
if (!aElement->IsHTML()) {
return false;
}
static const nsIAtom* voidElements[] = {
nsGkAtoms::area, nsGkAtoms::base, nsGkAtoms::basefont,
nsGkAtoms::bgsound, nsGkAtoms::br, nsGkAtoms::col,
nsGkAtoms::command, nsGkAtoms::embed, nsGkAtoms::frame,
nsGkAtoms::hr, nsGkAtoms::img, nsGkAtoms::input,
nsGkAtoms::keygen, nsGkAtoms::link, nsGkAtoms::meta,
nsGkAtoms::param, nsGkAtoms::source, nsGkAtoms::track,
nsGkAtoms::wbr
};
static mozilla::BloomFilter<12, nsIAtom> sFilter;
static bool sInitialized = false;
if (!sInitialized) {
sInitialized = true;
for (PRUint32 i = 0; i < ArrayLength(voidElements); ++i) {
sFilter.add(voidElements[i]);
}
}
nsIAtom* tag = aElement->Tag();
if (sFilter.mightContain(tag)) {
for (PRUint32 i = 0; i < ArrayLength(voidElements); ++i) {
if (tag == voidElements[i]) {
return true;
}
}
}
return false;
}
static bool
Serialize(Element* aRoot, bool aDescendentsOnly, nsAString& aOut)
{
nsINode* current = aDescendentsOnly ? aRoot->GetFirstChild() : aRoot;
if (!current) {
return true;
}
StringBuilder builder;
nsIContent* next;
while (true) {
bool isVoid = false;
switch (current->NodeType()) {
case nsIDOMNode::ELEMENT_NODE: {
Element* elem = current->AsElement();
StartElement(elem, builder);
isVoid = IsVoidTag(elem);
if (!isVoid && (next = current->GetFirstChild())) {
current = next;
continue;
}
break;
}
case nsIDOMNode::TEXT_NODE:
case nsIDOMNode::CDATA_SECTION_NODE: {
const nsTextFragment* text = static_cast<nsIContent*>(current)->GetText();
nsIContent* parent = current->GetParent();
if (ShouldEscape(parent)) {
AppendEncodedCharacters(text, builder);
} else {
builder.Append(text);
}
break;
}
case nsIDOMNode::COMMENT_NODE: {
builder.Append("<!--");
builder.Append(static_cast<nsIContent*>(current)->GetText());
builder.Append("-->");
break;
}
case nsIDOMNode::DOCUMENT_TYPE_NODE: {
builder.Append("<!DOCTYPE ");
builder.Append(current->NodeName());
builder.Append(">");
break;
}
case nsIDOMNode::PROCESSING_INSTRUCTION_NODE: {
builder.Append("<?");
builder.Append(current->NodeName());
builder.Append(" ");
builder.Append(static_cast<nsIContent*>(current)->GetText());
builder.Append(">");
break;
}
}
while (true) {
if (!isVoid && current->NodeType() == nsIDOMNode::ELEMENT_NODE) {
builder.Append("</");
nsIContent* elem = static_cast<nsIContent*>(current);
if (elem->IsHTML() || elem->IsSVG() || elem->IsMathML()) {
builder.Append(elem->Tag());
} else {
builder.Append(current->NodeName());
}
builder.Append(">");
}
isVoid = false;
if (current == aRoot) {
return builder.ToString(aOut);
}
if ((next = current->GetNextSibling())) {
current = next;
break;
}
current = current->GetNodeParent();
if (aDescendentsOnly && current == aRoot) {
return builder.ToString(aOut);
}
}
}
}
nsresult
nsGenericHTMLElement::GetMarkup(bool aIncludeSelf, nsAString& aMarkup)
{
aMarkup.Truncate();
nsIDocument* doc = OwnerDoc();
if (IsInHTMLDocument()) {
return Serialize(this, !aIncludeSelf, aMarkup) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
nsAutoString contentType;
if (IsInHTMLDocument()) {
contentType.AssignLiteral("text/html");
} else {
doc->GetContentType(contentType);
}
doc->GetContentType(contentType);
nsCOMPtr<nsIDocumentEncoder> docEncoder = doc->GetCachedEncoder();
if (!docEncoder) {
@ -654,7 +1245,7 @@ nsGenericHTMLElement::GetMarkup(bool aIncludeSelf, nsAString& aMarkup)
NS_ConvertUTF16toUTF8(contentType)
).get());
}
if (!(docEncoder || doc->IsHTML())) {
if (!docEncoder) {
// This could be some type for which we create a synthetic document. Try
// again as XML
contentType.AssignLiteral("application/xml");

View File

@ -52,6 +52,7 @@
#include "nsSVGSVGElement.h"
#include "nsSVGTextContainerFrame.h"
#include "SVGAnimatedPreserveAspectRatio.h"
#include "mozilla/unused.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -1669,9 +1670,9 @@ nsSVGUtils::WritePPM(const char *fname, gfxImageSurface *aSurface)
PRInt32 stride = aSurface->Stride();
for (int y=0; y<size.height; y++) {
for (int x=0; x<size.width; x++) {
fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_R, 1, 1, f);
fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_G, 1, 1, f);
fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_B, 1, 1, f);
unused << fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_R, 1, 1, f);
unused << fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_G, 1, 1, f);
unused << fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_B, 1, 1, f);
}
}
fclose(f);

View File

@ -0,0 +1,76 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_net_AutoClose_h
#define mozilla_net_AutoClose_h
#include "nsCOMPtr.h"
namespace mozilla { namespace net {
// Like an nsAutoPtr for XPCOM streams (e.g. nsIAsyncInputStream) and other
// refcounted classes that need to have the Close() method called explicitly
// before they are destroyed.
template <typename T>
class AutoClose
{
public:
AutoClose() { }
~AutoClose(){
Close();
}
operator bool() const
{
return mPtr;
}
already_AddRefed<T> forget()
{
return mPtr.forget();
}
void takeOver(AutoClose<T> & rhs)
{
Close();
mPtr = rhs.mPtr.forget();
}
// assign from |do_QueryInterface(expr, &rv)|
void operator=(const nsQueryInterfaceWithError rhs)
{
Close();
mPtr = rhs;
}
void CloseAndRelease()
{
Close();
mPtr = nsnull;
}
T* operator->() const
{
return mPtr.operator->();
}
private:
void Close()
{
if (mPtr) {
mPtr->Close();
}
}
void operator=(const AutoClose<T> &) MOZ_DELETE;
AutoClose(const AutoClose<T> &) MOZ_DELETE;
nsCOMPtr<T> mPtr;
};
} } // namespace mozilla::net
#endif // mozilla_net_AutoClose_h

View File

@ -540,6 +540,11 @@ nsInputStreamWrapper::LazyInit()
rv = nsCacheService::OpenInputStreamForEntry(cacheEntry, mode,
mStartOffset,
getter_AddRefs(mInput));
CACHE_LOG_DEBUG(("nsInputStreamWrapper::LazyInit "
"[entry=%p, wrapper=%p, mInput=%p, rv=%d]",
mDescriptor, this, mInput.get(), PRIntn(rv)));
if (NS_FAILED(rv)) return rv;
mInitialized = true;
@ -568,9 +573,14 @@ nsresult nsCacheEntryDescriptor::
nsInputStreamWrapper::Read(char *buf, PRUint32 count, PRUint32 *countRead)
{
nsresult rv = EnsureInit();
if (NS_FAILED(rv)) return rv;
if (NS_SUCCEEDED(rv))
rv = mInput->Read(buf, count, countRead);
return mInput->Read(buf, count, countRead);
CACHE_LOG_DEBUG(("nsInputStreamWrapper::Read "
"[entry=%p, wrapper=%p, mInput=%p, rv=%d]",
mDescriptor, this, mInput.get(), rv));
return rv;
}
nsresult nsCacheEntryDescriptor::

View File

@ -1759,7 +1759,7 @@ nsCacheService::ProcessRequest(nsCacheRequest * request,
if (request->mListener) { // Asynchronous
if (NS_FAILED(rv) && calledFromOpenCacheEntry)
if (NS_FAILED(rv) && calledFromOpenCacheEntry && request->IsBlocking())
return rv; // skip notifying listener, just return rv to caller
// call listener to report error or descriptor

View File

@ -4,6 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsCache.h"
#include "nsDiskCache.h"
#include "nsDiskCacheBlockFile.h"
#include "mozilla/FileUtils.h"
@ -31,14 +32,15 @@ nsDiskCacheBlockFile::Open(nsILocalFile * blockFile,
// open the file - restricted to user, the data could be confidential
nsresult rv = blockFile->OpenNSPRFileDesc(PR_RDWR | PR_CREATE_FILE, 00600, &mFD);
if (NS_FAILED(rv)) return rv; // unable to open or create file
if (NS_FAILED(rv)) {
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheBlockFile::Open "
"[this=%p] unable to open or create file: %d",
this, rv));
return rv; // unable to open or create file
}
// allocate bit map buffer
mBitMap = new PRUint32[mBitMapWords];
if (!mBitMap) {
rv = NS_ERROR_OUT_OF_MEMORY;
goto error_exit;
}
// check if we just creating the file
mFileSize = PR_Available(mFD);
@ -79,9 +81,13 @@ nsDiskCacheBlockFile::Open(nsILocalFile * blockFile,
goto error_exit;
}
}
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheBlockFile::Open [this=%p] succeeded",
this));
return NS_OK;
error_exit:
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheBlockFile::Open [this=%p] failed with "
"error %d", this, rv));
Close(false);
return rv;
}
@ -234,6 +240,9 @@ nsDiskCacheBlockFile::ReadBlocks( void * buffer,
}
*bytesRead = PR_Read(mFD, buffer, bytesToRead);
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheBlockFile::Read [this=%p] "
"returned %d / %d bytes", this, *bytesRead, bytesToRead));
return NS_OK;
}

View File

@ -77,6 +77,8 @@ nsDiskCacheMap::Open(nsILocalFile * cacheDirectory)
if (!cacheFilesExist)
goto error_exit;
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheMap::Open [this=%p] reading map", this));
// read the header
PRUint32 bytesRead = PR_Read(mMapFD, &mHeader, sizeof(nsDiskCacheHeader));
if (sizeof(nsDiskCacheHeader) != bytesRead) goto error_exit;
@ -686,7 +688,11 @@ nsDiskCacheMap::ReadDiskCacheEntry(nsDiskCacheRecord * record)
getter_AddRefs(file));
NS_ENSURE_SUCCESS(rv, nsnull);
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheMap::ReadDiskCacheEntry"
"[this=%p] reading disk cache entry", this));
PRFileDesc * fd = nsnull;
// open the file - restricted to user, the data could be confidential
rv = file->OpenNSPRFileDesc(PR_RDONLY, 00600, &fd);
NS_ENSURE_SUCCESS(rv, nsnull);

View File

@ -108,11 +108,25 @@ nsDiskCacheInputStream::Read(char * buffer, PRUint32 count, PRUint32 * bytesRead
{
*bytesRead = 0;
if (mClosed)
if (mClosed) {
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheInputStream::Read "
"[stream=%p] stream was closed",
this, buffer, count));
return NS_OK;
}
if (mPos == mStreamEnd) return NS_OK;
if (mPos > mStreamEnd) return NS_ERROR_UNEXPECTED;
if (mPos == mStreamEnd) {
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheInputStream::Read "
"[stream=%p] stream at end of file",
this, buffer, count));
return NS_OK;
}
if (mPos > mStreamEnd) {
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheInputStream::Read "
"[stream=%p] stream past end of file (!)",
this, buffer, count));
return NS_ERROR_UNEXPECTED;
}
if (count > mStreamEnd - mPos)
count = mStreamEnd - mPos;
@ -120,7 +134,14 @@ nsDiskCacheInputStream::Read(char * buffer, PRUint32 count, PRUint32 * bytesRead
if (mFD) {
// just read from file
PRInt32 result = PR_Read(mFD, buffer, count);
if (result < 0) return NS_ErrorAccordingToNSPR();
if (result < 0) {
PRErrorCode error = PR_GetError();
nsresult rv = NS_ErrorAccordingToNSPR();
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheInputStream::Read PR_Read failed"
"[stream=%p, rv=%d, NSPR error %s",
this, PRIntn(rv), PR_ErrorToName(error)));
return rv;
}
mPos += (PRUint32)result;
*bytesRead = (PRUint32)result;
@ -134,6 +155,9 @@ nsDiskCacheInputStream::Read(char * buffer, PRUint32 count, PRUint32 * bytesRead
// no data source for input stream
}
CACHE_LOG_DEBUG(("CACHE: nsDiskCacheInputStream::Read "
"[stream=%p, count=%ud, byteRead=%ud] ",
this, PRUintn(count), PRUintn(*bytesRead)));
return NS_OK;
}
@ -679,6 +703,8 @@ nsDiskCacheStreamIO::OpenCacheFile(PRIntn flags, PRFileDesc ** fd)
{
NS_ENSURE_ARG_POINTER(fd);
CACHE_LOG_DEBUG(("nsDiskCacheStreamIO::OpenCacheFile"));
nsresult rv;
nsDiskCacheMap * cacheMap = mDevice->CacheMap();

View File

@ -50,7 +50,6 @@ HttpBaseChannel::HttpBaseChannel()
, mTimingEnabled(false)
, mAllowSpdy(true)
, mSuspendCount(0)
, mRedirectedCachekeys(nsnull)
{
LOG(("Creating HttpBaseChannel @%x\n", this));
@ -1626,8 +1625,7 @@ HttpBaseChannel::SetupReplacementChannel(nsIURI *newURI,
if (mRedirectedCachekeys) {
LOG(("HttpBaseChannel::SetupReplacementChannel "
"[this=%p] transferring chain of redirect cache-keys", this));
httpInternal->SetCacheKeysRedirectChain(mRedirectedCachekeys);
mRedirectedCachekeys = nsnull;
httpInternal->SetCacheKeysRedirectChain(mRedirectedCachekeys.forget());
}
}

View File

@ -140,10 +140,7 @@ public:
inline void CleanRedirectCacheChainIfNecessary()
{
if (mRedirectedCachekeys) {
delete mRedirectedCachekeys;
mRedirectedCachekeys = nsnull;
}
mRedirectedCachekeys = nsnull;
}
NS_IMETHOD HTTPUpgrade(const nsACString & aProtocolName,
nsIHttpUpgradeListener *aListener);
@ -272,7 +269,7 @@ protected:
// Current suspension depth for this channel object
PRUint32 mSuspendCount;
nsTArray<nsCString> *mRedirectedCachekeys;
nsAutoPtr<nsTArray<nsCString> > mRedirectedCachekeys;
};
// Share some code while working around C++'s absurd inability to handle casting

File diff suppressed because it is too large Load Diff

View File

@ -26,15 +26,17 @@
#include "nsIHttpAuthenticableChannel.h"
#include "nsIHttpChannelAuthProvider.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsICryptoHash.h"
#include "nsITimedChannel.h"
#include "nsDNSPrefetch.h"
#include "TimingStruct.h"
#include "AutoClose.h"
#include "mozilla/Telemetry.h"
class nsAHttpConnection;
class AutoRedirectVetoNotifier;
using namespace mozilla::net;
namespace mozilla { namespace net {
class HttpCacheQuery;
//-----------------------------------------------------------------------------
// nsHttpChannel
@ -156,7 +158,8 @@ private:
typedef nsresult (nsHttpChannel::*nsContinueRedirectionFunc)(nsresult result);
bool RequestIsConditional();
nsresult Connect(bool firstTime = true);
nsresult Connect();
nsresult ContinueConnect();
void SpeculativeConnect();
nsresult SetupTransaction();
nsresult CallOnStartRequest();
@ -172,7 +175,6 @@ private:
nsresult ProcessFailedSSLConnect(PRUint32 httpStatus);
nsresult ProcessFallback(bool *waitingForRedirectCallback);
nsresult ContinueProcessFallback(nsresult);
bool ResponseWouldVary();
void HandleAsyncAbort();
nsresult EnsureAssocReq();
@ -200,11 +202,11 @@ private:
nsresult ResolveProxy();
// cache specific methods
nsresult OpenCacheEntry();
nsresult OpenCacheEntry(bool usingSSL);
nsresult OnOfflineCacheEntryAvailable(nsICacheEntryDescriptor *aEntry,
nsCacheAccessMode aAccess,
nsresult aResult);
nsresult OpenNormalCacheEntry();
nsresult OpenNormalCacheEntry(bool usingSSL);
nsresult OnNormalCacheEntryAvailable(nsICacheEntryDescriptor *aEntry,
nsCacheAccessMode aAccess,
nsresult aResult);
@ -219,8 +221,9 @@ private:
nsresult GenerateCacheKey(PRUint32 postID, nsACString &key);
nsresult UpdateExpirationTime();
nsresult CheckCache();
nsresult ShouldUpdateOfflineCacheEntry(bool *shouldCacheForOfflineUse);
nsresult ReadFromCache();
bool ShouldUpdateOfflineCacheEntry();
nsresult StartBufferingCachedEntity(bool usingSSL);
nsresult ReadFromCache(bool alreadyMarkedValid);
void CloseCacheEntry(bool doomOnFailure);
void CloseOfflineCacheEntry();
nsresult InitCacheEntry();
@ -232,7 +235,7 @@ private:
nsresult InstallCacheListener(PRUint32 offset = 0);
nsresult InstallOfflineCacheListener();
void MaybeInvalidateCacheEntryForSubsequentGet();
nsCacheStoragePolicy DetermineStoragePolicy();
nsCacheStoragePolicy DetermineStoragePolicy(bool isPrivate);
nsresult DetermineCacheAccess(nsCacheAccessMode *_retval);
void AsyncOnExamineCachedResponse();
@ -240,12 +243,10 @@ private:
void ClearBogusContentEncodingIfNeeded();
// byte range request specific methods
nsresult SetupByteRangeRequest(PRUint32 partialLen);
nsresult ProcessPartialContent();
nsresult OnDoneReadingPartialCacheEntry(bool *streamDone);
nsresult DoAuthRetry(nsAHttpConnection *);
bool MustValidateBasedOnQueryUrl();
void HandleAsyncRedirectChannelToHttps();
nsresult AsyncRedirectChannelToHttps();
@ -259,16 +260,10 @@ private:
*/
nsresult ProcessSTSHeader();
/**
* Computes and returns a 64 bit encoded string holding a hash of the
* input buffer. Input buffer must be a null-terminated string.
*/
nsresult Hash(const char *buf, nsACString &hash);
void InvalidateCacheEntryForLocation(const char *location);
void AssembleCacheKey(const char *spec, PRUint32 postID, nsACString &key);
nsresult CreateNewURI(const char *loc, nsIURI **newURI);
void DoInvalidateCacheEntry(nsACString &key);
void DoInvalidateCacheEntry(const nsCString &key);
// Ref RFC2616 13.10: "invalidation... MUST only be performed if
// the host part is the same as in the Request-URI"
@ -289,10 +284,15 @@ private:
PRUint64 mLogicalOffset;
// cache specific data
nsRefPtr<HttpCacheQuery> mCacheQuery;
nsCOMPtr<nsICacheEntryDescriptor> mCacheEntry;
// We must close mCacheAsyncInputStream explicitly to avoid leaks.
AutoClose<nsIAsyncInputStream> mCacheAsyncInputStream;
nsRefPtr<nsInputStreamPump> mCachePump;
nsAutoPtr<nsHttpResponseHead> mCachedResponseHead;
nsCOMPtr<nsISupports> mCachedSecurityInfo;
nsCacheAccessMode mCacheAccess;
mozilla::Telemetry::ID mCacheEntryDeviceTelemetryID;
PRUint32 mPostID;
PRUint32 mRequestTime;
@ -317,6 +317,8 @@ private:
friend class AutoRedirectVetoNotifier;
friend class HttpAsyncAborter<nsHttpChannel>;
friend class HttpCacheQuery;
nsCOMPtr<nsIURI> mRedirectURI;
nsCOMPtr<nsIChannel> mRedirectChannel;
PRUint32 mRedirectType;
@ -344,8 +346,6 @@ private:
nsTArray<nsContinueRedirectionFunc> mRedirectFuncStack;
nsCOMPtr<nsICryptoHash> mHasher;
PRTime mChannelCreationTime;
mozilla::TimeStamp mChannelCreationTimestamp;
mozilla::TimeStamp mAsyncOpenTime;
@ -374,4 +374,6 @@ private: // cache telemetry
bool mDidReval;
};
} } // namespace mozilla::net
#endif // nsHttpChannel_h__

View File

@ -406,52 +406,6 @@ nsHttpHandler::IsAcceptableEncoding(const char *enc)
return nsHttp::FindToken(mAcceptEncodings.get(), enc, HTTP_LWS ",") != nsnull;
}
nsresult
nsHttpHandler::GetCacheSession(nsCacheStoragePolicy storagePolicy,
bool isPrivate,
nsICacheSession **result)
{
nsresult rv;
// Skip cache if disabled in preferences
if (!mUseCache)
return NS_ERROR_NOT_AVAILABLE;
// We want to get the pointer to the cache service each time we're called,
// because it's possible for some add-ons (such as Google Gears) to swap
// in new cache services on the fly, and we want to pick them up as
// appropriate.
nsCOMPtr<nsICacheService> serv = do_GetService(NS_CACHESERVICE_CONTRACTID,
&rv);
if (NS_FAILED(rv)) return rv;
const char *sessionName = "HTTP";
switch (storagePolicy) {
case nsICache::STORE_IN_MEMORY:
sessionName = isPrivate ? "HTTP-memory-only-PB" : "HTTP-memory-only";
break;
case nsICache::STORE_OFFLINE:
sessionName = "HTTP-offline";
break;
default:
break;
}
nsCOMPtr<nsICacheSession> cacheSession;
rv = serv->CreateSession(sessionName,
storagePolicy,
nsICache::STREAM_BASED,
getter_AddRefs(cacheSession));
if (NS_FAILED(rv)) return rv;
rv = cacheSession->SetDoomEntriesIfExpired(false);
if (NS_FAILED(rv)) return rv;
NS_ADDREF(*result = cacheSession);
return NS_OK;
}
nsresult
nsHttpHandler::GetStreamConverterService(nsIStreamConverterService **result)
{

View File

@ -101,7 +101,7 @@ public:
nsHttpConnectionMgr *ConnMgr() { return mConnMgr; }
// cache support
nsresult GetCacheSession(nsCacheStoragePolicy, bool isPrivate, nsICacheSession **);
bool UseCache() const { return mUseCache; }
PRUint32 GenerateUniqueID() { return ++mLastUniqueID; }
PRUint32 SessionStartTime() { return mSessionStartTime; }

View File

@ -380,7 +380,11 @@ nsHttpResponseHead::IsResumable() const
{
// even though some HTTP/1.0 servers may support byte range requests, we're not
// going to bother with them, since those servers wouldn't understand If-Range.
return mVersion >= NS_HTTP_VERSION_1_1 &&
// Also, while in theory it may be possible to resume when the status code
// is not 200, it is unlikely to be worth the trouble, especially for
// non-2xx responses.
return mStatus == 200 &&
mVersion >= NS_HTTP_VERSION_1_1 &&
PeekHeader(nsHttp::Content_Length) &&
(PeekHeader(nsHttp::ETag) || PeekHeader(nsHttp::Last_Modified)) &&
HasHeaderValue(nsHttp::Accept_Ranges, "bytes");

View File

@ -491,10 +491,7 @@ nsAutoCompleteController::HandleKeyNavigation(PRUint32 aKey, bool *_retval)
// The user wants explicitely to use that result, so this ensures
// association of the result with the autocompleted text.
nsAutoString value;
nsAutoString inputValue;
input->GetTextValue(inputValue);
if (NS_SUCCEEDED(GetDefaultCompleteValue(-1, false, value)) &&
value.Equals(inputValue, nsCaseInsensitiveStringComparator())) {
if (NS_SUCCEEDED(GetFinalDefaultCompleteValue(value))) {
input->SetTextValue(value);
input->SelectTextRange(value.Length(), value.Length());
}
@ -1184,10 +1181,7 @@ nsAutoCompleteController::EnterMatch(bool aIsPopupSelection)
// The user wants explicitely to use that result, so this ensures
// association of the result with the autocompleted text.
nsAutoString defaultIndexValue;
nsAutoString inputValue;
input->GetTextValue(inputValue);
if (NS_SUCCEEDED(GetDefaultCompleteValue(-1, false, defaultIndexValue)) &&
defaultIndexValue.Equals(inputValue, nsCaseInsensitiveStringComparator()))
if (NS_SUCCEEDED(GetFinalDefaultCompleteValue(defaultIndexValue)))
value = defaultIndexValue;
}
@ -1444,34 +1438,34 @@ nsAutoCompleteController::CompleteDefaultIndex(PRInt32 aResultIndex)
}
nsresult
nsAutoCompleteController::GetDefaultCompleteValue(PRInt32 aResultIndex,
bool aPreserveCasing,
nsAString &_retval)
nsAutoCompleteController::GetDefaultCompleteResult(PRInt32 aResultIndex,
nsIAutoCompleteResult** _result,
PRInt32* _defaultIndex)
{
PRInt32 defaultIndex = -1;
PRInt32 index = aResultIndex;
if (index < 0) {
PRUint32 count = mResults.Count();
for (PRUint32 i = 0; i < count; ++i) {
nsIAutoCompleteResult *result = mResults[i];
if (result && NS_SUCCEEDED(result->GetDefaultIndex(&defaultIndex)) &&
defaultIndex >= 0) {
index = i;
break;
}
*_defaultIndex = -1;
PRInt32 resultIndex = aResultIndex;
// If a result index was not provided, find the first defaultIndex result.
for (PRInt32 i = 0; resultIndex < 0 && i < mResults.Count(); ++i) {
nsIAutoCompleteResult *result = mResults[i];
if (result &&
NS_SUCCEEDED(result->GetDefaultIndex(_defaultIndex)) &&
*_defaultIndex >= 0) {
resultIndex = i;
}
}
NS_ENSURE_TRUE(index >= 0, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(resultIndex >= 0, NS_ERROR_FAILURE);
nsIAutoCompleteResult *result = mResults.SafeObjectAt(index);
NS_ENSURE_TRUE(result != nsnull, NS_ERROR_FAILURE);
*_result = mResults.SafeObjectAt(resultIndex);
NS_ENSURE_TRUE(*_result, NS_ERROR_FAILURE);
if (defaultIndex < 0) {
if (*_defaultIndex < 0) {
// The search must explicitly provide a default index in order
// for us to be able to complete.
result->GetDefaultIndex(&defaultIndex);
(*_result)->GetDefaultIndex(_defaultIndex);
}
if (defaultIndex < 0) {
if (*_defaultIndex < 0) {
// We were given a result index, but that result doesn't want to
// be autocompleted.
return NS_ERROR_FAILURE;
@ -1481,10 +1475,24 @@ nsAutoCompleteController::GetDefaultCompleteValue(PRInt32 aResultIndex,
// provides a defaultIndex greater than its matchCount, avoid trying to
// complete to an empty value.
PRUint32 matchCount = 0;
result->GetMatchCount(&matchCount);
(*_result)->GetMatchCount(&matchCount);
// Here defaultIndex is surely non-negative, so can be cast to unsigned.
if ((PRUint32)defaultIndex >= matchCount)
if ((PRUint32)(*_defaultIndex) >= matchCount) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
nsAutoCompleteController::GetDefaultCompleteValue(PRInt32 aResultIndex,
bool aPreserveCasing,
nsAString &_retval)
{
nsIAutoCompleteResult *result;
PRInt32 defaultIndex = -1;
nsresult rv = GetDefaultCompleteResult(aResultIndex, &result, &defaultIndex);
if (NS_FAILED(rv)) return rv;
nsAutoString resultValue;
result->GetValueAt(defaultIndex, resultValue);
@ -1512,6 +1520,37 @@ nsAutoCompleteController::GetDefaultCompleteValue(PRInt32 aResultIndex,
return NS_OK;
}
nsresult
nsAutoCompleteController::GetFinalDefaultCompleteValue(nsAString &_retval)
{
nsIAutoCompleteResult *result;
PRInt32 defaultIndex = -1;
nsresult rv = GetDefaultCompleteResult(-1, &result, &defaultIndex);
if (NS_FAILED(rv)) return rv;
// Hack: For typeAheadResults allow the comment to be used as the final
// defaultComplete value if provided, otherwise fall back to the usual
// value. This allows to provide a different complete text when the user
// confirms the match. Don't rely on this for production code, since it's a
// temporary solution that needs a dedicated API (bug 754265).
bool isTypeAheadResult = false;
if (NS_SUCCEEDED(result->GetTypeAheadResult(&isTypeAheadResult)) &&
isTypeAheadResult &&
NS_SUCCEEDED(result->GetCommentAt(defaultIndex, _retval)) &&
!_retval.IsEmpty()) {
return NS_OK;
}
result->GetValueAt(defaultIndex, _retval);
nsAutoString inputValue;
mInput->GetTextValue(inputValue);
if (!_retval.Equals(inputValue, nsCaseInsensitiveStringComparator())) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
nsAutoCompleteController::CompleteValue(nsString &aValue)
/* mInput contains mSearchString, which we want to autocomplete to aValue. If

View File

@ -66,8 +66,50 @@ private:
nsresult GetResultValueLabelAt(PRInt32 aIndex, bool aValueOnly,
bool aGetValue, nsAString & _retval);
protected:
/**
* Gets and validates the defaultComplete result and the relative
* defaultIndex value.
*
* @param aResultIndex
* Index of the defaultComplete result to be used. Pass -1 to search
* for the first result providing a valid defaultIndex.
* @param _result
* The found result.
* @param _defaultIndex
* The defaultIndex relative to _result.
*/
nsresult GetDefaultCompleteResult(PRInt32 aResultIndex,
nsIAutoCompleteResult** _result,
PRInt32* _defaultIndex);
/**
* Gets the defaultComplete value to be suggested to the user.
*
* @param aResultIndex
* Index of the defaultComplete result to be used.
* @param aPreserveCasing
* Whether user casing should be preserved.
* @param _retval
* The value to be completed.
*/
nsresult GetDefaultCompleteValue(PRInt32 aResultIndex, bool aPreserveCasing,
nsAString &_retval);
/**
* Gets the defaultComplete value to be used when the user navigates or
* confirms the current match.
* The value is returned only if it case-insensitively matches the current
* input text, otherwise the method returns NS_ERROR_FAILURE.
* This happens because we don't want to override user casing in case of a
* navigation key (unless the text is the same), or to replace text if the
* user backspaces just before Enter.
*
* @param _retval
* The value to be completed.
*/
nsresult GetFinalDefaultCompleteValue(nsAString &_retval);
nsresult ClearResults();
nsresult RowIndexToSearch(PRInt32 aRowIndex,

View File

@ -718,7 +718,12 @@ Database::InitSchema(bool* aDatabaseMigrated)
NS_ENSURE_SUCCESS(rv, rv);
}
// Firefox 14 uses schema version 20.
if (currentSchemaVersion < 21) {
rv = MigrateV21Up();
NS_ENSURE_SUCCESS(rv, rv);
}
// Firefox 14 uses schema version 21.
// Schema Upgrades must add migration code here.
@ -1839,6 +1844,39 @@ Database::MigrateV20Up()
return NS_OK;
}
nsresult
Database::MigrateV21Up()
{
MOZ_ASSERT(NS_IsMainThread());
// Add a prefix column to moz_hosts.
nsCOMPtr<mozIStorageStatement> stmt;
nsresult rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT prefix FROM moz_hosts"
), getter_AddRefs(stmt));
if (NS_FAILED(rv)) {
rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
"ALTER TABLE moz_hosts ADD COLUMN prefix"
));
NS_ENSURE_SUCCESS(rv, rv);
}
// Update prefixes.
nsCOMPtr<mozIStorageAsyncStatement> updatePrefixesStmt;
rv = mMainConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
"UPDATE moz_hosts SET prefix = ( "
HOSTS_PREFIX_PRIORITY_FRAGMENT
") "
), getter_AddRefs(updatePrefixesStmt));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<mozIStoragePendingStatement> ps;
rv = updatePrefixesStmt->ExecuteAsync(nsnull, getter_AddRefs(ps));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
void
Database::Shutdown()
{

Some files were not shown because too many files have changed in this diff Show More