Bug 1053805 - Tweak webgl,canvas and webaudio actors for frames selection. r=vp,past

This commit is contained in:
Alexandre Poirot 2014-09-01 03:20:00 +02:00
parent 1a4979ddec
commit c730425c3a
10 changed files with 142 additions and 46 deletions

View File

@ -120,17 +120,26 @@ let EventsHandler = {
/**
* Called for each location change in the debugged tab.
*/
_onTabNavigated: function(event) {
_onTabNavigated: function(event, {isFrameSwitching}) {
switch (event) {
case "will-navigate": {
Task.spawn(function() {
// Make sure the backend is prepared to handle WebGL contexts.
gFront.setup({ reload: false });
if (!isFrameSwitching) {
gFront.setup({ reload: false });
}
// Reset UI.
ShadersListView.empty();
$("#reload-notice").hidden = true;
$("#waiting-notice").hidden = false;
// When switching to an iframe, ensure displaying the reload button.
// As the document has already been loaded without being hooked.
if (isFrameSwitching) {
$("#reload-notice").hidden = false;
$("#waiting-notice").hidden = true;
} else {
$("#reload-notice").hidden = true;
$("#waiting-notice").hidden = false;
}
yield ShadersEditorsView.setText({ vs: "", fs: "" });
$("#content").hidden = true;
}).then(() => window.emit(EVENTS.UI_RESET));

View File

@ -10,6 +10,7 @@ support-files =
doc_connect-toggle.html
doc_connect-param.html
doc_connect-multi-param.html
doc_iframe-context.html
440hz_sine.ogg
head.js
@ -29,6 +30,7 @@ support-files =
[browser_wa_reset-01.js]
[browser_wa_reset-02.js]
[browser_wa_reset-03.js]
[browser_wa_reset-04.js]
[browser_wa_graph-click.js]
[browser_wa_graph-markers.js]

View File

@ -0,0 +1,56 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests that switching to an iframe works fine.
*/
function spawnTest() {
Services.prefs.setBoolPref("devtools.command-button-frames.enabled", true);
let [target, debuggee, panel, toolbox] = yield initWebAudioEditor(IFRAME_CONTEXT_URL);
let { gFront, $ } = panel.panelWin;
is($("#reload-notice").hidden, false,
"The 'reload this page' notice should initially be visible.");
is($("#waiting-notice").hidden, true,
"The 'waiting for an audio context' notice should initially be hidden.");
is($("#content").hidden, true,
"The tool's content should initially be hidden.");
let btn = toolbox.doc.getElementById("command-button-frames");
ok(!btn.firstChild.getAttribute("hidden"), "The frame list button is visible");
let frameBtns = btn.firstChild.querySelectorAll("[data-window-id]");
is(frameBtns.length, 2, "We have both frames in the list");
// Select the iframe
frameBtns[1].click();
let navigating = once(target, "will-navigate");
yield navigating;
is($("#reload-notice").hidden, false,
"The 'reload this page' notice should still be visible when switching to a frame.");
is($("#waiting-notice").hidden, true,
"The 'waiting for an audio context' notice should be kept hidden when switching to a frame.");
is($("#content").hidden, true,
"The tool's content should still be hidden.");
let navigating = once(target, "will-navigate");
let started = once(gFront, "start-context");
reload(target);
yield Promise.all([navigating, started]);
is($("#reload-notice").hidden, true,
"The 'reload this page' notice should be hidden after reloading the frame.");
is($("#waiting-notice").hidden, true,
"The 'waiting for an audio context' notice should be hidden after reloading the frame.");
is($("#content").hidden, false,
"The tool's content should appear after reload.");
yield teardown(panel);
finish();
}

View File

@ -0,0 +1,14 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Web Audio Editor test page with an iframe</title>
</head>
<body>
<iframe id="frame" src="doc_simple-context.html" />
</body>
</html>

View File

@ -30,6 +30,7 @@ const DESTROY_NODES_URL = EXAMPLE_URL + "doc_destroy-nodes.html";
const CONNECT_TOGGLE_URL = EXAMPLE_URL + "doc_connect-toggle.html";
const CONNECT_PARAM_URL = EXAMPLE_URL + "doc_connect-param.html";
const CONNECT_MULTI_PARAM_URL = EXAMPLE_URL + "doc_connect-multi-param.html";
const IFRAME_CONTEXT_URL = EXAMPLE_URL + "doc_iframe-context.html";
// All tests are asynchronous.
waitForExplicitFinish();
@ -150,7 +151,7 @@ function initWebAudioEditor(aUrl) {
Services.prefs.setBoolPref("devtools.webaudioeditor.enabled", true);
let toolbox = yield gDevTools.showToolbox(target, "webaudioeditor");
let panel = toolbox.getCurrentPanel();
return [target, debuggee, panel];
return [target, debuggee, panel, toolbox];
});
}

View File

@ -223,8 +223,6 @@ let WebAudioEditorController = {
* for an audio context notice.
*/
reset: function () {
$("#reload-notice").hidden = true;
$("#waiting-notice").hidden = false;
$("#content").hidden = true;
WebAudioGraphView.resetUI();
WebAudioInspectorView.resetUI();
@ -250,16 +248,30 @@ let WebAudioEditorController = {
/**
* Called for each location change in the debugged tab.
*/
_onTabNavigated: Task.async(function* (event) {
_onTabNavigated: Task.async(function* (event, {isFrameSwitching}) {
switch (event) {
case "will-navigate": {
// Make sure the backend is prepared to handle audio contexts.
yield gFront.setup({ reload: false });
if (!isFrameSwitching) {
yield gFront.setup({ reload: false });
}
// Reset UI to show "Waiting for Audio Context..." and clear out
// current UI.
// Clear out current UI.
this.reset();
// When switching to an iframe, ensure displaying the reload button.
// As the document has already been loaded without being hooked.
if (isFrameSwitching) {
$("#reload-notice").hidden = false;
$("#waiting-notice").hidden = true;
} else {
// Otherwise, we are loading a new top level document,
// so we don't need to reload anymore and should receive
// new node events.
$("#reload-notice").hidden = true;
$("#waiting-notice").hidden = false;
}
// Clear out stored audio nodes
AudioNodes.length = 0;
AudioNodeConnections.clear();

View File

@ -290,10 +290,9 @@ let CallWatcherActor = exports.CallWatcherActor = protocol.ActorClass({
this._tracedFunctions = tracedFunctions || [];
this._holdWeak = !!holdWeak;
this._storeCalls = !!storeCalls;
this._contentObserver = new ContentObserver(this.tabActor);
on(this._contentObserver, "global-created", this._onGlobalCreated);
on(this._contentObserver, "global-destroyed", this._onGlobalDestroyed);
on(this.tabActor, "window-ready", this._onGlobalCreated);
on(this.tabActor, "window-destroyed", this._onGlobalDestroyed);
if (startRecording) {
this.resumeRecording();
@ -325,13 +324,11 @@ let CallWatcherActor = exports.CallWatcherActor = protocol.ActorClass({
this._initialized = false;
this._finalized = true;
this._contentObserver.stopListening();
off(this._contentObserver, "global-created", this._onGlobalCreated);
off(this._contentObserver, "global-destroyed", this._onGlobalDestroyed);
off(this.tabActor, "window-ready", this._onGlobalCreated);
off(this.tabActor, "window-destroyed", this._onGlobalDestroyed);
this._tracedGlobals = null;
this._tracedFunctions = null;
this._contentObserver = null;
}, {
oneway: true
}),
@ -380,10 +377,15 @@ let CallWatcherActor = exports.CallWatcherActor = protocol.ActorClass({
/**
* Invoked whenever the current tab actor's document global is created.
*/
_onGlobalCreated: function(window) {
_onGlobalCreated: function({window, id, isTopLevel}) {
let self = this;
this._tracedWindowId = ContentObserver.GetInnerWindowID(window);
// TODO: bug 981748, support more than just the top-level documents.
if (!isTopLevel) {
return;
}
this._tracedWindowId = id;
let unwrappedWindow = XPCNativeWrapper.unwrap(window);
let callback = this._onContentFunctionCall;
@ -529,7 +531,7 @@ let CallWatcherActor = exports.CallWatcherActor = protocol.ActorClass({
/**
* Invoked whenever the current tab actor's inner window is destroyed.
*/
_onGlobalDestroyed: function(id) {
_onGlobalDestroyed: function({window, id, isTopLevel}) {
if (this._tracedWindowId == id) {
this.pauseRecording();
this.eraseRecording();

View File

@ -332,11 +332,9 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
holdWeak: true,
storeCalls: false
});
// Bind to the `global-destroyed` event on the content observer so we can
// unbind events between the global destruction and the `finalize` cleanup
// method on the actor.
// TODO expose these events on CallWatcherActor itself, bug 1021321
on(this._callWatcher._contentObserver, "global-destroyed", this._onGlobalDestroyed);
// Bind to the `window-destroyed` event so we can unbind events between
// the global destruction and the `finalize` cleanup method on the actor.
on(this.tabActor, "window-destroyed", this._onGlobalDestroyed);
}, {
request: { reload: Option(0, "boolean") },
oneway: true
@ -406,7 +404,7 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
}
this.tabActor = null;
this._initialized = false;
off(this._callWatcher._contentObserver, "global-destroyed", this._onGlobalDestroyed);
off(this.tabActor, "window-destroyed", this._onGlobalDestroyed);
this._nativeToActorID = null;
this._callWatcher.eraseRecording();
this._callWatcher.finalize();
@ -586,7 +584,7 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
* so we can cleanup some things between the global being destroyed and
* when the actor's `finalize` method gets called.
*/
_onGlobalDestroyed: function (id) {
_onGlobalDestroyed: function ({id}) {
if (this._callWatcher._tracedWindowId !== id) {
return;
}

View File

@ -1230,7 +1230,7 @@ TabActor.prototype = {
// to let a chance to unregister it
this._willNavigate(this.window, window.location.href, null, true);
this._windowDestroyed(this.window);
this._windowDestroyed(this.window, null, true);
DevToolsUtils.executeSoon(() => {
this._setWindow(window);
@ -1311,11 +1311,12 @@ TabActor.prototype = {
}
},
_windowDestroyed: function (window, id = null) {
_windowDestroyed: function (window, id = null, isFrozen = false) {
events.emit(this, "window-destroyed", {
window: window,
isTopLevel: window == this.window,
id: id || getWindowID(window)
id: id || getWindowID(window),
isFrozen: isFrozen
});
},
@ -1969,7 +1970,7 @@ DebuggerProgressListener.prototype = {
}
let window = evt.target.defaultView;
this._tabActor._windowDestroyed(window);
this._tabActor._windowDestroyed(window, null, true);
}, "DebuggerProgressListener.prototype.onWindowHidden"),
observe: DevToolsUtils.makeInfallible(function(subject, topic) {

View File

@ -252,11 +252,10 @@ let WebGLActor = exports.WebGLActor = protocol.ActorClass({
this._initialized = true;
this._programActorsCache = [];
this._contentObserver = new ContentObserver(this.tabActor);
this._webglObserver = new WebGLObserver();
on(this._contentObserver, "global-created", this._onGlobalCreated);
on(this._contentObserver, "global-destroyed", this._onGlobalDestroyed);
on(this.tabActor, "window-ready", this._onGlobalCreated);
on(this.tabActor, "window-destroyed", this._onGlobalDestroyed);
on(this._webglObserver, "program-linked", this._onProgramLinked);
if (reload) {
@ -278,9 +277,8 @@ let WebGLActor = exports.WebGLActor = protocol.ActorClass({
}
this._initialized = false;
this._contentObserver.stopListening();
off(this._contentObserver, "global-created", this._onGlobalCreated);
off(this._contentObserver, "global-destroyed", this._onGlobalDestroyed);
off(this.tabActor, "window-ready", this._onGlobalCreated);
off(this.tabActor, "window-destroyed", this._onGlobalDestroyed);
off(this._webglObserver, "program-linked", this._onProgramLinked);
this._programActorsCache = null;
@ -379,19 +377,22 @@ let WebGLActor = exports.WebGLActor = protocol.ActorClass({
/**
* Invoked whenever the current tab actor's document global is created.
*/
_onGlobalCreated: function(window) {
let id = ContentObserver.GetInnerWindowID(window);
WebGLInstrumenter.handle(window, this._webglObserver);
events.emit(this, "global-created", id);
_onGlobalCreated: function({id, window, isTopLevel}) {
if (isTopLevel) {
WebGLInstrumenter.handle(window, this._webglObserver);
events.emit(this, "global-created", id);
}
},
/**
* Invoked whenever the current tab actor's inner window is destroyed.
*/
_onGlobalDestroyed: function(id) {
removeFromArray(this._programActorsCache, e => e.ownerWindow == id);
this._webglObserver.unregisterContextsForWindow(id);
events.emit(this, "global-destroyed", id);
_onGlobalDestroyed: function({id, isTopLevel, isFrozen}) {
if (isTopLevel && !isFrozen) {
removeFromArray(this._programActorsCache, e => e.ownerWindow == id);
this._webglObserver.unregisterContextsForWindow(id);
events.emit(this, "global-destroyed", id);
}
},
/**