зеркало из https://github.com/mozilla/gecko-dev.git
Bug 672470 - Fix memory leaks in Web Console code; r=rcampbell,gavin.sharp
This commit is contained in:
Родитель
1b9d0af5d1
Коммит
42502a15ad
|
@ -466,7 +466,6 @@ ResponseListener.prototype =
|
|||
}
|
||||
});
|
||||
this.httpActivity.response.isDone = true;
|
||||
this.httpActivity.response.listener = null;
|
||||
this.httpActivity = null;
|
||||
this.receivedData = "";
|
||||
this.request = null;
|
||||
|
@ -1278,6 +1277,37 @@ function HUD_SERVICE()
|
|||
// bytes).
|
||||
this.responsePipeSegmentSize =
|
||||
Services.prefs.getIntPref("network.buffer.cache.size");
|
||||
|
||||
/**
|
||||
* Collection of HUDIds that map to the tabs/windows/contexts
|
||||
* that a HeadsUpDisplay can be activated for.
|
||||
*/
|
||||
this.activatedContexts = [];
|
||||
|
||||
/**
|
||||
* Collection of outer window IDs mapping to HUD IDs.
|
||||
*/
|
||||
this.windowIds = {};
|
||||
|
||||
/**
|
||||
* Each HeadsUpDisplay has a set of filter preferences
|
||||
*/
|
||||
this.filterPrefs = {};
|
||||
|
||||
/**
|
||||
* Keeps a reference for each HeadsUpDisplay that is created
|
||||
*/
|
||||
this.hudReferences = {};
|
||||
|
||||
/**
|
||||
* Requests that haven't finished yet.
|
||||
*/
|
||||
this.openRequests = {};
|
||||
|
||||
/**
|
||||
* Response headers for requests that haven't finished yet.
|
||||
*/
|
||||
this.openResponseHeaders = {};
|
||||
};
|
||||
|
||||
HUD_SERVICE.prototype =
|
||||
|
@ -1313,28 +1343,12 @@ HUD_SERVICE.prototype =
|
|||
return HeadsUpDisplayUICommands;
|
||||
},
|
||||
|
||||
/**
|
||||
* Collection of HUDIds that map to the tabs/windows/contexts
|
||||
* that a HeadsUpDisplay can be activated for.
|
||||
*/
|
||||
activatedContexts: [],
|
||||
|
||||
/**
|
||||
* Collection of outer window IDs mapping to HUD IDs.
|
||||
*/
|
||||
windowIds: {},
|
||||
|
||||
/**
|
||||
* The sequencer is a generator (after initialization) that returns unique
|
||||
* integers
|
||||
*/
|
||||
sequencer: null,
|
||||
|
||||
/**
|
||||
* Each HeadsUpDisplay has a set of filter preferences
|
||||
*/
|
||||
filterPrefs: {},
|
||||
|
||||
/**
|
||||
* Gets the ID of the outer window of this DOM window
|
||||
*
|
||||
|
@ -1681,11 +1695,6 @@ HUD_SERVICE.prototype =
|
|||
this.regroupOutput(outputNode);
|
||||
},
|
||||
|
||||
/**
|
||||
* Keeps a reference for each HeadsUpDisplay that is created
|
||||
*/
|
||||
hudReferences: {},
|
||||
|
||||
/**
|
||||
* Register a reference of each HeadsUpDisplay that is created
|
||||
*/
|
||||
|
@ -1730,6 +1739,8 @@ HUD_SERVICE.prototype =
|
|||
// remove the nodes then.
|
||||
hud.jsterm.clearOutput();
|
||||
|
||||
hud.destroy();
|
||||
|
||||
// Make sure that the console panel does not try to call
|
||||
// deactivateHUDForContext() again.
|
||||
hud.consoleWindowUnregisterOnHide = false;
|
||||
|
@ -1826,6 +1837,8 @@ HUD_SERVICE.prototype =
|
|||
delete this.defaultFilterPrefs;
|
||||
delete this.defaultGlobalConsolePrefs;
|
||||
|
||||
delete this.lastFinishedRequestCallback;
|
||||
|
||||
HUDWindowObserver.uninit();
|
||||
HUDConsoleObserver.uninit();
|
||||
ConsoleAPIObserver.shutdown();
|
||||
|
@ -2124,16 +2137,6 @@ HUD_SERVICE.prototype =
|
|||
*/
|
||||
applicationHooks: null,
|
||||
|
||||
/**
|
||||
* Requests that haven't finished yet.
|
||||
*/
|
||||
openRequests: {},
|
||||
|
||||
/**
|
||||
* Response headers for requests that haven't finished yet.
|
||||
*/
|
||||
openResponseHeaders: {},
|
||||
|
||||
/**
|
||||
* Assign a function to this property to listen for finished httpRequests.
|
||||
* Used by unit tests.
|
||||
|
@ -2239,15 +2242,8 @@ HUD_SERVICE.prototype =
|
|||
return;
|
||||
}
|
||||
|
||||
// Add listener for the response body.
|
||||
let newListener = new ResponseListener(httpActivity);
|
||||
aChannel.QueryInterface(Ci.nsITraceableChannel);
|
||||
|
||||
httpActivity.response.listener = newListener;
|
||||
|
||||
let tee = Cc["@mozilla.org/network/stream-listener-tee;1"].
|
||||
createInstance(Ci.nsIStreamListenerTee);
|
||||
|
||||
// The response will be written into the outputStream of this pipe.
|
||||
// This allows us to buffer the data we are receiving and read it
|
||||
// asynchronously.
|
||||
|
@ -2259,11 +2255,17 @@ HUD_SERVICE.prototype =
|
|||
sink.init(false, false, HUDService.responsePipeSegmentSize,
|
||||
PR_UINT32_MAX, null);
|
||||
|
||||
// Add listener for the response body.
|
||||
let newListener = new ResponseListener(httpActivity);
|
||||
|
||||
// Remember the input stream, so it isn't released by GC.
|
||||
newListener.inputStream = sink.inputStream;
|
||||
newListener.sink = sink;
|
||||
|
||||
let tee = Cc["@mozilla.org/network/stream-listener-tee;1"].
|
||||
createInstance(Ci.nsIStreamListenerTee);
|
||||
|
||||
let originalListener = aChannel.setNewListener(tee);
|
||||
newListener.sink = sink;
|
||||
|
||||
tee.init(originalListener, sink.outputStream, newListener);
|
||||
|
||||
|
@ -2307,7 +2309,7 @@ HUD_SERVICE.prototype =
|
|||
// Iterate over all currently ongoing requests. If aChannel can't
|
||||
// be found within them, then exit this function.
|
||||
let httpActivity = null;
|
||||
for each (var item in self.openRequests) {
|
||||
for each (let item in self.openRequests) {
|
||||
if (item.channel !== aChannel) {
|
||||
continue;
|
||||
}
|
||||
|
@ -2420,7 +2422,8 @@ HUD_SERVICE.prototype =
|
|||
msgObject.messageNode.clipboardText =
|
||||
clipboardTextPieces.join(" ");
|
||||
|
||||
delete self.openRequests[item.id];
|
||||
delete httpActivity.messageObject;
|
||||
delete self.openRequests[httpActivity.id];
|
||||
updatePanel = true;
|
||||
break;
|
||||
}
|
||||
|
@ -2657,14 +2660,25 @@ HUD_SERVICE.prototype =
|
|||
*/
|
||||
onWindowUnload: function HS_onWindowUnload(aEvent)
|
||||
{
|
||||
let gBrowser = aEvent.target.defaultView.gBrowser;
|
||||
let window = aEvent.target.defaultView;
|
||||
|
||||
window.removeEventListener("unload", this.onWindowUnload, false);
|
||||
|
||||
let gBrowser = window.gBrowser;
|
||||
let tabContainer = gBrowser.tabContainer;
|
||||
|
||||
tabContainer.removeEventListener("TabClose", this.onTabClose, false);
|
||||
|
||||
let tab = tabContainer.firstChild;
|
||||
while (tab != null) {
|
||||
this.deactivateHUDForContext(tab, false);
|
||||
tab = tab.nextSibling;
|
||||
}
|
||||
|
||||
if (window.webConsoleCommandController) {
|
||||
window.controllers.removeController(window.webConsoleCommandController);
|
||||
window.webConsoleCommandController = null;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -2690,13 +2704,8 @@ HUD_SERVICE.prototype =
|
|||
return;
|
||||
}
|
||||
|
||||
xulWindow.addEventListener("unload", this.onWindowUnload, false);
|
||||
|
||||
let gBrowser = xulWindow.gBrowser;
|
||||
|
||||
let container = gBrowser.tabContainer;
|
||||
container.addEventListener("TabClose", this.onTabClose, false);
|
||||
|
||||
let _browser = gBrowser.
|
||||
getBrowserForDocument(aContentWindow.top.document);
|
||||
let nBox = gBrowser.getNotificationBox(_browser);
|
||||
|
@ -2716,6 +2725,9 @@ HUD_SERVICE.prototype =
|
|||
return;
|
||||
}
|
||||
|
||||
xulWindow.addEventListener("unload", this.onWindowUnload, false);
|
||||
gBrowser.tabContainer.addEventListener("TabClose", this.onTabClose, false);
|
||||
|
||||
this.registerDisplay(hudId);
|
||||
|
||||
let hudNode;
|
||||
|
@ -2775,9 +2787,10 @@ HUD_SERVICE.prototype =
|
|||
*/
|
||||
createController: function HUD_createController(aWindow)
|
||||
{
|
||||
if (aWindow.commandController == null) {
|
||||
aWindow.commandController = new CommandController(aWindow);
|
||||
aWindow.controllers.insertControllerAt(0, aWindow.commandController);
|
||||
if (aWindow.webConsoleCommandController == null) {
|
||||
aWindow.webConsoleCommandController = new CommandController(aWindow);
|
||||
aWindow.controllers.insertControllerAt(0,
|
||||
aWindow.webConsoleCommandController);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -3611,7 +3624,16 @@ HeadsUpDisplay.prototype = {
|
|||
*/
|
||||
createPositionUI: function HUD_createPositionUI()
|
||||
{
|
||||
let self = this;
|
||||
this._positionConsoleAbove = (function HUD_positionAbove() {
|
||||
this.positionConsole("above");
|
||||
}).bind(this);
|
||||
|
||||
this._positionConsoleBelow = (function HUD_positionBelow() {
|
||||
this.positionConsole("below");
|
||||
}).bind(this);
|
||||
this._positionConsoleWindow = (function HUD_positionWindow() {
|
||||
this.positionConsole("window");
|
||||
}).bind(this);
|
||||
|
||||
let button = this.makeXULNode("toolbarbutton");
|
||||
button.setAttribute("type", "menu");
|
||||
|
@ -3625,27 +3647,21 @@ HeadsUpDisplay.prototype = {
|
|||
itemAbove.setAttribute("label", this.getStr("webConsolePositionAbove"));
|
||||
itemAbove.setAttribute("type", "checkbox");
|
||||
itemAbove.setAttribute("autocheck", "false");
|
||||
itemAbove.addEventListener("command", function() {
|
||||
self.positionConsole("above");
|
||||
}, false);
|
||||
itemAbove.addEventListener("command", this._positionConsoleAbove, false);
|
||||
menuPopup.appendChild(itemAbove);
|
||||
|
||||
let itemBelow = this.makeXULNode("menuitem");
|
||||
itemBelow.setAttribute("label", this.getStr("webConsolePositionBelow"));
|
||||
itemBelow.setAttribute("type", "checkbox");
|
||||
itemBelow.setAttribute("autocheck", "false");
|
||||
itemBelow.addEventListener("command", function() {
|
||||
self.positionConsole("below");
|
||||
}, false);
|
||||
itemBelow.addEventListener("command", this._positionConsoleBelow, false);
|
||||
menuPopup.appendChild(itemBelow);
|
||||
|
||||
let itemWindow = this.makeXULNode("menuitem");
|
||||
itemWindow.setAttribute("label", this.getStr("webConsolePositionWindow"));
|
||||
itemWindow.setAttribute("type", "checkbox");
|
||||
itemWindow.setAttribute("autocheck", "false");
|
||||
itemWindow.addEventListener("command", function() {
|
||||
self.positionConsole("window");
|
||||
}, false);
|
||||
itemWindow.addEventListener("command", this._positionConsoleWindow, false);
|
||||
menuPopup.appendChild(itemWindow);
|
||||
|
||||
this.positionMenuitems = {
|
||||
|
@ -3771,16 +3787,17 @@ HeadsUpDisplay.prototype = {
|
|||
*/
|
||||
makeCloseButton: function HUD_makeCloseButton(aToolbar)
|
||||
{
|
||||
let onCommand = (function HUD_closeButton_onCommand() {
|
||||
this.closeButtonOnCommand = (function HUD_closeButton_onCommand() {
|
||||
HUDService.animate(this.hudId, ANIMATE_OUT, (function() {
|
||||
HUDService.deactivateHUDForContext(this.tab, true);
|
||||
}).bind(this));
|
||||
}).bind(this);
|
||||
|
||||
let closeButton = this.makeXULNode("toolbarbutton");
|
||||
closeButton.classList.add("webconsole-close-button");
|
||||
closeButton.addEventListener("command", onCommand, false);
|
||||
aToolbar.appendChild(closeButton);
|
||||
this.closeButton = this.makeXULNode("toolbarbutton");
|
||||
this.closeButton.classList.add("webconsole-close-button");
|
||||
this.closeButton.addEventListener("command",
|
||||
this.closeButtonOnCommand, false);
|
||||
aToolbar.appendChild(this.closeButton);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -3859,7 +3876,26 @@ HeadsUpDisplay.prototype = {
|
|||
HUD_BOX_DOES_NOT_EXIST: "Heads Up Display does not exist",
|
||||
TAB_ID_REQUIRED: "Tab DOM ID is required",
|
||||
PARENTNODE_NOT_FOUND: "parentNode element not found"
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroy the HUD object. Call this method to avoid memory leaks when the Web
|
||||
* Console is closed.
|
||||
*/
|
||||
destroy: function HUD_destroy()
|
||||
{
|
||||
this.jsterm.destroy();
|
||||
|
||||
this.positionMenuitems.above.removeEventListener("command",
|
||||
this._positionConsoleAbove, false);
|
||||
this.positionMenuitems.below.removeEventListener("command",
|
||||
this._positionConsoleBelow, false);
|
||||
this.positionMenuitems.window.removeEventListener("command",
|
||||
this._positionConsoleWindow, false);
|
||||
|
||||
this.closeButton.removeEventListener("command",
|
||||
this.closeButtonOnCommand, false);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
@ -4459,12 +4495,15 @@ JSTerm.prototype = {
|
|||
this.outputNode = this.mixins.outputNode;
|
||||
this.completeNode = this.mixins.completeNode;
|
||||
|
||||
this._keyPress = this.keyPress.bind(this);
|
||||
this._inputEventHandler = this.inputEventHandler.bind(this);
|
||||
|
||||
this.inputNode.addEventListener("keypress",
|
||||
this.keyPress.bind(this), false);
|
||||
this._keyPress, false);
|
||||
this.inputNode.addEventListener("input",
|
||||
this.inputEventHandler.bind(this), false);
|
||||
this._inputEventHandler, false);
|
||||
this.inputNode.addEventListener("keyup",
|
||||
this.inputEventHandler.bind(this), false);
|
||||
this._inputEventHandler, false);
|
||||
},
|
||||
|
||||
get codeInputString()
|
||||
|
@ -5245,6 +5284,16 @@ JSTerm.prototype = {
|
|||
let prefix = aSuffix ? this.inputNode.value.replace(/[\S]/g, " ") : "";
|
||||
this.completeNode.value = prefix + aSuffix;
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroy the JSTerm object. Call this method to avoid memory leaks.
|
||||
*/
|
||||
destroy: function JST_destroy()
|
||||
{
|
||||
this.inputNode.removeEventListener("keypress", this._keyPress, false);
|
||||
this.inputNode.removeEventListener("input", this._inputEventHandler, false);
|
||||
this.inputNode.removeEventListener("keyup", this._inputEventHandler, false);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -6399,8 +6448,7 @@ CommandController.prototype = {
|
|||
|
||||
supportsCommand: function CommandController_supportsCommand(aCommand)
|
||||
{
|
||||
return this.isCommandEnabled(aCommand) &&
|
||||
this._getFocusedOutputNode() != null;
|
||||
return this.isCommandEnabled(aCommand);
|
||||
},
|
||||
|
||||
isCommandEnabled: function CommandController_isCommandEnabled(aCommand)
|
||||
|
|
|
@ -36,7 +36,7 @@ function testSelectionWhenMovingBetweenBoxes() {
|
|||
|
||||
// Test that the global Firefox "Select All" functionality (e.g. Edit >
|
||||
// Select All) works properly in the Web Console.
|
||||
let commandController = window.commandController;
|
||||
let commandController = window.webConsoleCommandController;
|
||||
ok(commandController != null, "the window has a command controller object");
|
||||
|
||||
commandController.selectAll(outputNode);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
let itemsSet;
|
||||
let itemsSet, HUD;
|
||||
|
||||
function test() {
|
||||
addTab("data:text/html,Web Console test for bug 626484");
|
||||
|
@ -30,6 +30,7 @@ function nextTest() {
|
|||
if (itemsSet.length === 0) {
|
||||
outputNode.clearSelection();
|
||||
HUD.jsterm.clearOutput();
|
||||
HUD = null;
|
||||
finish();
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -57,8 +57,6 @@ function pprint(aObj)
|
|||
|
||||
let tab, browser, hudId, hud, hudBox, filterBox, outputNode, cs;
|
||||
|
||||
let win = gBrowser.selectedBrowser;
|
||||
|
||||
function addTab(aURL)
|
||||
{
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
|
@ -185,6 +183,3 @@ registerCleanupFunction(tearDown);
|
|||
|
||||
waitForExplicitFinish();
|
||||
|
||||
// removed tests:
|
||||
// browser_webconsole_bug_580030_errors_after_page_reload.js \
|
||||
// browser_webconsole_bug_595350_multiple_windows_and_tabs.js \
|
||||
|
|
Загрузка…
Ссылка в новой задаче