Bug 808231 - Implement add/removeNextPaintListener() methods for mozbrowsers r=jlebar a=blocking-basecamp

This commit is contained in:
Tim Taubert 2012-12-06 18:03:27 +01:00
parent 04b19cea8b
commit 0c4f22e11f
7 changed files with 163 additions and 14 deletions

View File

@ -58,6 +58,8 @@ function BrowserElementChild() {
this._forcedVisible = true;
this._ownerVisible = true;
this._nextPaintHandler = null;
this._init();
};
@ -109,11 +111,10 @@ BrowserElementChild.prototype = {
/* useCapture = */ true,
/* wantsUntrusted = */ false);
this._afterPaintHandlerClosure = this._afterPaintHandler.bind(this);
addEventListener('MozAfterPaint',
this._afterPaintHandlerClosure,
/* useCapture = */ true,
/* wantsUntrusted = */ false);
// Registers a MozAfterPaint handler for the very first paint.
this._addMozAfterPaintHandler(function () {
sendAsyncMsg('firstpaint');
});
var self = this;
function addMsgListener(msg, handler) {
@ -135,6 +136,8 @@ BrowserElementChild.prototype = {
addMsgListener("fire-ctx-callback", this._recvFireCtxCallback);
addMsgListener("owner-visibility-change", this._recvOwnerVisibilityChange);
addMsgListener("exit-fullscreen", this._recvExitFullscreen.bind(this));
addMsgListener("activate-next-paint-listener", this._activateNextPaintListener.bind(this));
addMsgListener("deactivate-next-paint-listener", this._deactivateNextPaintListener.bind(this));
let els = Cc["@mozilla.org/eventlistenerservice;1"]
.getService(Ci.nsIEventListenerService);
@ -361,16 +364,39 @@ BrowserElementChild.prototype = {
}
},
_afterPaintHandler: function(e) {
let uri = docShell.QueryInterface(Ci.nsIWebNavigation).currentURI;
debug("Got afterpaint event: " + uri.spec);
if (uri.spec != "about:blank") {
/* this._afterPaintHandlerClosure == arguments.callee, except we're in
* strict mode so we don't have arguments.callee. */
removeEventListener('MozAfterPaint', this._afterPaintHandlerClosure,
/* useCapture */ true);
_addMozAfterPaintHandler: function(callback) {
function onMozAfterPaint() {
let uri = docShell.QueryInterface(Ci.nsIWebNavigation).currentURI;
debug("Got afterpaint event: " + uri.spec);
if (uri.spec != "about:blank") {
removeEventListener('MozAfterPaint', onMozAfterPaint,
/* useCapture = */ true);
callback();
}
}
sendAsyncMsg('firstpaint');
addEventListener('MozAfterPaint', onMozAfterPaint, /* useCapture = */ true);
return onMozAfterPaint;
},
_removeMozAfterPaintHandler: function(listener) {
removeEventListener('MozAfterPaint', listener,
/* useCapture = */ true);
},
_activateNextPaintListener: function(e) {
if (!this._nextPaintHandler) {
this._nextPaintHandler = this._addMozAfterPaintHandler(function () {
this._nextPaintHandler = null;
sendAsyncMsg('nextpaint');
}.bind(this));
}
},
_deactivateNextPaintListener: function(e) {
if (this._nextPaintHandler) {
this._removeMozAfterPaintHandler(this._nextPaintHandler);
this._nextPaintHandler = null;
}
},

View File

@ -176,6 +176,7 @@ function BrowserElementParent(frameLoader, hasRemoteFrame) {
this._domRequestCounter = 0;
this._pendingDOMRequests = {};
this._hasRemoteFrame = hasRemoteFrame;
this._nextPaintListeners = [];
this._frameLoader = frameLoader;
this._frameElement = frameLoader.QueryInterface(Ci.nsIFrameLoader).ownerElement;
@ -213,6 +214,7 @@ function BrowserElementParent(frameLoader, hasRemoteFrame) {
addMessageListener("error", this._fireEventFromMsg);
addMessageListener("scroll", this._fireEventFromMsg);
addMessageListener("firstpaint", this._fireEventFromMsg);
addMessageListener("nextpaint", this._recvNextPaint);
addMessageListener("keyevent", this._fireKeyEvent);
addMessageListener("showmodalprompt", this._handleShowModalPrompt);
addMessageListener('got-purge-history', this._gotDOMRequestResult);
@ -257,6 +259,8 @@ function BrowserElementParent(frameLoader, hasRemoteFrame) {
defineMethod('stop', this._stop);
defineMethod('purgeHistory', this._purgeHistory);
defineMethod('getScreenshot', this._getScreenshot);
defineMethod('addNextPaintListener', this._addNextPaintListener);
defineMethod('removeNextPaintListener', this._removeNextPaintListener);
defineDOMRequestMethod('getCanGoBack', 'get-can-go-back');
defineDOMRequestMethod('getCanGoForward', 'get-can-go-forward');
@ -594,6 +598,41 @@ BrowserElementParent.prototype = {
{width: width, height: height});
},
_recvNextPaint: function(data) {
let listeners = this._nextPaintListeners;
this._nextPaintListeners = [];
for (let listener of listeners) {
try {
listener();
} catch (e) {
// If a listener throws we'll continue.
}
}
},
_addNextPaintListener: function(listener) {
if (typeof listener != 'function')
throw Components.Exception("Invalid argument", Cr.NS_ERROR_INVALID_ARG);
if (this._nextPaintListeners.push(listener) == 1)
this._sendAsyncMsg('activate-next-paint-listener');
},
_removeNextPaintListener: function(listener) {
if (typeof listener != 'function')
throw Components.Exception("Invalid argument", Cr.NS_ERROR_INVALID_ARG);
for (let i = this._nextPaintListeners.length - 1; i >= 0; i--) {
if (this._nextPaintListeners[i] == listener) {
this._nextPaintListeners.splice(i, 1);
break;
}
}
if (this._nextPaintListeners.length == 0)
this._sendAsyncMsg('deactivate-next-paint-listener');
},
_fireKeyEvent: function(data) {
let evt = this._window.document.createEvent("KeyboardEvent");
evt.initKeyEvent(data.json.type, true, true, this._window,

View File

@ -71,6 +71,10 @@ MOCHITEST_FILES = \
file_browserElement_XFrameOptionsAllowFrom.sjs \
browserElement_FirstPaint.js \
test_browserElement_inproc_FirstPaint.html \
browserElement_NextPaint.js \
test_browserElement_inproc_NextPaint.html \
test_browserElement_oop_NextPaint.html \
file_browserElement_NextPaint.html \
browserElement_Alert.js \
test_browserElement_inproc_Alert.html \
browserElement_AlertInFrame.js \

View File

@ -0,0 +1,45 @@
/* Any copyright is dedicated to the public domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Bug 808231 - Add mozbrowsernextpaint event.
"use strict";
SimpleTest.waitForExplicitFinish();
function runTest() {
browserElementTestHelpers.setEnabledPref(true);
browserElementTestHelpers.addPermission();
var iframe = document.createElement('iframe');
iframe.mozbrowser = true;
document.body.appendChild(iframe);
// Add a first listener that we'll remove shortly after.
iframe.addNextPaintListener(wrongListener);
var gotFirstNextPaintEvent = false;
iframe.addNextPaintListener(function () {
ok(!gotFirstNextPaintEvent, 'got the first nextpaint event');
// Make sure we're only called once.
gotFirstNextPaintEvent = true;
iframe.addNextPaintListener(function () {
info('got the second nextpaint event');
SimpleTest.finish();
});
// Force the iframe to repaint.
SimpleTest.executeSoon(function () iframe.src += '#next');
});
// Remove the first listener to make sure it's not called.
iframe.removeNextPaintListener(wrongListener);
iframe.src = 'file_browserElement_NextPaint.html';
}
function wrongListener() {
ok(false, 'first listener should have been removed');
}
runTest();

View File

@ -0,0 +1,9 @@
<html>
<body>
<script>
addEventListener("hashchange", function () {
document.body.style.backgroundColor = "red";
});
</script>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Bug 808231</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7" src="browserElement_NextPaint.js">
</script>
</body>
</html>

View File

@ -0,0 +1,13 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for Bug 808231</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="browserElementTestHelpers.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript;version=1.7" src="browserElement_NextPaint.js">
</script>
</body>
</html>