Bug 899354 - Only ever add one visibilitychange listener to BrowserElementParent's owner window. r=khuey

This prevents a leak when we run tests that create thousands of BrowserElementParents without ever turning the screen off.
This commit is contained in:
Justin Lebar 2013-07-31 14:14:12 -07:00
Родитель 429cdd568c
Коммит 2847abff91
1 изменённых файлов: 34 добавлений и 15 удалений

Просмотреть файл

@ -67,13 +67,22 @@ function defineAndExpose(obj, name, value) {
obj.__exposedProps__[name] = 'r';
}
function visibilityChangeHandler(weakBEP, win) {
let bep = weakBEP.get();
if (bep) {
bep._ownerVisibilityChange();
} else {
win.removeEventListener('visibilitychange', visibilityChangeHandler,
/* useCapture */ false);
function visibilityChangeHandler(e) {
// The visibilitychange event's target is the document.
let win = e.target.defaultView;
if (!win._browserElementParents) {
return;
}
let beps = Cu.nondeterministicGetWeakMapKeys(win._browserElementParents);
if (beps.length == 0) {
win.removeEventListener('visibilitychange', visibilityChangeHandler);
return;
}
for (let i = 0; i < beps.length; i++) {
beps[i]._ownerVisibilityChange();
}
}
@ -178,15 +187,25 @@ function BrowserElementParent(frameLoader, hasRemoteFrame) {
defineDOMRequestMethod('getCanGoBack', 'get-can-go-back');
defineDOMRequestMethod('getCanGoForward', 'get-can-go-forward');
// Listen to visibilitychange on the iframe's owner window, and forward it
// down to the child. The event listener must hold a weak reference to this,
// otherwise the window will hold this object alive.
// Listen to visibilitychange on the iframe's owner window, and forward
// changes down to the child. We want to do this while registering as few
// visibilitychange listeners on _window as possible, because such a listener
// may live longer than this BrowserElementParent object.
//
// To accomplish this, we register just one listener on the window, and have
// it reference a WeakMap whose keys are all the BrowserElementParent objects
// on the window. Then when the listener fires, we iterate over the
// WeakMap's keys (which we can do, because we're chrome) to notify the
// BrowserElementParents.
if (!this._window._browserElementParents) {
this._window._browserElementParents = new WeakMap();
this._window.addEventListener('visibilitychange',
visibilityChangeHandler,
/* useCapture = */ false,
/* wantsUntrusted = */ false);
}
var weakSelf = Cu.getWeakReference(this);
this._window.addEventListener('visibilitychange',
visibilityChangeHandler.bind(null, weakSelf, this._window),
/* useCapture = */ false,
/* wantsUntrusted = */ false);
this._window._browserElementParents.set(this, null);
// Insert ourself into the prompt service.
BrowserElementPromptService.mapFrameToBrowserElementParent(this._frameElement, this);