Bug 611789 - Web Console cleanup: Remove the window registry; f=rcampbell r=sdwilsh a=blocking2.0

This commit is contained in:
Mihai Sucan 2010-12-23 13:07:03 -04:00
parent f22fbb6193
commit b409cdbd95
4 changed files with 84 additions and 280 deletions

View File

@ -1170,24 +1170,9 @@ HUD_SERVICE.prototype =
activatedContexts: [],
/**
* Registry of HeadsUpDisplay DOM node ids
* Collection of outer window IDs mapping to HUD IDs.
*/
_headsUpDisplays: {},
/**
* Mapping of HUDIds to URIspecs
*/
displayRegistry: {},
/**
* Mapping of HUDIds to contentWindows.
*/
windowRegistry: {},
/**
* Mapping of URISpecs to HUDIds
*/
uriRegistry: {},
windowIds: {},
/**
* The sequencer is a generator (after initialization) that returns unique
@ -1220,9 +1205,21 @@ HUD_SERVICE.prototype =
*/
getWindowByWindowId: function HS_getWindowByWindowId(aId)
{
// In the future (post-Electrolysis), getOuterWindowWithId() could
// return null, because the originating window could have gone away
// while we were in the process of receiving and/or processing a
// message. For future-proofing purposes, we do a null check here.
let someWindow = Services.wm.getMostRecentWindow(null);
let windowUtils = someWindow.getInterface(Ci.nsIDOMWindowUtils);
return windowUtils.getOuterWindowWithId(aId);
let content = null;
if (someWindow) {
let windowUtils = someWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
content = windowUtils.getOuterWindowWithId(aId);
}
return content;
},
/**
@ -1295,13 +1292,14 @@ HUD_SERVICE.prototype =
{
this.wakeup();
var window = aContext.linkedBrowser.contentWindow;
var id = aContext.linkedBrowser.parentNode.parentNode.getAttribute("id");
this.registerActiveContext(id);
let window = aContext.linkedBrowser.contentWindow;
let nBox = aContext.ownerDocument.defaultView.
getNotificationBox(window);
this.registerActiveContext(nBox.id);
this.windowInitializer(window);
if (!aAnimated) {
this.disableAnimation("hud_" + id);
this.disableAnimation("hud_" + nBox.id);
}
},
@ -1320,12 +1318,11 @@ HUD_SERVICE.prototype =
let hudId = "hud_" + nBox.id;
let displayNode = nBox.querySelector("#" + hudId);
if (hudId in this.displayRegistry && displayNode) {
if (hudId in this.hudReferences && displayNode) {
if (!aAnimated) {
this.storeHeight(hudId);
}
this.unregisterActiveContext(hudId);
this.unregisterDisplay(displayNode);
window.focus();
}
@ -1582,66 +1579,20 @@ HUD_SERVICE.prototype =
this.hudReferences[aHUD.hudId] = aHUD;
},
/**
* Deletes a HeadsUpDisplay object from memory
*
* @param string aHUDId
* @returns void
*/
deleteHeadsUpDisplay: function HS_deleteHeadsUpDisplay(aHUDId)
{
delete this.hudReferences[aHUDId];
},
/**
* Register a new Heads Up Display
*
* @param nsIDOMWindow aContentWindow
* @returns void
*/
registerDisplay: function HS_registerDisplay(aHUDId, aContentWindow)
registerDisplay: function HS_registerDisplay(aHUDId)
{
// register a display DOM node Id and HUD uriSpec with the service
if (!aHUDId || !aContentWindow){
// register a display DOM node Id with the service.
if (!aHUDId){
throw new Error(ERRORS.MISSING_ARGS);
}
var URISpec = aContentWindow.document.location.href;
this.filterPrefs[aHUDId] = this.defaultFilterPrefs;
this.displayRegistry[aHUDId] = URISpec;
this._headsUpDisplays[aHUDId] = { id: aHUDId };
this.registerActiveContext(aHUDId);
// init storage objects:
this.storage.createDisplay(aHUDId);
var huds = this.uriRegistry[URISpec];
var foundHUDId = false;
if (huds) {
var len = huds.length;
for (var i = 0; i < len; i++) {
if (huds[i] == aHUDId) {
foundHUDId = true;
break;
}
}
if (!foundHUDId) {
this.uriRegistry[URISpec].push(aHUDId);
}
}
else {
this.uriRegistry[URISpec] = [aHUDId];
}
var windows = this.windowRegistry[aHUDId];
if (!windows) {
this.windowRegistry[aHUDId] = [aContentWindow];
}
else {
windows.push(aContentWindow);
}
},
/**
@ -1662,7 +1613,7 @@ HUD_SERVICE.prototype =
var id, outputNode;
if (typeof(aHUD) === "string") {
id = aHUD;
outputNode = this.mixins.getOutputNodeById(aHUD);
outputNode = this.getHeadsUpDisplay(aHUD);
}
else {
id = aHUD.getAttribute("id");
@ -1683,28 +1634,20 @@ HUD_SERVICE.prototype =
// remove the DOM Nodes
parent.removeChild(outputNode);
// remove our record of the DOM Nodes from the registry
delete this._headsUpDisplays[id];
// remove the HeadsUpDisplay object from memory
this.deleteHeadsUpDisplay(id);
delete this.hudReferences[id];
// remove the related storage object
this.storage.removeDisplay(id);
// remove the related window objects
delete this.windowRegistry[id];
let displays = this.displays();
var uri = this.displayRegistry[id];
if (this.uriRegistry[uri]) {
this.uriRegistry[uri] = this.uriRegistry[uri].filter(function(e) e != id);
for (let windowID in this.windowIds) {
if (this.windowIds[windowID] == id) {
delete this.windowIds[windowID];
}
}
delete displays[id];
delete this.displayRegistry[id];
delete this.uriRegistry[uri];
this.unregisterActiveContext(id);
if (Object.keys(this._headsUpDisplays).length == 0) {
if (Object.keys(this.hudReferences).length == 0) {
this.suspend();
}
},
@ -1717,7 +1660,7 @@ HUD_SERVICE.prototype =
*/
wakeup: function HS_wakeup()
{
if (Object.keys(this._headsUpDisplays).length > 0) {
if (Object.keys(this.hudReferences).length > 0) {
return;
}
@ -1761,8 +1704,8 @@ HUD_SERVICE.prototype =
*/
shutdown: function HS_shutdown()
{
for (var displayId in this._headsUpDisplays) {
this.unregisterDisplay(displayId);
for (let hudId in this.hudReferences) {
this.unregisterDisplay(hudId);
}
},
@ -1775,84 +1718,52 @@ HUD_SERVICE.prototype =
*/
getHudIdByWindow: function HS_getHudIdByWindow(aContentWindow)
{
// Fast path: check the cached window registry.
for (let hudId in this.windowRegistry) {
if (this.windowRegistry[hudId] &&
this.windowRegistry[hudId].indexOf(aContentWindow) != -1) {
return hudId;
}
}
// As a fallback, do a little pointer chasing to try to find the Web
// Console. This fallback approach occurs when opening the Console on a
// page with subframes.
let [ , tabBrowser, browser ] = ConsoleUtils.getParents(aContentWindow);
if (!tabBrowser) {
return null;
}
let notificationBox = tabBrowser.getNotificationBox(browser);
let hudBox = notificationBox.querySelector(".hud-box");
if (!hudBox) {
return null;
}
// Cache it!
let hudId = hudBox.id;
this.windowRegistry[hudId].push(aContentWindow);
let uri = aContentWindow.document.location.href;
if (!this.uriRegistry[uri]) {
this.uriRegistry[uri] = [ hudId ];
} else {
this.uriRegistry[uri].push(hudId);
}
return hudId;
let windowId = this.getWindowId(aContentWindow);
return this.getHudIdByWindowId(windowId);
},
/**
* Gets HUD DOM Node
* Gets the Web Console DOM node, the .hud-box.
*
* @param string id
* The Heads Up Display DOM Id
* @returns nsIDOMNode
*/
getHeadsUpDisplay: function HS_getHeadsUpDisplay(aId)
{
return this.mixins.getOutputNodeById(aId);
return aId in this.hudReferences ? this.hudReferences[aId].HUDBox : null;
},
/**
* gets the nsIDOMNode outputNode by ID via the gecko app mixins
* Gets the Web Console DOM node, the .hud-box.
*
* @param string aId
* @returns nsIDOMNode
*/
getOutputNodeById: function HS_getOutputNodeById(aId)
{
return this.mixins.getOutputNodeById(aId);
return this.getHeadsUpDisplay(aId);
},
/**
* Gets an object that contains active DOM Node Ids for all Heads Up Displays
*
* @returns object
*/
displays: function HS_displays() {
return this._headsUpDisplays;
},
/**
* Gets an array that contains active DOM Node Ids for all HUDs
* Gets an array that contains all the HUD IDs.
* @returns array
*/
displaysIndex: function HS_displaysIndex()
{
var props = [];
for (var prop in this._headsUpDisplays) {
props.push(prop);
}
return props;
return Object.keys(this.hudReferences);
},
/**
* Returns the hudId that is corresponding to the given outer window ID.
*
* @param number aWindowId
* the outer window ID
* @returns string the hudId
*/
getHudIdByWindowId: function HS_getHudIdByWindowId(aWindowId)
{
return this.windowIds[aWindowId];
},
/**
@ -1965,21 +1876,22 @@ HUD_SERVICE.prototype =
severity = SEVERITY_WARNING;
}
// Sends the error to all applicable Web Consoles.
let hudIds = ConsoleUtils.getHUDIdsForScriptError(aScriptError);
for (let i = 0; i < hudIds.length; i++) {
let hudId = hudIds[i];
let outputNode = this.hudReferences[hudId].outputNode;
let chromeDocument = outputNode.ownerDocument;
let window = HUDService.getWindowByWindowId(aScriptError.outerWindowID);
if (window) {
let hudId = HUDService.getHudIdByWindow(window.top);
if (hudId) {
let outputNode = this.hudReferences[hudId].outputNode;
let chromeDocument = outputNode.ownerDocument;
let node = ConsoleUtils.createMessageNode(chromeDocument,
aCategory,
severity,
aScriptError.errorMessage,
aScriptError.sourceName,
aScriptError.lineNumber);
let node = ConsoleUtils.createMessageNode(chromeDocument,
aCategory,
severity,
aScriptError.errorMessage,
aScriptError.sourceName,
aScriptError.lineNumber);
ConsoleUtils.outputMessageNode(node, hudId);
ConsoleUtils.outputMessageNode(node, hudId);
}
}
},
@ -2096,7 +2008,7 @@ HUD_SERVICE.prototype =
}
// Try to get the hudId that is associated to the window.
hudId = self.getHudIdByWindow(win);
hudId = self.getHudIdByWindow(win.top);
if (!hudId) {
return;
}
@ -2561,7 +2473,7 @@ HUD_SERVICE.prototype =
return;
}
this.registerDisplay(hudId, aContentWindow);
this.registerDisplay(hudId);
let hudNode;
let childNodes = nBox.childNodes;
@ -2586,6 +2498,8 @@ HUD_SERVICE.prototype =
hud = new HeadsUpDisplay(config);
HUDService.registerHUDReference(hud);
let windowId = this.getWindowId(aContentWindow.top);
this.windowIds[windowId] = hudId;
}
else {
hud = this.hudReferences[hudId];
@ -4678,42 +4592,6 @@ function FirefoxApplicationHooks()
{ }
FirefoxApplicationHooks.prototype = {
/**
* Firefox-specific method for getting an array of chrome Window objects
*/
get chromeWindows()
{
var windows = [];
var enumerator = Services.ww.getWindowEnumerator(null);
while (enumerator.hasMoreElements()) {
windows.push(enumerator.getNext());
}
return windows;
},
/**
* Firefox-specific method for getting the DOM node (per tab) that message
* nodes are appended to.
* @param aId
* The DOM node's id.
*/
getOutputNodeById: function FAH_getOutputNodeById(aId)
{
if (!aId) {
throw new Error("FAH_getOutputNodeById: id is null!!");
}
var enumerator = Services.ww.getWindowEnumerator(null);
while (enumerator.hasMoreElements()) {
let window = enumerator.getNext();
let node = window.document.getElementById(aId);
if (node) {
return node;
}
}
throw new Error("Cannot get outputNode by id");
},
/**
* gets the current contentWindow (Firefox-specific)
*
@ -4722,7 +4600,7 @@ FirefoxApplicationHooks.prototype = {
getCurrentContext: function FAH_getCurrentContext()
{
return Services.wm.getMostRecentWindow("navigator:browser");
}
},
};
//////////////////////////////////////////////////////////////////////////////
@ -5052,79 +4930,6 @@ ConsoleUtils = {
}
return aSourceURL;
},
/**
* Given an instance of nsIScriptError, attempts to work out the IDs of HUDs
* to which the script should be sent.
*
* @param nsIScriptError aScriptError
* The script error that was received.
* @returns Array<string>
*/
getHUDIdsForScriptError:
function ConsoleUtils_getHUDIdsForScriptError(aScriptError) {
if (aScriptError instanceof Ci.nsIScriptError2) {
let windowID = aScriptError.outerWindowID;
if (windowID) {
// We just need some arbitrary window here so that we can GI to
// nsIDOMWindowUtils...
let someWindow = Services.wm.getMostRecentWindow(null);
if (someWindow) {
let windowUtils = someWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
// In the future (post-Electrolysis), getOuterWindowWithId() could
// return null, because the originating window could have gone away
// while we were in the process of receiving and/or processing a
// message. For future-proofing purposes, we do a null check here.
let content = windowUtils.getOuterWindowWithId(windowID);
if (content) {
let hudId = HUDService.getHudIdByWindow(content);
if (hudId) {
return [ hudId ];
}
}
}
}
}
// The error had no window ID. As a less precise fallback, see whether we
// can find some consoles to send to via the URI.
let hudIds = HUDService.uriRegistry[aScriptError.sourceName];
return hudIds ? hudIds : [];
},
/**
* Returns the chrome window, the tab browser, and the browser that
* contain the given content window.
*
* NB: This function only works in Firefox.
*
* @param nsIDOMWindow aContentWindow
* The content window to query. If this parameter is not a content
* window, then [ null, null, null ] will be returned.
*/
getParents: function ConsoleUtils_getParents(aContentWindow) {
let chromeEventHandler =
aContentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler;
if (!chromeEventHandler) {
return [ null, null, null ];
}
let chromeWindow = chromeEventHandler.ownerDocument.defaultView;
let gBrowser = XPCNativeWrapper.unwrap(chromeWindow).gBrowser;
let documentElement = chromeWindow.document.documentElement;
if (!documentElement || !gBrowser ||
documentElement.getAttribute("windowtype") !== "navigator:browser") {
// Not a browser window.
return [ chromeWindow, null, null ];
}
return [ chromeWindow, gBrowser, chromeEventHandler ];
}
};
@ -5692,8 +5497,11 @@ HUDConsoleObserver = {
return;
}
if (!(aSubject instanceof Ci.nsIScriptError))
if (!(aSubject instanceof Ci.nsIScriptError) ||
!(aSubject instanceof Ci.nsIScriptError2) ||
!aSubject.outerWindowID) {
return;
}
switch (aSubject.category) {
// We ignore chrome-originating errors as we only

View File

@ -35,7 +35,7 @@ function testCloseButton() {
EventUtils.synthesizeMouse(closeButton, 0, 0, {});
executeSoon(function (){
ok(!(hudId in HUDService.windowRegistry), "the console is closed when " +
ok(!(hudId in HUDService.hudReferences), "the console is closed when " +
"the close button is pressed");
closeButton = null;
finishTest();

View File

@ -53,8 +53,6 @@ function testDisplayAccessors() {
openConsole();
var allHuds = HUDService.displays();
ok(typeof allHuds == "object", "allHuds is an object");
var idx = HUDService.displaysIndex();
let hudId = idx[0];

View File

@ -57,12 +57,10 @@ function testRegistries() {
ok(displaysIdx.length == 1, "one display id found");
var display = displaysIdx[0];
var registry = HUDService.displayRegistry;
var uri = registry[display];
ok(registry[display], "we have a URI: " + registry[display]);
ok(HUDService.hudReferences[display], "we have a HUD");
var uriRegistry = HUDService.uriRegistry;
ok(uriRegistry[uri].length == 1, "uri registry is working");
let windowID = HUDService.getWindowId(content);
is(HUDService.windowIds[windowID], display, "windowIds is working");
finishTest();
}