mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-03 02:25:34 +00:00
merge m-c to fx-team
This commit is contained in:
commit
4fc0e432b9
@ -978,7 +978,7 @@ var WebappsHelper = {
|
||||
});
|
||||
break;
|
||||
case "webapps-close":
|
||||
shell.sendEvent(shell.getContentWindow(), "webapps-close",
|
||||
shell.sendEvent(getContentWindow(), "webapps-close",
|
||||
{
|
||||
__exposedProps__: { "manifestURL": "r" },
|
||||
"manifestURL": json.manifestURL
|
||||
|
@ -4206,6 +4206,10 @@ var TabsProgressListener = {
|
||||
if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT)
|
||||
return;
|
||||
|
||||
// Filter out location changes in sub documents.
|
||||
if (!aWebProgress.isTopLevel)
|
||||
return;
|
||||
|
||||
// Only need to call locationChange if the PopupNotifications object
|
||||
// for this window has already been initialized (i.e. its getter no
|
||||
// longer exists)
|
||||
@ -4214,10 +4218,7 @@ var TabsProgressListener = {
|
||||
|
||||
gBrowser.getNotificationBox(aBrowser).removeTransientNotifications();
|
||||
|
||||
// Filter out location changes in sub documents.
|
||||
if (aWebProgress.isTopLevel) {
|
||||
FullZoom.onLocationChange(aLocationURI, false, aBrowser);
|
||||
}
|
||||
FullZoom.onLocationChange(aLocationURI, false, aBrowser);
|
||||
},
|
||||
|
||||
onRefreshAttempted: function (aBrowser, aWebProgress, aURI, aDelay, aSameURI) {
|
||||
|
@ -31,6 +31,15 @@ let gPage = {
|
||||
this._updateAttributes(enabled);
|
||||
},
|
||||
|
||||
/**
|
||||
* True if the page is allowed to capture thumbnails using the background
|
||||
* thumbnail service.
|
||||
*/
|
||||
get allowBackgroundCaptures() {
|
||||
return document.documentElement.getAttribute("allow-background-captures") ==
|
||||
"true";
|
||||
},
|
||||
|
||||
/**
|
||||
* Listens for notifications specific to this page.
|
||||
*/
|
||||
@ -74,6 +83,20 @@ let gPage = {
|
||||
|
||||
this._initialized = true;
|
||||
|
||||
this._mutationObserver = new MutationObserver(() => {
|
||||
if (this.allowBackgroundCaptures) {
|
||||
for (let site of gGrid.sites) {
|
||||
if (site) {
|
||||
site.captureIfMissing();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
this._mutationObserver.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ["allow-background-captures"],
|
||||
});
|
||||
|
||||
gLinks.populateCache(function () {
|
||||
// Initialize and render the grid.
|
||||
gGrid.init();
|
||||
@ -123,6 +146,7 @@ let gPage = {
|
||||
handleEvent: function Page_handleEvent(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case "unload":
|
||||
this._mutationObserver.disconnect();
|
||||
gAllPages.unregister(this);
|
||||
break;
|
||||
case "click":
|
||||
|
31
browser/base/content/newtab/preloaderContent.js
Normal file
31
browser/base/content/newtab/preloaderContent.js
Normal file
@ -0,0 +1,31 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
(function () { // bug 673569 workaround :(
|
||||
|
||||
const ALLOW_BG_CAPTURES_MSG = "BrowserNewTabPreloader:allowBackgroundCaptures";
|
||||
|
||||
addMessageListener(ALLOW_BG_CAPTURES_MSG, function onMsg(msg) {
|
||||
removeMessageListener(ALLOW_BG_CAPTURES_MSG, onMsg);
|
||||
|
||||
if (content.document.readyState == "complete") {
|
||||
setAllowBackgroundCaptures();
|
||||
return;
|
||||
}
|
||||
|
||||
// This is the case when preloading is disabled.
|
||||
addEventListener("load", function onLoad(event) {
|
||||
if (event.target == content.document) {
|
||||
removeEventListener("load", onLoad, true);
|
||||
setAllowBackgroundCaptures();
|
||||
}
|
||||
}, true);
|
||||
});
|
||||
|
||||
function setAllowBackgroundCaptures() {
|
||||
content.document.documentElement.setAttribute("allow-background-captures",
|
||||
"true");
|
||||
}
|
||||
|
||||
})();
|
@ -133,11 +133,20 @@ Site.prototype = {
|
||||
this._updateAttributes(true);
|
||||
// Capture the page if the thumbnail is missing, which will cause page.js
|
||||
// to be notified and call our refreshThumbnail() method.
|
||||
BackgroundPageThumbs.captureIfMissing(this.url);
|
||||
this.captureIfMissing();
|
||||
// but still display whatever thumbnail might be available now.
|
||||
this.refreshThumbnail();
|
||||
},
|
||||
|
||||
/**
|
||||
* Captures the site's thumbnail in the background, but only if there's no
|
||||
* existing thumbnail and the page allows background captures.
|
||||
*/
|
||||
captureIfMissing: function Site_captureIfMissing() {
|
||||
if (gPage.allowBackgroundCaptures)
|
||||
BackgroundPageThumbs.captureIfMissing(this.url);
|
||||
},
|
||||
|
||||
/**
|
||||
* Refreshes the thumbnail for the site.
|
||||
*/
|
||||
|
@ -829,23 +829,41 @@ var tests = [
|
||||
});
|
||||
}
|
||||
},
|
||||
{ // Test #28 - location change in embedded frame removes notification
|
||||
{ // Test #28 - location change in an embedded frame should not remove a notification
|
||||
run: function () {
|
||||
loadURI("data:text/html,<iframe id='iframe' src='http://example.com/'>", function () {
|
||||
let notifyObj = new basicNotification();
|
||||
notifyObj.options.eventCallback = function (eventName) {
|
||||
loadURI("data:text/html;charset=utf8,<iframe id='iframe' src='http://example.com/'>", function () {
|
||||
this.notifyObj = new basicNotification();
|
||||
this.notifyObj.options.eventCallback = function (eventName) {
|
||||
if (eventName == "removed") {
|
||||
ok(true, "Notification removed in background tab after reloading");
|
||||
executeSoon(goNext);
|
||||
ok(false, "Test 28: Notification removed from browser when subframe navigated");
|
||||
}
|
||||
};
|
||||
showNotification(notifyObj);
|
||||
executeSoon(function () {
|
||||
content.document.getElementById("iframe")
|
||||
.setAttribute("src", "http://example.org/");
|
||||
});
|
||||
});
|
||||
}
|
||||
showNotification(this.notifyObj);
|
||||
}.bind(this));
|
||||
},
|
||||
onShown: function (popup) {
|
||||
let self = this;
|
||||
let progressListener = {
|
||||
onLocationChange: function onLocationChange(aBrowser) {
|
||||
if (aBrowser != gBrowser.selectedBrowser) {
|
||||
return;
|
||||
}
|
||||
let notification = PopupNotifications.getNotification(self.notifyObj.id,
|
||||
self.notifyObj.browser);
|
||||
ok(notification != null, "Test 28: Notification remained when subframe navigated");
|
||||
self.notifyObj.options.eventCallback = undefined;
|
||||
|
||||
notification.remove();
|
||||
gBrowser.removeTabsProgressListener(progressListener);
|
||||
},
|
||||
};
|
||||
|
||||
info("Test 28: Adding progress listener and performing navigation");
|
||||
gBrowser.addTabsProgressListener(progressListener);
|
||||
content.document.getElementById("iframe")
|
||||
.setAttribute("src", "http://example.org/");
|
||||
},
|
||||
onHidden: function () {}
|
||||
},
|
||||
{ // Test #29 - Popup Notifications should catch exceptions from callbacks
|
||||
run: function () {
|
||||
|
@ -1,6 +1,7 @@
|
||||
[DEFAULT]
|
||||
support-files = head.js
|
||||
|
||||
[browser_newtab_background_captures.js]
|
||||
[browser_newtab_block.js]
|
||||
[browser_newtab_bug721442.js]
|
||||
[browser_newtab_bug722273.js]
|
||||
|
@ -0,0 +1,100 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Verifies that hidden, pre-loaded newtabs don't allow background captures, and
|
||||
* when unhidden, do allow background captures.
|
||||
*/
|
||||
|
||||
const CAPTURE_PREF = "browser.pagethumbnails.capturing_disabled";
|
||||
|
||||
function runTests() {
|
||||
let imports = {};
|
||||
Cu.import("resource://gre/modules/PageThumbs.jsm", imports);
|
||||
Cu.import("resource:///modules/BrowserNewTabPreloader.jsm", imports);
|
||||
|
||||
// Disable captures.
|
||||
let originalDisabledState = Services.prefs.getBoolPref(CAPTURE_PREF);
|
||||
Services.prefs.setBoolPref(CAPTURE_PREF, true);
|
||||
|
||||
// Make sure the thumbnail doesn't exist yet.
|
||||
let siteName = "newtab_background_captures";
|
||||
let url = "http://example.com/#" + siteName;
|
||||
let path = imports.PageThumbsStorage.getFilePathForURL(url);
|
||||
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
|
||||
file.initWithPath(path);
|
||||
try {
|
||||
file.remove(false);
|
||||
}
|
||||
catch (err) {}
|
||||
|
||||
// Add a top site.
|
||||
yield setLinks(siteName);
|
||||
|
||||
// We need a handle to a hidden, pre-loaded newtab so we can verify that it
|
||||
// doesn't allow background captures. Add a newtab, which triggers creation
|
||||
// of a hidden newtab, and then keep calling BrowserNewTabPreloader.newTab
|
||||
// until it returns true, meaning that it swapped the passed-in tab's docshell
|
||||
// for the hidden newtab docshell.
|
||||
let tab = gWindow.gBrowser.addTab("about:blank");
|
||||
yield addNewTabPageTab();
|
||||
let swapWaitCount = 0;
|
||||
let swapped = imports.BrowserNewTabPreloader.newTab(tab);
|
||||
while (!swapped) {
|
||||
if (++swapWaitCount == 10) {
|
||||
ok(false, "Timed out waiting for newtab docshell swap.");
|
||||
return;
|
||||
}
|
||||
// Give the hidden newtab some time to finish loading.
|
||||
yield wait(2000);
|
||||
info("Checking newtab swap " + swapWaitCount);
|
||||
swapped = imports.BrowserNewTabPreloader.newTab(tab);
|
||||
}
|
||||
|
||||
// The tab's docshell is now the previously hidden newtab docshell.
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
isnot(doc.documentElement.getAttribute("allow-background-captures"), "true",
|
||||
"Pre-loaded docshell just synchronously swapped, so background " +
|
||||
"captures should not be allowed yet");
|
||||
|
||||
// Enable captures.
|
||||
Services.prefs.setBoolPref(CAPTURE_PREF, false);
|
||||
|
||||
// Now that the newtab is visible, its allow-background-captures attribute
|
||||
// should be set eventually.
|
||||
let allowBackgroundCaptures = false;
|
||||
let mutationObserver = new MutationObserver(() => {
|
||||
mutationObserver.disconnect();
|
||||
allowBackgroundCaptures = true;
|
||||
is(doc.documentElement.getAttribute("allow-background-captures"), "true",
|
||||
"allow-background-captures should now be true");
|
||||
info("Waiting for thumbnail to be created after observing " +
|
||||
"allow-background-captures change");
|
||||
});
|
||||
mutationObserver.observe(doc.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ["allow-background-captures"],
|
||||
});
|
||||
|
||||
// And the allow-background-captures change should trigger the thumbnail
|
||||
// capture.
|
||||
Services.obs.addObserver(function onCreate(subj, topic, data) {
|
||||
if (data != url)
|
||||
return;
|
||||
ok(allowBackgroundCaptures,
|
||||
"page-thumbnail:create should be observed after " +
|
||||
"allow-background-captures was set");
|
||||
Services.obs.removeObserver(onCreate, "page-thumbnail:create");
|
||||
// Test finished!
|
||||
Services.prefs.setBoolPref(CAPTURE_PREF, originalDisabledState);
|
||||
file.remove(false);
|
||||
TestRunner.next();
|
||||
}, "page-thumbnail:create", false);
|
||||
|
||||
info("Waiting for allow-background-captures change");
|
||||
yield true;
|
||||
}
|
||||
|
||||
function wait(ms) {
|
||||
setTimeout(TestRunner.next, ms);
|
||||
}
|
@ -64,6 +64,7 @@ browser.jar:
|
||||
content/browser/newtab/newTab.xul (content/newtab/newTab.xul)
|
||||
* content/browser/newtab/newTab.js (content/newtab/newTab.js)
|
||||
content/browser/newtab/newTab.css (content/newtab/newTab.css)
|
||||
content/browser/newtab/preloaderContent.js (content/newtab/preloaderContent.js)
|
||||
* content/browser/pageinfo/pageInfo.xul (content/pageinfo/pageInfo.xul)
|
||||
content/browser/pageinfo/pageInfo.js (content/pageinfo/pageInfo.js)
|
||||
content/browser/pageinfo/pageInfo.css (content/pageinfo/pageInfo.css)
|
||||
|
@ -49,7 +49,7 @@
|
||||
<button id="requests-menu-status-button"
|
||||
class="requests-menu-header-button requests-menu-status"
|
||||
onclick="NetMonitorView.RequestsMenu.sortBy('status')"
|
||||
label="&netmonitorUI.toolbar.status;">
|
||||
label="&netmonitorUI.toolbar.status2;">
|
||||
</button>
|
||||
<button id="requests-menu-method-button"
|
||||
class="requests-menu-header-button requests-menu-method"
|
||||
|
@ -19,8 +19,13 @@ const Editor = require("devtools/sourceeditor/editor");
|
||||
|
||||
// The panel's window global is an EventEmitter firing the following events:
|
||||
const EVENTS = {
|
||||
// When new programs are received from the server.
|
||||
NEW_PROGRAM: "ShaderEditor:NewProgram",
|
||||
PROGRAMS_ADDED: "ShaderEditor:ProgramsAdded",
|
||||
|
||||
// When the vertex and fragment sources were shown in the editor.
|
||||
SOURCES_SHOWN: "ShaderEditor:SourcesShown",
|
||||
|
||||
// When a shader's source was edited and compiled via the editor.
|
||||
SHADER_COMPILED: "ShaderEditor:ShaderCompiled"
|
||||
};
|
||||
@ -72,10 +77,12 @@ let EventsHandler = {
|
||||
*/
|
||||
initialize: function() {
|
||||
this._onHostChanged = this._onHostChanged.bind(this);
|
||||
this._onWillNavigate = this._onWillNavigate.bind(this);
|
||||
this._onTabNavigated = this._onTabNavigated.bind(this);
|
||||
this._onProgramLinked = this._onProgramLinked.bind(this);
|
||||
this._onProgramsAdded = this._onProgramsAdded.bind(this);
|
||||
gToolbox.on("host-changed", this._onHostChanged);
|
||||
gTarget.on("will-navigate", this._onWillNavigate);
|
||||
gTarget.on("will-navigate", this._onTabNavigated);
|
||||
gTarget.on("navigate", this._onTabNavigated);
|
||||
gFront.on("program-linked", this._onProgramLinked);
|
||||
|
||||
},
|
||||
@ -85,7 +92,8 @@ let EventsHandler = {
|
||||
*/
|
||||
destroy: function() {
|
||||
gToolbox.off("host-changed", this._onHostChanged);
|
||||
gTarget.off("will-navigate", this._onWillNavigate);
|
||||
gTarget.off("will-navigate", this._onTabNavigated);
|
||||
gTarget.off("navigate", this._onTabNavigated);
|
||||
gFront.off("program-linked", this._onProgramLinked);
|
||||
},
|
||||
|
||||
@ -101,20 +109,51 @@ let EventsHandler = {
|
||||
/**
|
||||
* Called for each location change in the debugged tab.
|
||||
*/
|
||||
_onWillNavigate: function() {
|
||||
gFront.setup();
|
||||
_onTabNavigated: function(event) {
|
||||
switch (event) {
|
||||
case "will-navigate": {
|
||||
// Make sure the backend is prepared to handle WebGL contexts.
|
||||
gFront.setup({ reload: false });
|
||||
|
||||
ShadersListView.empty();
|
||||
ShadersEditorsView.setText({ vs: "", fs: "" });
|
||||
$("#reload-notice").hidden = true;
|
||||
$("#waiting-notice").hidden = false;
|
||||
$("#content").hidden = true;
|
||||
// Reset UI.
|
||||
ShadersListView.empty();
|
||||
ShadersEditorsView.setText({ vs: "", fs: "" });
|
||||
$("#reload-notice").hidden = true;
|
||||
$("#waiting-notice").hidden = false;
|
||||
$("#content").hidden = true;
|
||||
break;
|
||||
}
|
||||
case "navigate": {
|
||||
// Manually retrieve the list of program actors known to the server,
|
||||
// because the backend won't emit "program-linked" notifications
|
||||
// in the case of a bfcache navigation (since no new programs are
|
||||
// actually linked).
|
||||
gFront.getPrograms().then(this._onProgramsAdded);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called every time a program was linked in the debugged tab.
|
||||
*/
|
||||
_onProgramLinked: function(programActor) {
|
||||
this._addProgram(programActor);
|
||||
window.emit(EVENTS.NEW_PROGRAM);
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback for the front's getPrograms() method.
|
||||
*/
|
||||
_onProgramsAdded: function(programActors) {
|
||||
programActors.forEach(this._addProgram);
|
||||
window.emit(EVENTS.PROGRAMS_ADDED);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a program to the shaders list and unhides any modal notices.
|
||||
*/
|
||||
_addProgram: function(programActor) {
|
||||
$("#waiting-notice").hidden = true;
|
||||
$("#reload-notice").hidden = true;
|
||||
$("#content").hidden = false;
|
||||
@ -163,6 +202,10 @@ let ShadersListView = Heritage.extend(WidgetMethods, {
|
||||
* The program actor coming from the active thread.
|
||||
*/
|
||||
addProgram: function(programActor) {
|
||||
if (this.hasProgram(programActor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Currently, there's no good way of differentiating between programs
|
||||
// in a way that helps humans. It will be a good idea to implement a
|
||||
// standard of allowing debuggees to add some identifiable metadata to their
|
||||
@ -192,6 +235,18 @@ let ShadersListView = Heritage.extend(WidgetMethods, {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns whether a program was already added to this programs container.
|
||||
*
|
||||
* @param object programActor
|
||||
* The program actor coming from the active thread.
|
||||
* @param boolean
|
||||
* True if the program was added, false otherwise.
|
||||
*/
|
||||
hasProgram: function(programActor) {
|
||||
return !!this.attachments.filter(e => e.programActor == programActor).length;
|
||||
},
|
||||
|
||||
/**
|
||||
* The select listener for the sources container.
|
||||
*/
|
||||
|
@ -24,7 +24,7 @@
|
||||
<button id="requests-menu-reload-notice-button"
|
||||
class="devtools-toolbarbutton"
|
||||
label="&shaderEditorUI.reloadNotice1;"
|
||||
oncommand="gFront.setup();"/>
|
||||
oncommand="gFront.setup({ reload: true });"/>
|
||||
<label id="requests-menu-reload-notice-label"
|
||||
class="plain"
|
||||
value="&shaderEditorUI.reloadNotice2;"/>
|
||||
|
@ -6,6 +6,7 @@ support-files =
|
||||
head.js
|
||||
|
||||
[browser_se_aaa_run_first_leaktest.js]
|
||||
[browser_se_bfcache.js]
|
||||
[browser_se_editors-contents.js]
|
||||
[browser_se_editors-lazy-init.js]
|
||||
[browser_se_first-run.js]
|
||||
@ -31,3 +32,5 @@ support-files =
|
||||
[browser_webgl-actor-test-12.js]
|
||||
[browser_webgl-actor-test-13.js]
|
||||
[browser_webgl-actor-test-14.js]
|
||||
[browser_webgl-actor-test-15.js]
|
||||
[browser_webgl-actor-test-16.js]
|
||||
|
64
browser/devtools/shadereditor/test/browser_se_bfcache.js
Normal file
64
browser/devtools/shadereditor/test/browser_se_bfcache.js
Normal file
@ -0,0 +1,64 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests if the shader editor works with bfcache.
|
||||
*/
|
||||
|
||||
function ifWebGLSupported() {
|
||||
let [target, debuggee, panel] = yield initShaderEditor(SIMPLE_CANVAS_URL);
|
||||
let { gFront, $, EVENTS, ShadersListView, ShadersEditorsView } = panel.panelWin;
|
||||
|
||||
let reloaded = reload(target);
|
||||
let firstProgram = yield once(gFront, "program-linked");
|
||||
yield reloaded;
|
||||
|
||||
let navigated = navigate(target, MULTIPLE_CONTEXTS_URL);
|
||||
let secondProgram = yield once(gFront, "program-linked");
|
||||
let thirdProgram = yield once(gFront, "program-linked");
|
||||
yield navigated;
|
||||
|
||||
let vsEditor = yield ShadersEditorsView._getEditor("vs");
|
||||
let fsEditor = yield ShadersEditorsView._getEditor("fs");
|
||||
|
||||
yield navigateInHistory(target, "back", "will-navigate");
|
||||
yield once(panel.panelWin, EVENTS.PROGRAMS_ADDED);
|
||||
yield once(panel.panelWin, EVENTS.SOURCES_SHOWN);
|
||||
|
||||
is($("#content").hidden, false,
|
||||
"The tool's content should not be hidden.");
|
||||
is(ShadersListView.itemCount, 1,
|
||||
"The shaders list contains one entry after navigating back.");
|
||||
is(ShadersListView.selectedIndex, 0,
|
||||
"The shaders list has a correct selection after navigating back.");
|
||||
|
||||
is(vsEditor.getText().indexOf("gl_Position"), 170,
|
||||
"The vertex shader editor contains the correct text.");
|
||||
is(fsEditor.getText().indexOf("gl_FragColor"), 97,
|
||||
"The fragment shader editor contains the correct text.");
|
||||
|
||||
yield navigateInHistory(target, "forward", "will-navigate");
|
||||
yield once(panel.panelWin, EVENTS.PROGRAMS_ADDED);
|
||||
yield once(panel.panelWin, EVENTS.SOURCES_SHOWN);
|
||||
|
||||
is($("#content").hidden, false,
|
||||
"The tool's content should not be hidden.");
|
||||
is(ShadersListView.itemCount, 2,
|
||||
"The shaders list contains two entries after navigating forward.");
|
||||
is(ShadersListView.selectedIndex, 0,
|
||||
"The shaders list has a correct selection after navigating forward.");
|
||||
|
||||
is(vsEditor.getText().indexOf("gl_Position"), 100,
|
||||
"The vertex shader editor contains the correct text.");
|
||||
is(fsEditor.getText().indexOf("gl_FragColor"), 89,
|
||||
"The fragment shader editor contains the correct text.");
|
||||
|
||||
yield teardown(panel);
|
||||
finish();
|
||||
}
|
||||
|
||||
function once(aTarget, aEvent) {
|
||||
let deferred = promise.defer();
|
||||
aTarget.once(aEvent, deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
@ -12,7 +12,7 @@ function ifWebGLSupported() {
|
||||
let navigated = once(target, "navigate");
|
||||
let linked = once(front, "program-linked");
|
||||
|
||||
yield front.setup();
|
||||
yield front.setup({ reload: true });
|
||||
ok(true, "The front was setup up successfully.");
|
||||
|
||||
yield navigated;
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
function ifWebGLSupported() {
|
||||
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
|
||||
front.setup();
|
||||
front.setup({ reload: true });
|
||||
|
||||
let programActor = yield once(front, "program-linked");
|
||||
ok(programActor,
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
function ifWebGLSupported() {
|
||||
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
|
||||
front.setup();
|
||||
front.setup({ reload: true });
|
||||
|
||||
let programActor = yield once(front, "program-linked");
|
||||
let vertexShader = yield programActor.getVertexShader();
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
function ifWebGLSupported() {
|
||||
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
|
||||
front.setup();
|
||||
front.setup({ reload: true });
|
||||
|
||||
let programActor = yield once(front, "program-linked");
|
||||
let vertexShader = yield programActor.getVertexShader();
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
function ifWebGLSupported() {
|
||||
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
|
||||
front.setup();
|
||||
front.setup({ reload: true });
|
||||
|
||||
let programActor = yield once(front, "program-linked");
|
||||
let vertexShader = yield programActor.getVertexShader();
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
function ifWebGLSupported() {
|
||||
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
|
||||
front.setup();
|
||||
front.setup({ reload: true });
|
||||
|
||||
let programActor = yield once(front, "program-linked");
|
||||
let vertexShader = yield programActor.getVertexShader();
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
function ifWebGLSupported() {
|
||||
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
|
||||
front.setup();
|
||||
front.setup({ reload: true });
|
||||
|
||||
let programActor = yield once(front, "program-linked");
|
||||
let vertexShader = yield programActor.getVertexShader();
|
||||
|
@ -9,36 +9,33 @@
|
||||
function ifWebGLSupported() {
|
||||
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
|
||||
|
||||
let linked = once(front, "program-linked");
|
||||
yield front.setup();
|
||||
yield linked;
|
||||
front.setup({ reload: true });
|
||||
yield testHighlighting((yield once(front, "program-linked")));
|
||||
ok(true, "Canvas was correctly instrumented on the first navigation.");
|
||||
|
||||
let linked = once(front, "program-linked");
|
||||
yield reload(target);
|
||||
yield linked;
|
||||
reload(target);
|
||||
yield testHighlighting((yield once(front, "program-linked")));
|
||||
ok(true, "Canvas was correctly instrumented on the second navigation.");
|
||||
|
||||
let linked = once(front, "program-linked");
|
||||
yield reload(target);
|
||||
yield linked;
|
||||
reload(target);
|
||||
yield testHighlighting((yield once(front, "program-linked")));
|
||||
ok(true, "Canvas was correctly instrumented on the third navigation.");
|
||||
|
||||
let programActor = yield linked;
|
||||
let vertexShader = yield programActor.getVertexShader();
|
||||
let fragmentShader = yield programActor.getFragmentShader();
|
||||
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
|
||||
ok(true, "The top left pixel color was correct before highlighting.");
|
||||
|
||||
yield programActor.highlight([0, 0, 1, 1]);
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true);
|
||||
ok(true, "The top left pixel color is correct after highlighting.");
|
||||
|
||||
yield programActor.unhighlight();
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
|
||||
ok(true, "The top left pixel color is correct after unhighlighting.");
|
||||
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
|
||||
function testHighlighting(programActor) {
|
||||
return Task.spawn(function() {
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
|
||||
ok(true, "The top left pixel color was correct before highlighting.");
|
||||
|
||||
yield programActor.highlight([0, 0, 1, 1]);
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true);
|
||||
ok(true, "The top left pixel color is correct after highlighting.");
|
||||
|
||||
yield programActor.unhighlight();
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
|
||||
ok(true, "The top left pixel color is correct after unhighlighting.");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ function ifWebGLSupported() {
|
||||
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
|
||||
|
||||
let linked = once(front, "program-linked");
|
||||
yield front.setup();
|
||||
front.setup({ reload: true });
|
||||
yield linked;
|
||||
ok(true, "Canvas was correctly instrumented on the first navigation.");
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
function ifWebGLSupported() {
|
||||
let [target, debuggee, front] = yield initBackend(SHADER_ORDER_URL);
|
||||
front.setup();
|
||||
front.setup({ reload: true });
|
||||
|
||||
let programActor = yield once(front, "program-linked");
|
||||
let vertexShader = yield programActor.getVertexShader();
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
function ifWebGLSupported() {
|
||||
let [target, debuggee, front] = yield initBackend(MULTIPLE_CONTEXTS_URL);
|
||||
front.setup();
|
||||
front.setup({ reload: true });
|
||||
|
||||
let firstProgramActor = yield once(front, "program-linked");
|
||||
let secondProgramActor = yield once(front, "program-linked");
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
function ifWebGLSupported() {
|
||||
let [target, debuggee, front] = yield initBackend(MULTIPLE_CONTEXTS_URL);
|
||||
front.setup();
|
||||
front.setup({ reload: true });
|
||||
|
||||
let firstProgramActor = yield once(front, "program-linked");
|
||||
let secondProgramActor = yield once(front, "program-linked");
|
||||
|
@ -0,0 +1,127 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests if program actors are cached when navigating in the bfcache.
|
||||
*/
|
||||
|
||||
function ifWebGLSupported() {
|
||||
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
|
||||
front.setup({ reload: false });
|
||||
|
||||
reload(target);
|
||||
let firstProgram = yield once(front, "program-linked");
|
||||
yield checkFirstCachedPrograms(firstProgram);
|
||||
yield checkHighlightingInTheFirstPage(firstProgram);
|
||||
ok(true, "The cached programs behave correctly before the navigation.");
|
||||
|
||||
navigate(target, MULTIPLE_CONTEXTS_URL);
|
||||
let secondProgram = yield once(front, "program-linked");
|
||||
let thirdProgram = yield once(front, "program-linked");
|
||||
yield checkSecondCachedPrograms(firstProgram, [secondProgram, thirdProgram]);
|
||||
yield checkHighlightingInTheSecondPage(secondProgram, thirdProgram);
|
||||
ok(true, "The cached programs behave correctly after the navigation.");
|
||||
|
||||
once(front, "program-linked").then(() => {
|
||||
ok(false, "Shouldn't have received any more program-linked notifications.");
|
||||
});
|
||||
|
||||
yield navigateInHistory(target, "back");
|
||||
yield checkFirstCachedPrograms(firstProgram);
|
||||
yield checkHighlightingInTheFirstPage(firstProgram);
|
||||
ok(true, "The cached programs behave correctly after navigating back.");
|
||||
|
||||
yield navigateInHistory(target, "forward");
|
||||
yield checkSecondCachedPrograms(firstProgram, [secondProgram, thirdProgram]);
|
||||
yield checkHighlightingInTheSecondPage(secondProgram, thirdProgram);
|
||||
ok(true, "The cached programs behave correctly after navigating forward.");
|
||||
|
||||
yield navigateInHistory(target, "back");
|
||||
yield checkFirstCachedPrograms(firstProgram);
|
||||
yield checkHighlightingInTheFirstPage(firstProgram);
|
||||
ok(true, "The cached programs behave correctly after navigating back again.");
|
||||
|
||||
yield navigateInHistory(target, "forward");
|
||||
yield checkSecondCachedPrograms(firstProgram, [secondProgram, thirdProgram]);
|
||||
yield checkHighlightingInTheSecondPage(secondProgram, thirdProgram);
|
||||
ok(true, "The cached programs behave correctly after navigating forward again.");
|
||||
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
|
||||
function checkFirstCachedPrograms(programActor) {
|
||||
return Task.spawn(function() {
|
||||
let programs = yield front.getPrograms();
|
||||
|
||||
is(programs.length, 1,
|
||||
"There should be 1 cached program actor.");
|
||||
is(programs[0], programActor,
|
||||
"The cached program actor was the expected one.");
|
||||
})
|
||||
}
|
||||
|
||||
function checkSecondCachedPrograms(oldProgramActor, newProgramActors) {
|
||||
return Task.spawn(function() {
|
||||
let programs = yield front.getPrograms();
|
||||
|
||||
is(programs.length, 2,
|
||||
"There should be 2 cached program actors after the navigation.");
|
||||
is(programs[0], newProgramActors[0],
|
||||
"The first cached program actor was the expected one after the navigation.");
|
||||
is(programs[1], newProgramActors[1],
|
||||
"The second cached program actor was the expected one after the navigation.");
|
||||
|
||||
isnot(newProgramActors[0], oldProgramActor,
|
||||
"The old program actor is not equal to the new first program actor.");
|
||||
isnot(newProgramActors[1], oldProgramActor,
|
||||
"The old program actor is not equal to the new second program actor.");
|
||||
});
|
||||
}
|
||||
|
||||
function checkHighlightingInTheFirstPage(programActor) {
|
||||
return Task.spawn(function() {
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
|
||||
ok(true, "The top left pixel color was correct before highlighting.");
|
||||
|
||||
yield programActor.highlight([0, 0, 1, 1]);
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true);
|
||||
ok(true, "The top left pixel color is correct after highlighting.");
|
||||
|
||||
yield programActor.unhighlight();
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
|
||||
ok(true, "The top left pixel color is correct after unhighlighting.");
|
||||
});
|
||||
}
|
||||
|
||||
function checkHighlightingInTheSecondPage(firstProgramActor, secondProgramActor) {
|
||||
return Task.spawn(function() {
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
|
||||
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
|
||||
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
|
||||
ok(true, "The two canvases are correctly drawn before highlighting.");
|
||||
|
||||
yield firstProgramActor.highlight([1, 0, 0, 1]);
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
|
||||
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
|
||||
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
|
||||
ok(true, "The first canvas was correctly filled after highlighting.");
|
||||
|
||||
yield secondProgramActor.highlight([0, 1, 0, 1]);
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2");
|
||||
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
|
||||
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2");
|
||||
ok(true, "The second canvas was correctly filled after highlighting.");
|
||||
|
||||
yield firstProgramActor.unhighlight();
|
||||
yield secondProgramActor.unhighlight();
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
|
||||
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
|
||||
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
|
||||
ok(true, "The two canvases were correctly filled after unhighlighting.");
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests if program actors are invalidated from the cache when a window is
|
||||
* removed from the bfcache.
|
||||
*/
|
||||
|
||||
function ifWebGLSupported() {
|
||||
let [target, debuggee, front] = yield initBackend(SIMPLE_CANVAS_URL);
|
||||
front.setup({ reload: false });
|
||||
|
||||
reload(target);
|
||||
let firstProgram = yield once(front, "program-linked");
|
||||
|
||||
navigate(target, MULTIPLE_CONTEXTS_URL);
|
||||
let secondProgram = yield once(front, "program-linked");
|
||||
let thirdProgram = yield once(front, "program-linked");
|
||||
|
||||
yield navigateInHistory(target, "back");
|
||||
let globalDestroyed = observe("inner-window-destroyed");
|
||||
let globalCreated = observe("content-document-global-created");
|
||||
reload(target);
|
||||
|
||||
yield globalDestroyed;
|
||||
let programs = yield front.getPrograms();
|
||||
is(programs.length, 0,
|
||||
"There should be no cached program actors yet.");
|
||||
|
||||
yield globalCreated;
|
||||
let programs = yield front.getPrograms();
|
||||
is(programs.length, 1,
|
||||
"There should be 1 cached program actor now.");
|
||||
|
||||
yield checkHighlightingInTheFirstPage(programs[0]);
|
||||
ok(true, "The cached programs behave correctly after navigating back and reloading.");
|
||||
|
||||
yield navigateInHistory(target, "forward");
|
||||
let globalDestroyed = observe("inner-window-destroyed");
|
||||
let globalCreated = observe("content-document-global-created");
|
||||
reload(target);
|
||||
|
||||
yield globalDestroyed;
|
||||
let programs = yield front.getPrograms();
|
||||
is(programs.length, 0,
|
||||
"There should be no cached program actors yet.");
|
||||
|
||||
yield globalCreated;
|
||||
let programs = yield front.getPrograms();
|
||||
is(programs.length, 2,
|
||||
"There should be 2 cached program actors now.");
|
||||
|
||||
yield checkHighlightingInTheSecondPage(programs[0], programs[1]);
|
||||
ok(true, "The cached programs behave correctly after navigating forward and reloading.");
|
||||
|
||||
yield removeTab(target.tab);
|
||||
finish();
|
||||
|
||||
function checkHighlightingInTheFirstPage(programActor) {
|
||||
return Task.spawn(function() {
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
|
||||
ok(true, "The top left pixel color was correct before highlighting.");
|
||||
|
||||
yield programActor.highlight([0, 0, 1, 1]);
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 0, b: 255, a: 255 }, true);
|
||||
ok(true, "The top left pixel color is correct after highlighting.");
|
||||
|
||||
yield programActor.unhighlight();
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true);
|
||||
ok(true, "The top left pixel color is correct after unhighlighting.");
|
||||
});
|
||||
}
|
||||
|
||||
function checkHighlightingInTheSecondPage(firstProgramActor, secondProgramActor) {
|
||||
return Task.spawn(function() {
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
|
||||
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
|
||||
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
|
||||
ok(true, "The two canvases are correctly drawn before highlighting.");
|
||||
|
||||
yield firstProgramActor.highlight([1, 0, 0, 1]);
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
|
||||
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
|
||||
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
|
||||
ok(true, "The first canvas was correctly filled after highlighting.");
|
||||
|
||||
yield secondProgramActor.highlight([0, 1, 0, 1]);
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2");
|
||||
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 0, b: 0, a: 255 }, true, "#canvas1");
|
||||
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 0, a: 255 }, true, "#canvas2");
|
||||
ok(true, "The second canvas was correctly filled after highlighting.");
|
||||
|
||||
yield firstProgramActor.unhighlight();
|
||||
yield secondProgramActor.unhighlight();
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
|
||||
yield ensurePixelIs(debuggee, { x: 0, y: 0 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
|
||||
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 255, g: 255, b: 0, a: 255 }, true, "#canvas1");
|
||||
yield ensurePixelIs(debuggee, { x: 127, y: 127 }, { r: 0, g: 255, b: 255, a: 255 }, true, "#canvas2");
|
||||
ok(true, "The two canvases were correctly filled after unhighlighting.");
|
||||
});
|
||||
}
|
||||
}
|
@ -133,6 +133,19 @@ function once(aTarget, aEventName, aUseCapture = false) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function observe(aNotificationName, aOwnsWeak = false) {
|
||||
info("Waiting for observer notification: '" + aNotificationName + ".");
|
||||
|
||||
let deferred = promise.defer();
|
||||
|
||||
Services.obs.addObserver(function onNotification(...aArgs) {
|
||||
Services.obs.removeObserver(onNotification, aNotificationName);
|
||||
deferred.resolve.apply(deferred, aArgs);
|
||||
}, aNotificationName, aOwnsWeak);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function waitForFrame(aDebuggee) {
|
||||
let deferred = promise.defer();
|
||||
aDebuggee.requestAnimationFrame(deferred.resolve);
|
||||
@ -193,16 +206,19 @@ function ensurePixelIs(aDebuggee, aPosition, aColor, aWaitFlag = false, aSelecto
|
||||
return promise.reject(null);
|
||||
}
|
||||
|
||||
function navigate(aTarget, aUrl) {
|
||||
let navigated = once(aTarget, "navigate");
|
||||
aTarget.client.activeTab.navigateTo(aUrl);
|
||||
return navigated;
|
||||
function navigateInHistory(aTarget, aDirection, aWaitForTargetEvent = "navigate") {
|
||||
executeSoon(() => content.history[aDirection]());
|
||||
return once(aTarget, aWaitForTargetEvent);
|
||||
}
|
||||
|
||||
function reload(aTarget) {
|
||||
let navigated = once(aTarget, "navigate");
|
||||
function navigate(aTarget, aUrl, aWaitForTargetEvent = "navigate") {
|
||||
executeSoon(() => aTarget.client.activeTab.navigateTo(aUrl));
|
||||
return once(aTarget, aWaitForTargetEvent);
|
||||
}
|
||||
|
||||
function reload(aTarget, aWaitForTargetEvent = "navigate") {
|
||||
executeSoon(() => aTarget.client.activeTab.reload());
|
||||
return navigated;
|
||||
return once(aTarget, aWaitForTargetEvent);
|
||||
}
|
||||
|
||||
function initBackend(aUrl) {
|
||||
|
@ -181,6 +181,10 @@ Tooltip.prototype = {
|
||||
this.stopTogglingOnHover();
|
||||
}
|
||||
|
||||
// If no targetNodeCb callback is provided, then we need to hide the tooltip
|
||||
// on mouseleave since baseNode is the target node itself
|
||||
this._hideOnMouseLeave = !targetNodeCb;
|
||||
|
||||
this._basedNode = baseNode;
|
||||
this._showDelay = showDelay;
|
||||
this._targetNodeCb = targetNodeCb || (() => true);
|
||||
@ -221,7 +225,7 @@ Tooltip.prototype = {
|
||||
},
|
||||
|
||||
_showOnHover: function(target) {
|
||||
if (this._targetNodeCb && this._targetNodeCb(target, this)) {
|
||||
if (this._targetNodeCb(target, this)) {
|
||||
this.show(target);
|
||||
this._lastHovered = target;
|
||||
}
|
||||
@ -230,6 +234,9 @@ Tooltip.prototype = {
|
||||
_onBaseNodeMouseLeave: function() {
|
||||
clearNamedTimeout(this.uid);
|
||||
this._lastHovered = null;
|
||||
if (this._hideOnMouseLeave) {
|
||||
this.hide();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -49,8 +49,6 @@ let Svc = {};
|
||||
XPCOMUtils.defineLazyServiceGetter(Svc, 'mime',
|
||||
'@mozilla.org/mime;1', 'nsIMIMEService');
|
||||
|
||||
let profiler = Cc["@mozilla.org/tools/profiler;1"].getService(Ci.nsIProfiler);
|
||||
|
||||
function getBoolPref(pref, def) {
|
||||
try {
|
||||
return Services.prefs.getBoolPref(pref);
|
||||
@ -222,7 +220,10 @@ ChromeActions.prototype = {
|
||||
});
|
||||
},
|
||||
addProfilerMarker: function (marker) {
|
||||
profiler.AddMarker(marker);
|
||||
if ('nsIProfiler' in Ci) {
|
||||
let profiler = Cc["@mozilla.org/tools/profiler;1"].getService(Ci.nsIProfiler);
|
||||
profiler.AddMarker(marker);
|
||||
}
|
||||
},
|
||||
getPluginParams: function getPluginParams() {
|
||||
return JSON.stringify({
|
||||
|
@ -1 +1 @@
|
||||
0.7.501
|
||||
0.7.502
|
||||
|
@ -15,9 +15,9 @@
|
||||
- in the network table when empty. -->
|
||||
<!ENTITY netmonitorUI.emptyNotice2 "Perform a request or reload the page to see detailed information about network activity.">
|
||||
|
||||
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.status): This is the label displayed
|
||||
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.status2): This is the label displayed
|
||||
- in the network table toolbar, above the "status" column. -->
|
||||
<!ENTITY netmonitorUI.toolbar.status "√">
|
||||
<!ENTITY netmonitorUI.toolbar.status2 "✓">
|
||||
|
||||
<!-- LOCALIZATION NOTE (netmonitorUI.toolbar.method): This is the label displayed
|
||||
- in the network table toolbar, above the "method" column. -->
|
||||
|
@ -35,6 +35,8 @@ const TOPIC_TIMER_CALLBACK = "timer-callback";
|
||||
const TOPIC_DELAYED_STARTUP = "browser-delayed-startup-finished";
|
||||
const TOPIC_XUL_WINDOW_CLOSED = "xul-window-destroyed";
|
||||
|
||||
const FRAME_SCRIPT_URL = "chrome://browser/content/newtab/preloaderContent.js";
|
||||
|
||||
function createTimer(obj, delay) {
|
||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.init(obj, delay, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
@ -61,6 +63,7 @@ this.BrowserNewTabPreloader = {
|
||||
},
|
||||
|
||||
newTab: function Preloader_newTab(aTab) {
|
||||
let swapped = false;
|
||||
let win = aTab.ownerDocument.defaultView;
|
||||
if (win.gBrowser) {
|
||||
let utils = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
@ -69,11 +72,17 @@ this.BrowserNewTabPreloader = {
|
||||
let {width, height} = utils.getBoundsWithoutFlushing(win.gBrowser);
|
||||
let hiddenBrowser = HiddenBrowsers.get(width, height)
|
||||
if (hiddenBrowser) {
|
||||
return hiddenBrowser.swapWithNewTab(aTab);
|
||||
swapped = hiddenBrowser.swapWithNewTab(aTab);
|
||||
}
|
||||
|
||||
// aTab's browser is now visible and is therefore allowed to make
|
||||
// background captures.
|
||||
let msgMan = aTab.linkedBrowser.messageManager;
|
||||
msgMan.loadFrameScript(FRAME_SCRIPT_URL, false);
|
||||
msgMan.sendAsyncMessage("BrowserNewTabPreloader:allowBackgroundCaptures");
|
||||
}
|
||||
|
||||
return false;
|
||||
return swapped;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -50,6 +50,7 @@ html|*.highlighter-nodeinfobar-pseudo-classes {
|
||||
|
||||
.highlighter-nodeinfobar-button {
|
||||
-moz-appearance: none;
|
||||
border-width: 0;
|
||||
padding: 0;
|
||||
width: 26px;
|
||||
min-height: 26px;
|
||||
|
@ -68,14 +68,14 @@ function submitForm(idNum) {
|
||||
|
||||
function submitFormMouse(idNum) {
|
||||
$("test"+idNum).setAttribute("onload", "frameLoaded(this)");
|
||||
// Use 4.999 instead of 5 to guard against the possibility that the
|
||||
// Use 4.99 instead of 5 to guard against the possibility that the
|
||||
// image's 'top' is exactly N + 0.5 pixels from the root. In that case
|
||||
// we'd round up the widget mouse coordinate to N + 6, which relative
|
||||
// to the image would be 5.5, which would get rounded up to 6 when
|
||||
// submitting the form. Instead we round the widget mouse coordinate to
|
||||
// N + 5, which relative to the image would be 4.5 which gets rounded up
|
||||
// to 5.
|
||||
synthesizeMouse($("test" + idNum + "image"), 4.999, 4.999, {});
|
||||
synthesizeMouse($("test" + idNum + "image"), 4.99, 4.99, {});
|
||||
}
|
||||
|
||||
addLoadEvent(function() {
|
||||
|
@ -651,6 +651,9 @@ static const dom::ConstantSpec gWinProperties[] =
|
||||
INT_CONSTANT(MOVEFILE_COPY_ALLOWED),
|
||||
INT_CONSTANT(MOVEFILE_REPLACE_EXISTING),
|
||||
|
||||
// GetFileAttributes error constant
|
||||
INT_CONSTANT(INVALID_FILE_ATTRIBUTES),
|
||||
|
||||
// Errors
|
||||
INT_CONSTANT(ERROR_ACCESS_DENIED),
|
||||
INT_CONSTANT(ERROR_DIR_NOT_EMPTY),
|
||||
|
@ -134,7 +134,8 @@ Object.defineProperty(OSError.prototype, "becauseExists", {
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseNoSuchFile", {
|
||||
get: function becauseNoSuchFile() {
|
||||
return this.winLastError == Const.ERROR_FILE_NOT_FOUND;
|
||||
return this.winLastError == Const.ERROR_FILE_NOT_FOUND ||
|
||||
this.winLastError == Const.ERROR_PATH_NOT_FOUND;
|
||||
}
|
||||
});
|
||||
/**
|
||||
|
@ -345,6 +345,17 @@
|
||||
"FlushFileBuffers", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*file*/ Type.HANDLE);
|
||||
|
||||
declareLazyFFI(SysFile, "GetFileAttributes", libc,
|
||||
"GetFileAttributesW", ctypes.winapi_abi,
|
||||
/*return*/ Type.DWORD,
|
||||
/*fileName*/ Type.path);
|
||||
|
||||
declareLazyFFI(SysFile, "SetFileAttributes", libc,
|
||||
"SetFileAttributesW", ctypes.winapi_abi,
|
||||
/*return*/ Type.zero_or_nothing,
|
||||
/*fileName*/ Type.path,
|
||||
/*fileAttributes*/ Type.DWORD);
|
||||
};
|
||||
|
||||
exports.OS.Win = {
|
||||
|
@ -382,14 +382,27 @@
|
||||
* @throws {OS.File.Error} In case of I/O error.
|
||||
*/
|
||||
File.remove = function remove(path, options = {}) {
|
||||
let result = WinFile.DeleteFile(path);
|
||||
if (!result) {
|
||||
if ((!("ignoreAbsent" in options) || options.ignoreAbsent) &&
|
||||
ctypes.winLastError == Const.ERROR_FILE_NOT_FOUND) {
|
||||
if (WinFile.DeleteFile(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctypes.winLastError == Const.ERROR_FILE_NOT_FOUND) {
|
||||
if ((!("ignoreAbsent" in options) || options.ignoreAbsent)) {
|
||||
return;
|
||||
}
|
||||
throw new File.Error("remove");
|
||||
} else if (ctypes.winLastError == Const.ERROR_ACCESS_DENIED) {
|
||||
let attributes = WinFile.GetFileAttributes(path);
|
||||
if (attributes != Const.INVALID_FILE_ATTRIBUTES &&
|
||||
attributes & Const.FILE_ATTRIBUTE_READONLY) {
|
||||
let newAttributes = attributes & ~Const.FILE_ATTRIBUTE_READONLY;
|
||||
if (WinFile.SetFileAttributes(path, newAttributes) &&
|
||||
WinFile.DeleteFile(path)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new File.Error("remove");
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -151,7 +151,6 @@ let test = maketest("Main", function main(test) {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
yield test_constants();
|
||||
yield test_path();
|
||||
yield test_open();
|
||||
yield test_stat();
|
||||
yield test_debug();
|
||||
yield test_info_features_detect();
|
||||
@ -199,50 +198,6 @@ let test_path = maketest("path", function path(test) {
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test OS.File.open for reading:
|
||||
* - with an existing file (should succeed);
|
||||
* - with a non-existing file (should fail);
|
||||
* - with inconsistent arguments (should fail).
|
||||
*/
|
||||
let test_open = maketest("open", function open(test) {
|
||||
return Task.spawn(function() {
|
||||
// Attempt to open a file that does not exist, ensure that it yields the
|
||||
// appropriate error.
|
||||
try {
|
||||
let fd = yield OS.File.open(OS.Path.join(".", "This file does not exist"));
|
||||
test.ok(false, "File opening 1 succeeded (it should fail)" + fd);
|
||||
} catch (err) {
|
||||
test.ok(true, "File opening 1 failed " + err);
|
||||
test.ok(err instanceof OS.File.Error, "File opening 1 returned a file error");
|
||||
test.ok(err.becauseNoSuchFile, "File opening 1 informed that the file does not exist");
|
||||
}
|
||||
|
||||
// Attempt to open a file with the wrong args, so that it fails before
|
||||
// serialization, ensure that it yields the appropriate error.
|
||||
test.info("Attempting to open a file with wrong arguments");
|
||||
try {
|
||||
let fd = yield OS.File.open(1, 2, 3);
|
||||
test.ok(false, "File opening 2 succeeded (it should fail)" + fd);
|
||||
} catch (err) {
|
||||
test.ok(true, "File opening 2 failed " + err);
|
||||
test.ok(!(err instanceof OS.File.Error), "File opening 2 returned something that is not a file error");
|
||||
test.ok(err.constructor.name == "TypeError", "File opening 2 returned a TypeError");
|
||||
}
|
||||
|
||||
// Attempt to open a file correctly
|
||||
test.info("Attempting to open a file correctly");
|
||||
let openedFile = yield OS.File.open(EXISTING_FILE);
|
||||
test.ok(true, "File opened correctly");
|
||||
|
||||
test.info("Attempting to close a file correctly");
|
||||
yield openedFile.close();
|
||||
|
||||
test.info("Attempting to close a file again");
|
||||
yield openedFile.close();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Test OS.File.stat and OS.File.prototype.stat
|
||||
*/
|
||||
|
@ -844,4 +844,16 @@ function test_remove_file()
|
||||
OS.File.remove(absent_file_name);
|
||||
});
|
||||
ok(!exn, "test_remove_file: ignoreAbsent works");
|
||||
|
||||
if (OS.Win) {
|
||||
let file_name = "test_osfile_front_file_to_remove.tmp";
|
||||
let file = OS.File.open(file_name, {write: true});
|
||||
file.close();
|
||||
ok(OS.File.exists(file_name), "test_remove_file: test file exists");
|
||||
OS.Win.File.SetFileAttributes(file_name,
|
||||
OS.Constants.Win.FILE_ATTRIBUTE_READONLY);
|
||||
OS.File.remove(file_name);
|
||||
ok(!OS.File.exists(file_name),
|
||||
"test_remove_file: test file has been removed");
|
||||
}
|
||||
}
|
||||
|
75
toolkit/components/osfile/tests/xpcshell/test_open.js
Normal file
75
toolkit/components/osfile/tests/xpcshell/test_open.js
Normal file
@ -0,0 +1,75 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test OS.File.open for reading:
|
||||
* - with an existing file (should succeed);
|
||||
* - with a non-existing file (should fail);
|
||||
* - with inconsistent arguments (should fail).
|
||||
*/
|
||||
add_task(function() {
|
||||
// Attempt to open a file that does not exist, ensure that it yields the
|
||||
// appropriate error.
|
||||
try {
|
||||
let fd = yield OS.File.open(OS.Path.join(".", "This file does not exist"));
|
||||
do_check_true(false, "File opening 1 succeeded (it should fail)");
|
||||
} catch (err if err instanceof OS.File.Error && err.becauseNoSuchFile) {
|
||||
do_print("File opening 1 failed " + err);
|
||||
}
|
||||
|
||||
// Attempt to open a file with the wrong args, so that it fails before
|
||||
// serialization, ensure that it yields the appropriate error.
|
||||
do_print("Attempting to open a file with wrong arguments");
|
||||
try {
|
||||
let fd = yield OS.File.open(1, 2, 3);
|
||||
do_check_true(false, "File opening 2 succeeded (it should fail)" + fd);
|
||||
} catch (err) {
|
||||
do_print("File opening 2 failed " + err);
|
||||
do_check_false(err instanceof OS.File.Error,
|
||||
"File opening 2 returned something that is not a file error");
|
||||
do_check_true(err.constructor.name == "TypeError",
|
||||
"File opening 2 returned a TypeError");
|
||||
}
|
||||
|
||||
// Attempt to open a file correctly
|
||||
do_print("Attempting to open a file correctly");
|
||||
let openedFile = yield OS.File.open(OS.Path.join(do_get_cwd().path, "test_open.js"));
|
||||
do_print("File opened correctly");
|
||||
|
||||
do_print("Attempting to close a file correctly");
|
||||
yield openedFile.close();
|
||||
|
||||
do_print("Attempting to close a file again");
|
||||
yield openedFile.close();
|
||||
});
|
||||
|
||||
/**
|
||||
* Test the error thrown by OS.File.open when attempting to open a directory
|
||||
* that does not exist.
|
||||
*/
|
||||
add_task(function test_error_attributes () {
|
||||
|
||||
let dir = OS.Path.join(do_get_profile().path, "test_osfileErrorAttrs");
|
||||
let fpath = OS.Path.join(dir, "test_error_attributes.txt");
|
||||
|
||||
try {
|
||||
yield OS.File.open(fpath, {truncate: true}, {});
|
||||
do_check_true(false, "Opening path suceeded (it should fail) " + fpath);
|
||||
} catch (err) {
|
||||
do_check_true(err instanceof OS.File.Error);
|
||||
do_check_true(err.becauseNoSuchFile);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function() {
|
||||
do_test_finished();
|
||||
});
|
@ -19,3 +19,4 @@ tail =
|
||||
[test_reset.js]
|
||||
[test_shutdown.js]
|
||||
[test_unique.js]
|
||||
[test_open.js]
|
||||
|
@ -1,9 +1,27 @@
|
||||
/*
|
||||
* Initialization: for each test, remove any prior notifications.
|
||||
*/
|
||||
function cleanUpPopupNotifications() {
|
||||
var container = getPopupNotifications(window.top);
|
||||
var notes = container._currentNotifications;
|
||||
info(true, "Removing " + notes.length + " popup notifications.");
|
||||
for (var i = notes.length-1; i >= 0; i--) {
|
||||
notes[i].remove();
|
||||
}
|
||||
}
|
||||
cleanUpPopupNotifications();
|
||||
|
||||
/*
|
||||
* getPopupNotifications
|
||||
*
|
||||
* Fetches the popup notification for the specified window.
|
||||
*/
|
||||
function getPopupNotifications(aWindow) {
|
||||
var Ci = SpecialPowers.Ci;
|
||||
var Cc = SpecialPowers.Cc;
|
||||
ok(Ci != null, "Access Ci");
|
||||
ok(Cc != null, "Access Cc");
|
||||
|
||||
var chromeWin = SpecialPowers.wrap(aWindow)
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
|
@ -1190,8 +1190,8 @@ Engine.prototype = {
|
||||
_updateURL: null,
|
||||
// The url to check for a new icon
|
||||
_iconUpdateURL: null,
|
||||
// A reference to the timer used for lazily serializing the engine to file
|
||||
_serializeTimer: null,
|
||||
/* Deferred serialization task. */
|
||||
_lazySerializeTask: null,
|
||||
|
||||
/**
|
||||
* Retrieves the data from the engine's file. If the engine's dataType is
|
||||
@ -2244,28 +2244,15 @@ Engine.prototype = {
|
||||
return doc;
|
||||
},
|
||||
|
||||
_lazySerializeToFile: function SRCH_ENG_serializeToFile() {
|
||||
if (this._serializeTimer) {
|
||||
// Reset the timer
|
||||
this._serializeTimer.delay = LAZY_SERIALIZE_DELAY;
|
||||
} else {
|
||||
this._serializeTimer = Cc["@mozilla.org/timer;1"].
|
||||
createInstance(Ci.nsITimer);
|
||||
var timerCallback = {
|
||||
self: this,
|
||||
notify: function SRCH_ENG_notify(aTimer) {
|
||||
try {
|
||||
this.self._serializeToFile();
|
||||
} catch (ex) {
|
||||
LOG("Serialization from timer callback failed:\n" + ex);
|
||||
}
|
||||
this.self._serializeTimer = null;
|
||||
}
|
||||
};
|
||||
this._serializeTimer.initWithCallback(timerCallback,
|
||||
LAZY_SERIALIZE_DELAY,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
get lazySerializeTask() {
|
||||
if (!this._lazySerializeTask) {
|
||||
let task = function taskCallback() {
|
||||
this._serializeToFile();
|
||||
}.bind(this);
|
||||
this._lazySerializeTask = new DeferredTask(task, LAZY_SERIALIZE_DELAY);
|
||||
}
|
||||
|
||||
return this._lazySerializeTask;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -2296,6 +2283,9 @@ Engine.prototype = {
|
||||
}
|
||||
|
||||
closeSafeOutputStream(fos);
|
||||
|
||||
Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC,
|
||||
"write-engine-to-disk-complete");
|
||||
},
|
||||
|
||||
/**
|
||||
@ -2541,7 +2531,7 @@ Engine.prototype = {
|
||||
url.addParam(aName, aValue);
|
||||
|
||||
// Serialize the changes to file lazily
|
||||
this._lazySerializeToFile();
|
||||
this.lazySerializeTask.start();
|
||||
},
|
||||
|
||||
#ifdef ANDROID
|
||||
@ -2895,25 +2885,17 @@ SearchService.prototype = {
|
||||
return false;
|
||||
},
|
||||
|
||||
_batchTimer: null,
|
||||
_batchCacheInvalidation: function SRCH_SVC__batchCacheInvalidation() {
|
||||
let callback = {
|
||||
self: this,
|
||||
notify: function SRCH_SVC_batchTimerNotify(aTimer) {
|
||||
LOG("_batchCacheInvalidation: Invalidating engine cache");
|
||||
this.self._buildCache();
|
||||
this.self._batchTimer = null;
|
||||
}
|
||||
};
|
||||
|
||||
if (!this._batchTimer) {
|
||||
this._batchTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
this._batchTimer.initWithCallback(callback, CACHE_INVALIDATION_DELAY,
|
||||
Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
} else {
|
||||
this._batchTimer.delay = CACHE_INVALIDATION_DELAY;
|
||||
LOG("_batchCacheInvalidation: Batch timer reset");
|
||||
_batchTask: null,
|
||||
get batchTask() {
|
||||
if (!this._batchTask) {
|
||||
let task = function taskCallback() {
|
||||
LOG("batchTask: Invalidating engine cache");
|
||||
this._buildCache();
|
||||
}.bind(this);
|
||||
this._batchTask = new DeferredTask(task, CACHE_INVALIDATION_DELAY);
|
||||
}
|
||||
|
||||
return this._batchTask;
|
||||
},
|
||||
|
||||
_addEngineToStore: function SRCH_SVC_addEngineToStore(aEngine) {
|
||||
@ -3403,7 +3385,7 @@ SearchService.prototype = {
|
||||
engine._initFromMetadata(aName, aIconURL, aAlias, aDescription,
|
||||
aMethod, aTemplate);
|
||||
this._addEngineToStore(engine);
|
||||
this._batchCacheInvalidation();
|
||||
this.batchTask.start();
|
||||
},
|
||||
|
||||
addEngine: function SRCH_SVC_addEngine(aEngineURL, aDataType, aIconURL,
|
||||
@ -3466,10 +3448,10 @@ SearchService.prototype = {
|
||||
engineToRemove.hidden = true;
|
||||
engineToRemove.alias = null;
|
||||
} else {
|
||||
// Cancel the lazy serialization timer if it's running
|
||||
if (engineToRemove._serializeTimer) {
|
||||
engineToRemove._serializeTimer.cancel();
|
||||
engineToRemove._serializeTimer = null;
|
||||
// Cancel the serialized task if it's running
|
||||
if (engineToRemove._lazySerializeTask) {
|
||||
engineToRemove._lazySerializeTask.cancel();
|
||||
engineToRemove._lazySerializeTask = null;
|
||||
}
|
||||
|
||||
// Remove the engine file from disk (this might throw)
|
||||
@ -3667,21 +3649,20 @@ SearchService.prototype = {
|
||||
LOG("nsSearchService::observe: setting current");
|
||||
this.currentEngine = aEngine;
|
||||
}
|
||||
this._batchCacheInvalidation();
|
||||
this.batchTask.start();
|
||||
break;
|
||||
case SEARCH_ENGINE_CHANGED:
|
||||
case SEARCH_ENGINE_REMOVED:
|
||||
this._batchCacheInvalidation();
|
||||
this.batchTask.start();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case QUIT_APPLICATION_TOPIC:
|
||||
this._removeObservers();
|
||||
if (this._batchTimer) {
|
||||
if (this._batchTask) {
|
||||
// Flush to disk immediately
|
||||
this._batchTimer.cancel();
|
||||
this._buildCache();
|
||||
this._batchTask.flush();
|
||||
}
|
||||
engineMetadataService.flush();
|
||||
break;
|
||||
|
@ -0,0 +1,88 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/*
|
||||
* test_serialize_file: Add test engines
|
||||
*
|
||||
* Ensure that :
|
||||
* - File is created.
|
||||
* - File size is bigger than 0.
|
||||
* - lazySerializeTask updates the file.
|
||||
*/
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
add_test(function test_batchTask() {
|
||||
let observer = function(aSubject, aTopic, aData) {
|
||||
if (aTopic == "browser-search-engine-modified" && aData == "engine-loaded") {
|
||||
let engine1 = Services.search.getEngineByName("Test search engine");
|
||||
let engine2 = Services.search.getEngineByName("Sherlock test search engine");
|
||||
if (engine1 && engine2) {
|
||||
Services.obs.removeObserver(observer, aTopic);
|
||||
// Test that files are written correctly.
|
||||
let engineFile1 = engine1.wrappedJSObject._file;
|
||||
let engineFile2 = engine2.wrappedJSObject._file;
|
||||
do_check_true(engineFile1.exists());
|
||||
do_check_true(engineFile2.exists());
|
||||
do_check_neq(engineFile1.fileSize, 0);
|
||||
do_check_neq(engineFile2.fileSize, 0);
|
||||
run_next_test();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
|
||||
Services.search.addEngine("http://localhost:4444/data/engine.xml",
|
||||
Ci.nsISearchEngine.DATA_XML, null, false);
|
||||
Services.search.addEngine("http://localhost:4444/data/engine.src",
|
||||
Ci.nsISearchEngine.DATA_TEXT,
|
||||
"http://localhost:4444/data/ico-size-16x16-png.ico",
|
||||
false);
|
||||
});
|
||||
|
||||
add_test(function test_addParam() {
|
||||
let engine = Services.search.getEngineByName("Test search engine");
|
||||
engine.addParam("param-name", "param-value", null);
|
||||
|
||||
function readAsyncFile(aFile, aCallback) {
|
||||
NetUtil.asyncFetch(aFile, function(inputStream, status) {
|
||||
do_check_true(Components.isSuccessCode(status));
|
||||
|
||||
let data = NetUtil.readInputStreamToString(inputStream, inputStream.available());
|
||||
aCallback(data);
|
||||
});
|
||||
}
|
||||
|
||||
let observer = function(aSubject, aTopic, aData) {
|
||||
if (aTopic == "browser-search-service" &&
|
||||
aData == "write-engine-to-disk-complete") {
|
||||
Services.obs.removeObserver(observer, aTopic);
|
||||
|
||||
let engineFile = engine.wrappedJSObject._file;
|
||||
|
||||
readAsyncFile(engineFile, function(engineData) {
|
||||
do_check_true(engineData.indexOf("param-name") > 0);
|
||||
run_next_test();
|
||||
});
|
||||
}
|
||||
}
|
||||
Services.obs.addObserver(observer, "browser-search-service", false);
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
updateAppInfo();
|
||||
|
||||
let httpServer = new HttpServer();
|
||||
httpServer.start(4444);
|
||||
httpServer.registerDirectory("/", do_get_cwd());
|
||||
|
||||
do_register_cleanup(function cleanup() {
|
||||
httpServer.stop(function() {});
|
||||
});
|
||||
|
||||
run_next_test();
|
||||
}
|
@ -28,3 +28,4 @@ support-files =
|
||||
[test_prefSync.js]
|
||||
[test_notifications.js]
|
||||
[test_addEngine_callback.js]
|
||||
[test_serialize_file.js]
|
||||
|
@ -27,6 +27,8 @@ loader:
|
||||
5. Prepend `module.exports = ` to the package.json file contents, so that the
|
||||
JSON data is exported, and we can load package.json as a module.
|
||||
|
||||
Bug 933482: Note, this is a workaround for Bug 910594, which will allow the SDK loader to require JSON files. To remove ambiguity, comment out the `require('./package.json').version` line in `escodegen.js` so that when Bug 910594 is uplifted into central, it does not attempt to look for `package.json`, rather than `package.json.js`. This is a temporary workaround, and once Bug 933500 is solved, either `package.json` or `package.json.js` will work.
|
||||
|
||||
6. Copy the estraverse.js that escodegen depends on into our tree:
|
||||
|
||||
$ cp node_modules/estraverse/estraverse.js /path/to/mozilla-central/devtools/escodegen/estraverse.js
|
||||
|
@ -2055,7 +2055,7 @@
|
||||
|
||||
FORMAT_DEFAULTS = getDefaultOptions().format;
|
||||
|
||||
exports.version = require('./package.json').version;
|
||||
// exports.version = require('./package.json').version;
|
||||
exports.generate = generate;
|
||||
exports.attachComments = estraverse.attachComments;
|
||||
exports.browser = false;
|
||||
|
@ -184,7 +184,9 @@ let WebGLActor = exports.WebGLActor = protocol.ActorClass({
|
||||
protocol.Actor.prototype.initialize.call(this, conn);
|
||||
this.tabActor = tabActor;
|
||||
this._onGlobalCreated = this._onGlobalCreated.bind(this);
|
||||
this._onGlobalDestroyed = this._onGlobalDestroyed.bind(this);
|
||||
this._onProgramLinked = this._onProgramLinked.bind(this);
|
||||
this._programActorsCache = [];
|
||||
},
|
||||
destroy: function(conn) {
|
||||
protocol.Actor.prototype.destroy.call(this, conn);
|
||||
@ -198,7 +200,7 @@ let WebGLActor = exports.WebGLActor = protocol.ActorClass({
|
||||
*
|
||||
* See ContentObserver and WebGLInstrumenter for more details.
|
||||
*/
|
||||
setup: method(function() {
|
||||
setup: method(function({ reload }) {
|
||||
if (this._initialized) {
|
||||
return;
|
||||
}
|
||||
@ -206,10 +208,14 @@ let WebGLActor = exports.WebGLActor = protocol.ActorClass({
|
||||
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._webglObserver, "program-linked", this._onProgramLinked);
|
||||
|
||||
this.tabActor.window.location.reload();
|
||||
if (reload) {
|
||||
this.tabActor.window.location.reload();
|
||||
}
|
||||
}, {
|
||||
request: { reload: Option(0, "boolean") },
|
||||
oneway: true
|
||||
}),
|
||||
|
||||
@ -225,11 +231,23 @@ 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._webglObserver, "program-linked", this._onProgramLinked);
|
||||
}, {
|
||||
oneway: true
|
||||
}),
|
||||
|
||||
/**
|
||||
* Gets an array of cached program actors for the current tab actor's window.
|
||||
* This is useful for dealing with bfcache, when no new programs are linked.
|
||||
*/
|
||||
getPrograms: method(function() {
|
||||
let id = getInnerWindowID(this.tabActor.window);
|
||||
return this._programActorsCache.filter(e => e.owner == id).map(e => e.actor);
|
||||
}, {
|
||||
response: { programs: RetVal("array:gl-program") }
|
||||
}),
|
||||
|
||||
/**
|
||||
* Events emitted by this actor. The "program-linked" event is fired
|
||||
* every time a WebGL program was linked with its respective two shaders.
|
||||
@ -248,6 +266,14 @@ let WebGLActor = exports.WebGLActor = protocol.ActorClass({
|
||||
WebGLInstrumenter.handle(window, this._webglObserver);
|
||||
},
|
||||
|
||||
/**
|
||||
* Invoked whenever the current tab actor's inner window is destroyed.
|
||||
*/
|
||||
_onGlobalDestroyed: function(id) {
|
||||
this._programActorsCache =
|
||||
this._programActorsCache.filter(e => e.owner != id);
|
||||
},
|
||||
|
||||
/**
|
||||
* Invoked whenever the current WebGL context links a program.
|
||||
*/
|
||||
@ -275,6 +301,11 @@ let WebGLActor = exports.WebGLActor = protocol.ActorClass({
|
||||
programActor.program = program;
|
||||
programActor.shadersData = shadersData;
|
||||
|
||||
this._programActorsCache.push({
|
||||
owner: getInnerWindowID(this.tabActor.window),
|
||||
actor: programActor
|
||||
});
|
||||
|
||||
events.emit(this, "program-linked", programActor);
|
||||
}
|
||||
});
|
||||
@ -297,8 +328,9 @@ let WebGLFront = exports.WebGLFront = protocol.FrontClass(WebGLActor, {
|
||||
* instrument the HTMLCanvasElement with the appropriate inspection methods.
|
||||
*/
|
||||
function ContentObserver(tabActor) {
|
||||
this._contentWindow = tabActor.browser.contentWindow;
|
||||
this._contentWindow = tabActor.window;
|
||||
this._onContentGlobalCreated = this._onContentGlobalCreated.bind(this);
|
||||
this._onInnerWindowDestroyed = this._onInnerWindowDestroyed.bind(this);
|
||||
this.startListening();
|
||||
}
|
||||
|
||||
@ -309,6 +341,8 @@ ContentObserver.prototype = {
|
||||
startListening: function() {
|
||||
Services.obs.addObserver(
|
||||
this._onContentGlobalCreated, "content-document-global-created", false);
|
||||
Services.obs.addObserver(
|
||||
this._onInnerWindowDestroyed, "inner-window-destroyed", false);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -317,6 +351,8 @@ ContentObserver.prototype = {
|
||||
stopListening: function() {
|
||||
Services.obs.removeObserver(
|
||||
this._onContentGlobalCreated, "content-document-global-created", false);
|
||||
Services.obs.removeObserver(
|
||||
this._onInnerWindowDestroyed, "inner-window-destroyed", false);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -326,6 +362,14 @@ ContentObserver.prototype = {
|
||||
if (subject == this._contentWindow) {
|
||||
emit(this, "global-created", subject);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Fired when an inner window is removed from the backward/forward cache.
|
||||
*/
|
||||
_onInnerWindowDestroyed: function(subject, topic, data) {
|
||||
let id = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
|
||||
emit(this, "global-destroyed", id);
|
||||
}
|
||||
};
|
||||
|
||||
@ -849,3 +893,10 @@ WebGLProxy.prototype = {
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
function getInnerWindowID(window) {
|
||||
return window
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils)
|
||||
.currentInnerWindowID;
|
||||
}
|
||||
|
@ -177,16 +177,64 @@ let PendingErrors = {
|
||||
lineNumber: null
|
||||
};
|
||||
try { // Defend against non-enumerable values
|
||||
if (typeof error == "object" && error) {
|
||||
if (error && error instanceof Ci.nsIException) {
|
||||
// nsIException does things a little differently.
|
||||
try {
|
||||
// For starters |.toString()| does not only contain the message, but
|
||||
// also the top stack frame, and we don't really want that.
|
||||
value.message = error.message;
|
||||
} catch (ex) {
|
||||
// Ignore field
|
||||
}
|
||||
try {
|
||||
// All lowercase filename. ;)
|
||||
value.fileName = error.filename;
|
||||
} catch (ex) {
|
||||
// Ignore field
|
||||
}
|
||||
try {
|
||||
value.lineNumber = error.lineNumber;
|
||||
} catch (ex) {
|
||||
// Ignore field
|
||||
}
|
||||
} else if (typeof error == "object" && error) {
|
||||
for (let k of ["fileName", "stack", "lineNumber"]) {
|
||||
try { // Defend against fallible getters and string conversions
|
||||
let v = error[k];
|
||||
value[k] = v ? ("" + v):null;
|
||||
value[k] = v ? ("" + v) : null;
|
||||
} catch (ex) {
|
||||
// Ignore field
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!value.stack) {
|
||||
// |error| is not an Error (or Error-alike). Try to figure out the stack.
|
||||
let stack = null;
|
||||
if (error && error.location &&
|
||||
error.location instanceof Ci.nsIStackFrame) {
|
||||
// nsIException has full stack frames in the |.location| member.
|
||||
stack = error.location;
|
||||
} else {
|
||||
// Components.stack to the rescue!
|
||||
stack = Components.stack;
|
||||
// Remove those top frames that refer to Promise.jsm.
|
||||
while (stack) {
|
||||
if (!stack.filename.endsWith("/Promise.jsm")) {
|
||||
break;
|
||||
}
|
||||
stack = stack.caller;
|
||||
}
|
||||
}
|
||||
if (stack) {
|
||||
let frames = [];
|
||||
while (stack) {
|
||||
frames.push(stack);
|
||||
stack = stack.caller;
|
||||
}
|
||||
value.stack = frames.join("\n");
|
||||
}
|
||||
}
|
||||
} catch (ex) {
|
||||
// Ignore value
|
||||
}
|
||||
|
@ -757,14 +757,20 @@ function wait_for_uncaught(aMustAppear, aTimeout = undefined) {
|
||||
let make_string_rejection = function make_string_rejection() {
|
||||
let salt = (Math.random() * ( Math.pow(2, 24) - 1 ));
|
||||
let string = "This is an uncaught rejection " + salt;
|
||||
return {mustFind: [string], error: string};
|
||||
// Our error is not Error-like nor an nsIException, so the stack will
|
||||
// include the closure doing the actual rejection.
|
||||
return {mustFind: ["test_rejection_closure", string], error: string};
|
||||
};
|
||||
let make_num_rejection = function make_num_rejection() {
|
||||
let salt = (Math.random() * ( Math.pow(2, 24) - 1 ));
|
||||
return {mustFind: [salt], error: salt};
|
||||
// Our error is not Error-like nor an nsIException, so the stack will
|
||||
// include the closure doing the actual rejection.
|
||||
return {mustFind: ["test_rejection_closure", salt], error: salt};
|
||||
};
|
||||
let make_undefined_rejection = function make_undefined_rejection() {
|
||||
return {mustFind: [], error: undefined};
|
||||
// Our error is not Error-like nor an nsIException, so the stack will
|
||||
// include the closure doing the actual rejection.
|
||||
return {mustFind: ["test_rejection_closure"], error: undefined};
|
||||
};
|
||||
let make_error_rejection = function make_error_rejection() {
|
||||
let salt = (Math.random() * ( Math.pow(2, 24) - 1 ));
|
||||
@ -774,16 +780,26 @@ function wait_for_uncaught(aMustAppear, aTimeout = undefined) {
|
||||
error: error
|
||||
};
|
||||
};
|
||||
let make_exception_rejection = function make_exception_rejection() {
|
||||
let salt = (Math.random() * ( Math.pow(2, 24) - 1 ));
|
||||
let exn = new Components.Exception("This is an uncaught exception " + salt,
|
||||
Components.results.NS_ERROR_NOT_AVAILABLE);
|
||||
return {
|
||||
mustFind: [exn.message, exn.filename, exn.lineNumber, exn.location.toString()],
|
||||
error: exn
|
||||
};
|
||||
};
|
||||
for (let make_rejection of [make_string_rejection,
|
||||
make_num_rejection,
|
||||
make_undefined_rejection,
|
||||
make_error_rejection]) {
|
||||
make_error_rejection,
|
||||
make_exception_rejection]) {
|
||||
let {mustFind, error} = make_rejection();
|
||||
let name = make_rejection.name;
|
||||
tests.push(make_promise_test(function test_uncaught_is_reported() {
|
||||
do_print("Testing with rejection " + name);
|
||||
let promise = wait_for_uncaught(mustFind);
|
||||
(function() {
|
||||
(function test_rejection_closure() {
|
||||
// For the moment, we cannot be absolutely certain that a value is
|
||||
// garbage-collected, even if it is not referenced anymore, due to
|
||||
// the conservative stack-scanning algorithm.
|
||||
|
Loading…
Reference in New Issue
Block a user