mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge m-c to inbound on a CLOSED TREE
This commit is contained in:
commit
fd8ddfc8c0
@ -28,9 +28,10 @@ function duplicate(delta, msg, cb) {
|
||||
var start = gBrowser.sessionHistory.index;
|
||||
|
||||
duplicateTabIn(gBrowser.selectedTab, "tab", delta);
|
||||
let tab = gBrowser.selectedTab;
|
||||
|
||||
gBrowser.selectedBrowser.addEventListener("pageshow", function () {
|
||||
gBrowser.selectedBrowser.removeEventListener("pageshow", arguments.callee, false);
|
||||
tab.addEventListener("SSTabRestored", function tabRestoredListener() {
|
||||
tab.removeEventListener("SSTabRestored", tabRestoredListener, false);
|
||||
is(gBrowser.sessionHistory.index, start + delta, msg);
|
||||
executeSoon(cb);
|
||||
}, false);
|
||||
|
@ -22,10 +22,6 @@ EXTRA_DSO_LDOPTS += \
|
||||
$(MOZ_COMPONENT_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
ifdef JS_SHARED_LIBRARY
|
||||
EXTRA_DSO_LDOPTS += $(MOZ_JS_LIBS)
|
||||
endif
|
||||
|
||||
LOCAL_INCLUDES += -I$(srcdir)/../migration/src
|
||||
|
||||
# Mac: Need to link with CoreFoundation for Mac Migrators (PList reading code)
|
||||
|
@ -3,8 +3,3 @@
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
LOCAL_INCLUDES = -I$(srcdir)/../build
|
||||
|
||||
EXTRA_DSO_LDOPTS = \
|
||||
$(XPCOM_GLUE_LDOPTS) \
|
||||
$(NSPR_LIBS) \
|
||||
$(NULL)
|
||||
|
@ -2624,6 +2624,14 @@ let SessionStoreInternal = {
|
||||
// be ignored and don't override any tab data set by restoreHistory().
|
||||
TabState.flush(tab.linkedBrowser);
|
||||
|
||||
// Ensure the index is in bounds.
|
||||
let activeIndex = (tabData.index || tabData.entries.length) - 1;
|
||||
activeIndex = Math.min(activeIndex, tabData.entries.length - 1);
|
||||
activeIndex = Math.max(activeIndex, 0);
|
||||
|
||||
// Save the index in case we updated it above.
|
||||
tabData.index = activeIndex + 1;
|
||||
|
||||
// keep the data around to prevent dataloss in case
|
||||
// a tab gets closed before it's been properly restored
|
||||
browser.__SS_data = tabData;
|
||||
@ -2638,20 +2646,10 @@ let SessionStoreInternal = {
|
||||
pageStyle: tabData.pageStyle || null
|
||||
});
|
||||
|
||||
if (tabData.entries.length == 0) {
|
||||
// make sure to blank out this tab's content
|
||||
// (just purging the tab's history won't be enough)
|
||||
browser.loadURIWithFlags("about:blank",
|
||||
Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY,
|
||||
null, null, null);
|
||||
continue;
|
||||
}
|
||||
|
||||
browser.stop(); // in case about:blank isn't done yet
|
||||
|
||||
// wall-paper fix for bug 439675: make sure that the URL to be loaded
|
||||
// is always visible in the address bar
|
||||
let activeIndex = (tabData.index || tabData.entries.length) - 1;
|
||||
let activePageData = tabData.entries[activeIndex] || null;
|
||||
let uri = activePageData ? activePageData.url || null : null;
|
||||
browser.userTypedValue = uri;
|
||||
@ -2800,15 +2798,13 @@ let SessionStoreInternal = {
|
||||
// Remove the history listener, since we no longer need it once we start restoring
|
||||
this._removeSHistoryListener(aTab);
|
||||
|
||||
let activeIndex = (tabData.index || tabData.entries.length) - 1;
|
||||
if (activeIndex >= tabData.entries.length)
|
||||
activeIndex = tabData.entries.length - 1;
|
||||
let activeIndex = tabData.index - 1;
|
||||
// Reset currentURI. This creates a new session history entry with a new
|
||||
// doc identifier, so we need to explicitly save and restore the old doc
|
||||
// identifier (corresponding to the SHEntry at activeIndex) below.
|
||||
browser.webNavigation.setCurrentURI(Utils.makeURI("about:blank"));
|
||||
// Attach data that will be restored on "load" event, after tab is restored.
|
||||
if (activeIndex > -1) {
|
||||
if (tabData.entries.length) {
|
||||
// restore those aspects of the currently active documents which are not
|
||||
// preserved in the plain history entries (mainly scroll state and text data)
|
||||
browser.__SS_restore_data = tabData.entries[activeIndex] || {};
|
||||
@ -2826,6 +2822,14 @@ let SessionStoreInternal = {
|
||||
// ignore page load errors
|
||||
didStartLoad = false;
|
||||
}
|
||||
} else {
|
||||
browser.__SS_restore_data = {};
|
||||
browser.__SS_restore_pageStyle = "";
|
||||
browser.__SS_restore_tab = aTab;
|
||||
browser.loadURIWithFlags("about:blank",
|
||||
Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_HISTORY,
|
||||
null, null, null);
|
||||
didStartLoad = true;
|
||||
}
|
||||
|
||||
// Handle userTypedValue. Setting userTypedValue seems to update gURLbar
|
||||
@ -2850,8 +2854,8 @@ let SessionStoreInternal = {
|
||||
// channel (via the progress listener), so reset the tab ourselves. We will
|
||||
// also send SSTabRestored since this tab has technically been restored.
|
||||
if (!didStartLoad) {
|
||||
this._sendTabRestoredNotification(aTab);
|
||||
this._resetTabRestoringState(aTab);
|
||||
this._sendTabRestoredNotification(aTab);
|
||||
}
|
||||
|
||||
return didStartLoad;
|
||||
@ -2935,12 +2939,19 @@ let SessionStoreInternal = {
|
||||
PageStyle.restore(aBrowser.docShell, frameList, aBrowser.__SS_restore_pageStyle);
|
||||
TextAndScrollData.restore(frameList);
|
||||
|
||||
// notify the tabbrowser that this document has been completely restored
|
||||
this._sendTabRestoredNotification(aBrowser.__SS_restore_tab);
|
||||
let tab = aBrowser.__SS_restore_tab;
|
||||
|
||||
// Drop all the state associated with restoring the tab. We're
|
||||
// done with that now.
|
||||
delete aBrowser.__SS_data;
|
||||
delete aBrowser.__SS_restore_data;
|
||||
delete aBrowser.__SS_restore_pageStyle;
|
||||
delete aBrowser.__SS_restore_tab;
|
||||
|
||||
// Notify the tabbrowser that this document has been completely
|
||||
// restored. Do so after restoration is completely finished and
|
||||
// all state for it has been dropped.
|
||||
this._sendTabRestoredNotification(tab);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -119,7 +119,7 @@ function test() {
|
||||
// verify tab: (A), in undo list
|
||||
let tab_A_restored = test(function() ss.undoCloseTab(aWin, 0));
|
||||
ok(tab_A_restored, "a tab is in undo list");
|
||||
whenBrowserLoaded(tab_A_restored.linkedBrowser, function() {
|
||||
whenTabRestored(tab_A_restored, function() {
|
||||
is(testURL, tab_A_restored.linkedBrowser.currentURI.spec,
|
||||
"it's the same tab that we expect");
|
||||
aWin.gBrowser.removeTab(tab_A_restored);
|
||||
@ -137,14 +137,14 @@ function test() {
|
||||
|
||||
let tab_B = aWin.gBrowser.addTab(testURL2);
|
||||
ss.setTabState(tab_B, JSON.stringify(state1));
|
||||
whenBrowserLoaded(tab_B.linkedBrowser, function() {
|
||||
whenTabRestored(tab_B, function() {
|
||||
// populate tab: (B) with different form data
|
||||
for (let item in fieldList)
|
||||
setFormValue(tab_B, item, fieldList[item]);
|
||||
|
||||
// duplicate tab: (B)
|
||||
let tab_C = aWin.gBrowser.duplicateTab(tab_B);
|
||||
whenBrowserLoaded(tab_C.linkedBrowser, function() {
|
||||
whenTabRestored(tab_C, function() {
|
||||
// verify the correctness of the duplicated tab
|
||||
is(ss.getTabValue(tab_C, key1), value1,
|
||||
"tab successfully duplicated - correct state");
|
||||
|
@ -11,15 +11,13 @@ function test() {
|
||||
"browser/components/sessionstore/test/browser_339445_sample.html";
|
||||
|
||||
let tab = gBrowser.addTab(testURL);
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
whenBrowserLoaded(tab.linkedBrowser, function() {
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
is(doc.getElementById("storageTestItem").textContent, "PENDING",
|
||||
"sessionStorage value has been set");
|
||||
|
||||
let tab2 = gBrowser.duplicateTab(tab);
|
||||
tab2.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
whenTabRestored(tab2, function() {
|
||||
let doc2 = tab2.linkedBrowser.contentDocument;
|
||||
is(doc2.getElementById("storageTestItem").textContent, "SUCCESS",
|
||||
"sessionStorage value has been duplicated");
|
||||
@ -29,6 +27,6 @@ function test() {
|
||||
gBrowser.removeTab(tab);
|
||||
|
||||
finish();
|
||||
}, true);
|
||||
}, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -88,14 +88,12 @@ function test() {
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let testURL = rootDir + "browser_346337_sample.html";
|
||||
let tab = tabbrowser.addTab(testURL);
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
whenBrowserLoaded(tab.linkedBrowser, function() {
|
||||
for (let xpath in fieldList)
|
||||
setFormValue(tab, xpath, fieldList[xpath]);
|
||||
|
||||
let tab2 = tabbrowser.duplicateTab(tab);
|
||||
tab2.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
whenTabRestored(tab2, function() {
|
||||
for (let xpath in fieldList)
|
||||
ok(compareFormValue(tab2, xpath, fieldList[xpath]),
|
||||
"The value for \"" + xpath + "\" was correctly restored");
|
||||
@ -105,8 +103,7 @@ function test() {
|
||||
tabbrowser.removeTab(tab);
|
||||
|
||||
tab = undoCloseTab();
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
whenTabRestored(tab, function() {
|
||||
for (let xpath in fieldList)
|
||||
if (fieldList[xpath])
|
||||
ok(!compareFormValue(tab, xpath, fieldList[xpath]),
|
||||
@ -120,7 +117,7 @@ function test() {
|
||||
tabbrowser.addTab();
|
||||
tabbrowser.removeTab(tab);
|
||||
finish();
|
||||
}, true);
|
||||
}, true);
|
||||
}, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -71,8 +71,7 @@ function test() {
|
||||
// create a new tab
|
||||
let testURL = "about:";
|
||||
tab = gBrowser.addTab(testURL);
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
whenBrowserLoaded(tab.linkedBrowser, function() {
|
||||
// make sure that the next closed tab will increase getClosedTabCount
|
||||
gPrefService.setIntPref("browser.sessionstore.max_tabs_undo", max_tabs_undo + 1);
|
||||
|
||||
@ -87,15 +86,14 @@ function test() {
|
||||
tab = test(function() ss.undoCloseTab(window, 0));
|
||||
ok(tab, "undoCloseTab doesn't throw")
|
||||
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
is(this.currentURI.spec, testURL, "correct tab was reopened");
|
||||
whenTabRestored(tab, function() {
|
||||
is(tab.linkedBrowser.currentURI.spec, testURL, "correct tab was reopened");
|
||||
|
||||
// clean up
|
||||
if (gPrefService.prefHasUserValue("browser.sessionstore.max_tabs_undo"))
|
||||
gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo");
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
}, true);
|
||||
}, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -14,15 +14,12 @@ function test() {
|
||||
|
||||
// restore a blank tab
|
||||
let tab = gBrowser.addTab("about:");
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
whenBrowserLoaded(tab.linkedBrowser, function() {
|
||||
let history = tab.linkedBrowser.webNavigation.sessionHistory;
|
||||
ok(history.count >= 1, "the new tab does have at least one history entry");
|
||||
|
||||
ss.setTabState(tab, JSON.stringify({ entries: [] }));
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
whenTabRestored(tab, function() {
|
||||
ok(history.count == 0, "the tab was restored without any history whatsoever");
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
@ -33,6 +30,6 @@ function test() {
|
||||
if (gPrefService.prefHasUserValue("browser.sessionstore.max_tabs_undo"))
|
||||
gPrefService.clearUserPref("browser.sessionstore.max_tabs_undo");
|
||||
finish();
|
||||
}, true);
|
||||
}, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -13,8 +13,7 @@ function test() {
|
||||
// create a new tab
|
||||
let tab = gBrowser.addTab(testURL);
|
||||
ss.setTabValue(tab, key, value);
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
whenBrowserLoaded(tab.linkedBrowser, function() {
|
||||
// get the tab's state
|
||||
let state = ss.getTabState(tab);
|
||||
ok(state, "get the tab's state");
|
||||
@ -30,7 +29,7 @@ function test() {
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(tab);
|
||||
}, true);
|
||||
});
|
||||
|
||||
//////////////////////////////////
|
||||
// setTabState and duplicateTab //
|
||||
@ -44,31 +43,30 @@ function test() {
|
||||
let tab2 = gBrowser.addTab();
|
||||
// set the tab's state
|
||||
ss.setTabState(tab2, JSON.stringify(state));
|
||||
tab2.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
whenTabRestored(tab2, function() {
|
||||
// verify the correctness of the restored tab
|
||||
ok(ss.getTabValue(tab2, key2) == value2 && this.currentURI.spec == testURL,
|
||||
ok(ss.getTabValue(tab2, key2) == value2 && tab2.linkedBrowser.currentURI.spec == testURL,
|
||||
"the tab's state was correctly restored");
|
||||
|
||||
// add text data
|
||||
let textbox = this.contentDocument.getElementById("textbox");
|
||||
let textbox = tab2.linkedBrowser.contentDocument.getElementById("textbox");
|
||||
textbox.value = value3;
|
||||
|
||||
// duplicate the tab
|
||||
let duplicateTab = ss.duplicateTab(window, tab2);
|
||||
gBrowser.removeTab(tab2);
|
||||
|
||||
duplicateTab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
whenTabRestored(duplicateTab, function() {
|
||||
// verify the correctness of the duplicated tab
|
||||
ok(ss.getTabValue(duplicateTab, key2) == value2 && this.currentURI.spec == testURL,
|
||||
ok(ss.getTabValue(duplicateTab, key2) == value2 &&
|
||||
duplicateTab.linkedBrowser.currentURI.spec == testURL,
|
||||
"correctly duplicated the tab's state");
|
||||
let textbox = this.contentDocument.getElementById("textbox");
|
||||
let textbox = duplicateTab.linkedBrowser.contentDocument.getElementById("textbox");
|
||||
is(textbox.value, value3, "also duplicated text data");
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(duplicateTab);
|
||||
finish();
|
||||
}, true);
|
||||
}, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -28,8 +28,7 @@ function test() {
|
||||
|
||||
function testOpenCloseWindow(aIsPrivate, aTest, aCallback) {
|
||||
whenNewWindowLoaded({ private: aIsPrivate }, function(win) {
|
||||
win.gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
|
||||
win.gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
|
||||
whenBrowserLoaded(win.gBrowser.selectedBrowser, function() {
|
||||
executeSoon(function() {
|
||||
// Mark the window with some unique data to be restored later on.
|
||||
ss.setWindowValue(win, aTest.key, aTest.value);
|
||||
@ -37,7 +36,7 @@ function test() {
|
||||
win.close();
|
||||
aCallback();
|
||||
});
|
||||
}, true);
|
||||
});
|
||||
win.gBrowser.selectedBrowser.loadURI(aTest.url);
|
||||
});
|
||||
}
|
||||
|
@ -27,9 +27,7 @@ function test() {
|
||||
|
||||
newWin.gBrowser.loadURI(testURL, null, null);
|
||||
|
||||
newWin.gBrowser.addEventListener("load", function (aEvent) {
|
||||
newWin.gBrowser.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
whenBrowserLoaded(newWin.gBrowser.selectedBrowser, function() {
|
||||
// get the sessionstore state for the window
|
||||
let state = ss.getWindowState(newWin);
|
||||
|
||||
@ -67,7 +65,7 @@ function test() {
|
||||
cs.removeAll();
|
||||
newWin.close();
|
||||
finish();
|
||||
}, true);
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
|
||||
|
@ -10,17 +10,14 @@ function test() {
|
||||
"browser/components/sessionstore/test/browser_447951_sample.html#";
|
||||
|
||||
let tab = gBrowser.addTab();
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
whenBrowserLoaded(tab.linkedBrowser, function() {
|
||||
let tabState = { entries: [] };
|
||||
let max_entries = gPrefService.getIntPref("browser.sessionhistory.max_entries");
|
||||
for (let i = 0; i < max_entries; i++)
|
||||
tabState.entries.push({ url: baseURL + i });
|
||||
|
||||
ss.setTabState(tab, JSON.stringify(tabState));
|
||||
tab.addEventListener("SSTabRestored", function(aEvent) {
|
||||
tab.removeEventListener("SSTabRestored", arguments.callee, false);
|
||||
whenTabRestored(tab, function() {
|
||||
tabState = JSON.parse(ss.getTabState(tab));
|
||||
is(tabState.entries.length, max_entries, "session history filled to the limit");
|
||||
is(tabState.entries[0].url, baseURL + 0, "... but not more");
|
||||
@ -32,8 +29,15 @@ function test() {
|
||||
0, 0, 0, 0, false, false, false, false, 0, null);
|
||||
doc.querySelector("a").dispatchEvent(event);
|
||||
|
||||
executeSoon(function() {
|
||||
function check() {
|
||||
tabState = JSON.parse(ss.getTabState(tab));
|
||||
if (tabState.entries[tabState.entries.length - 1].url != baseURL + "end") {
|
||||
// It may take a few passes through the event loop before we
|
||||
// get the right URL.
|
||||
executeSoon(check);
|
||||
return;
|
||||
}
|
||||
|
||||
is(tab.linkedBrowser.currentURI.spec, baseURL + "end",
|
||||
"the new anchor was loaded");
|
||||
is(tabState.entries[tabState.entries.length - 1].url, baseURL + "end",
|
||||
@ -44,7 +48,9 @@ function test() {
|
||||
// clean up
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
});
|
||||
}, false);
|
||||
}, true);
|
||||
}
|
||||
|
||||
check();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -18,8 +18,7 @@ function test() {
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let testURL = rootDir + "browser_454908_sample.html";
|
||||
let tab = gBrowser.addTab(testURL);
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
whenBrowserLoaded(tab.linkedBrowser, function() {
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
for (let id in fieldValues)
|
||||
doc.getElementById(id).value = fieldValues[id];
|
||||
@ -27,8 +26,7 @@ function test() {
|
||||
gBrowser.removeTab(tab);
|
||||
|
||||
tab = undoCloseTab();
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
whenTabRestored(tab, function() {
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
for (let id in fieldValues) {
|
||||
let node = doc.getElementById(id);
|
||||
@ -47,6 +45,6 @@ function test() {
|
||||
gBrowser.addTab();
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
}, true);
|
||||
}, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -13,13 +13,11 @@ function test() {
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let testURL = rootDir + "browser_456342_sample.xhtml";
|
||||
let tab = gBrowser.addTab(testURL);
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
this.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
whenBrowserLoaded(tab.linkedBrowser, function() {
|
||||
let expectedValue = "try to save me";
|
||||
// Since bug 537289 we only save non-default values, so we need to set each
|
||||
// form field's value after load.
|
||||
let formEls = aEvent.originalTarget.forms[0].elements;
|
||||
let formEls = tab.linkedBrowser.contentDocument.forms[0].elements;
|
||||
for (let i = 0; i < formEls.length; i++)
|
||||
formEls[i].value = expectedValue;
|
||||
|
||||
@ -49,5 +47,5 @@ function test() {
|
||||
if (gPrefService.prefHasUserValue("browser.sessionstore.privacy_level"))
|
||||
gPrefService.clearUserPref("browser.sessionstore.privacy_level");
|
||||
finish();
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
@ -31,14 +31,8 @@ function test() {
|
||||
typeText(doc.getElementsByName("1|#out2")[0], Math.random());
|
||||
typeText(doc.defaultView.frames[0].frames[1].document.getElementById("in1"), new Date());
|
||||
|
||||
frameCount = 0;
|
||||
let tab2 = gBrowser.duplicateTab(tab);
|
||||
tab2.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
// wait for all frames to load completely
|
||||
if (frameCount++ < 5)
|
||||
return;
|
||||
tab2.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
whenTabRestored(tab2, function() {
|
||||
let doc = tab2.linkedBrowser.contentDocument;
|
||||
let win = tab2.linkedBrowser.contentWindow;
|
||||
isnot(doc.getElementById("out1").value,
|
||||
@ -59,6 +53,6 @@ function test() {
|
||||
gBrowser.removeTab(tab);
|
||||
|
||||
finish();
|
||||
}, true);
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
|
@ -13,8 +13,7 @@ function test() {
|
||||
|
||||
// set a unique value on a new, blank tab
|
||||
let tab1 = gBrowser.addTab();
|
||||
tab1.linkedBrowser.addEventListener("load", function() {
|
||||
tab1.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
whenBrowserLoaded(tab1.linkedBrowser, function() {
|
||||
ss.setTabValue(tab1, uniqueName, uniqueValue1);
|
||||
|
||||
// duplicate the tab with that value
|
||||
@ -26,14 +25,13 @@ function test() {
|
||||
|
||||
// overwrite the tab with the value which should remove it
|
||||
ss.setTabState(tab1, JSON.stringify({ entries: [] }));
|
||||
tab1.linkedBrowser.addEventListener("load", function() {
|
||||
tab1.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
whenTabRestored(tab1, function() {
|
||||
is(ss.getTabValue(tab1, uniqueName), "", "tab value was cleared");
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(tab2);
|
||||
gBrowser.removeTab(tab1);
|
||||
finish();
|
||||
}, true);
|
||||
}, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -18,15 +18,13 @@ function test() {
|
||||
"browser/components/sessionstore/test/browser_466937_sample.html";
|
||||
|
||||
let tab = gBrowser.addTab(testURL);
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
whenBrowserLoaded(tab.linkedBrowser, function() {
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
doc.getElementById("reverse_thief").value = "/home/user/secret2";
|
||||
doc.getElementById("bystander").value = testPath;
|
||||
|
||||
let tab2 = gBrowser.duplicateTab(tab);
|
||||
tab2.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab2.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
whenTabRestored(tab2, function() {
|
||||
doc = tab2.linkedBrowser.contentDocument;
|
||||
is(doc.getElementById("thief").value, "",
|
||||
"file path wasn't set to text field value");
|
||||
@ -40,6 +38,6 @@ function test() {
|
||||
gBrowser.removeTab(tab);
|
||||
|
||||
finish();
|
||||
}, true);
|
||||
}, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -13,14 +13,12 @@ function test() {
|
||||
let tab = gBrowser.addTab("about:sessionrestore");
|
||||
gBrowser.selectedTab = tab;
|
||||
let browser = tab.linkedBrowser;
|
||||
browser.addEventListener("load", function(aEvent) {
|
||||
browser.removeEventListener("load", arguments.callee, true);
|
||||
whenBrowserLoaded(browser, function() {
|
||||
let doc = browser.contentDocument;
|
||||
|
||||
// click on the "Start New Session" button after about:sessionrestore is loaded
|
||||
doc.getElementById("errorCancel").click();
|
||||
browser.addEventListener("load", function(aEvent) {
|
||||
browser.removeEventListener("load", arguments.callee, true);
|
||||
whenBrowserLoaded(browser, function() {
|
||||
let doc = browser.contentDocument;
|
||||
|
||||
is(doc.URL, "about:blank", "loaded page is about:blank");
|
||||
@ -31,14 +29,12 @@ function test() {
|
||||
gPrefService.setCharPref("browser.startup.homepage", homepage);
|
||||
gPrefService.setIntPref("browser.startup.page", 1);
|
||||
gBrowser.loadURI("about:sessionrestore");
|
||||
browser.addEventListener("load", function(aEvent) {
|
||||
browser.removeEventListener("load", arguments.callee, true);
|
||||
whenBrowserLoaded(browser, function() {
|
||||
let doc = browser.contentDocument;
|
||||
|
||||
// click on the "Start New Session" button after about:sessionrestore is loaded
|
||||
doc.getElementById("errorCancel").click();
|
||||
browser.addEventListener("load", function(aEvent) {
|
||||
browser.removeEventListener("load", arguments.callee, true);
|
||||
whenBrowserLoaded(browser, function() {
|
||||
let doc = browser.contentDocument;
|
||||
|
||||
is(doc.URL, homepage, "loaded page is the homepage");
|
||||
@ -48,8 +44,8 @@ function test() {
|
||||
gPrefService.clearUserPref("browser.startup.page");
|
||||
gPrefService.clearUserPref("browser.startup.homepage");
|
||||
finish();
|
||||
}, true);
|
||||
}, true);
|
||||
}, true);
|
||||
}, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -12,15 +12,13 @@ function test() {
|
||||
let rootDir = getRootDirectory(gTestPath);
|
||||
let testURL = rootDir + "browser_485482_sample.html";
|
||||
let tab = gBrowser.addTab(testURL);
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
whenBrowserLoaded(tab.linkedBrowser, function() {
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
doc.querySelector("input[type=text]").value = uniqueValue;
|
||||
doc.querySelector("input[type=checkbox]").checked = true;
|
||||
|
||||
let tab2 = gBrowser.duplicateTab(tab);
|
||||
tab2.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab2.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
whenTabRestored(tab2, function() {
|
||||
doc = tab2.linkedBrowser.contentDocument;
|
||||
is(doc.querySelector("input[type=text]").value, uniqueValue,
|
||||
"generated XPath expression was valid");
|
||||
@ -31,6 +29,6 @@ function test() {
|
||||
gBrowser.removeTab(tab2);
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
}, true);
|
||||
}, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -10,8 +10,7 @@ function test() {
|
||||
let uniqueValue = Math.random() + "\u2028Second line\u2029Second paragraph\u2027";
|
||||
|
||||
let tab = gBrowser.addTab();
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
whenBrowserLoaded(tab.linkedBrowser, function() {
|
||||
ss.setTabValue(tab, "bug485563", uniqueValue);
|
||||
let tabState = JSON.parse(ss.getTabState(tab));
|
||||
is(tabState.extData["bug485563"], uniqueValue,
|
||||
@ -23,5 +22,5 @@ function test() {
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
finish();
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
@ -14,9 +14,7 @@ function test() {
|
||||
gBrowser.selectedTab = tab;
|
||||
|
||||
let browser = tab.linkedBrowser;
|
||||
browser.addEventListener("load", function() {
|
||||
browser.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
whenBrowserLoaded(browser, function() {
|
||||
let tabState = JSON.parse(ss.getTabState(tab));
|
||||
is(tabState.entries[0].referrer, REFERRER1,
|
||||
"Referrer retrieved via getTabState matches referrer set via loadURI.");
|
||||
@ -24,29 +22,20 @@ function test() {
|
||||
tabState.entries[0].referrer = REFERRER2;
|
||||
ss.setTabState(tab, JSON.stringify(tabState));
|
||||
|
||||
tab.addEventListener("SSTabRestored", function(e) {
|
||||
tab.removeEventListener("SSTabRestored", arguments.callee, true);
|
||||
whenTabRestored(tab, function(e) {
|
||||
is(window.content.document.referrer, REFERRER2, "document.referrer matches referrer set via setTabState.");
|
||||
|
||||
gBrowser.removeTab(tab);
|
||||
// Call stopPropagation on the event so we won't fire the
|
||||
// tabbrowser's SSTabRestored listeners.
|
||||
e.stopPropagation();
|
||||
|
||||
let newTab = ss.undoCloseTab(window, 0);
|
||||
newTab.addEventListener("SSTabRestored", function(e) {
|
||||
newTab.removeEventListener("SSTabRestored", arguments.callee, true);
|
||||
|
||||
whenTabRestored(newTab, function() {
|
||||
is(window.content.document.referrer, REFERRER2, "document.referrer is still correct after closing and reopening the tab.");
|
||||
gBrowser.removeTab(newTab);
|
||||
// Call stopPropagation on the event so we won't fire the
|
||||
// tabbrowser's SSTabRestored listeners.
|
||||
e.stopPropagation();
|
||||
|
||||
finish();
|
||||
}, true);
|
||||
}, true);
|
||||
},true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
let referrerURI = Services.io.newURI(REFERRER1, null, null);
|
||||
browser.loadURI("http://example.org", referrerURI, null);
|
||||
|
@ -72,16 +72,12 @@ function test() {
|
||||
// http://example.com. We need to load the blank window first, otherwise the
|
||||
// docshell gets confused and doesn't have a current history entry.
|
||||
let tab = gBrowser.addTab("about:blank");
|
||||
let tabBrowser = tab.linkedBrowser;
|
||||
let browser = tab.linkedBrowser;
|
||||
|
||||
tabBrowser.addEventListener("load", function(aEvent) {
|
||||
tabBrowser.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
tabBrowser.loadURI("http://example.com", null, null);
|
||||
|
||||
tabBrowser.addEventListener("load", function(aEvent) {
|
||||
tabBrowser.removeEventListener("load", arguments.callee, true);
|
||||
whenBrowserLoaded(browser, function() {
|
||||
browser.loadURI("http://example.com", null, null);
|
||||
|
||||
whenBrowserLoaded(browser, function() {
|
||||
// After these push/replaceState calls, the window should have three
|
||||
// history entries:
|
||||
// testURL (state object: null) <-- oldest
|
||||
@ -102,13 +98,12 @@ function test() {
|
||||
ss.setTabState(tab2, state, true);
|
||||
|
||||
// Run checkState() once the tab finishes loading its restored state.
|
||||
tab2.linkedBrowser.addEventListener("load", function() {
|
||||
tab2.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
whenTabRestored(tab2, function() {
|
||||
SimpleTest.executeSoon(function() {
|
||||
checkState(tab2);
|
||||
});
|
||||
}, true);
|
||||
});
|
||||
|
||||
}, true);
|
||||
}, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -47,9 +47,7 @@ function test() {
|
||||
|
||||
// create and select a first tab
|
||||
let tab = gBrowser.addTab(TEST_URL);
|
||||
tab.linkedBrowser.addEventListener("load", function loadListener(e) {
|
||||
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
whenBrowserLoaded(tab.linkedBrowser, function() {
|
||||
// step1: the above has triggered some saveStateDelayed(), sleep until
|
||||
// it's done, and get the initial sessionstore.js mtime
|
||||
setTimeout(function step1(e) {
|
||||
@ -72,5 +70,5 @@ function test() {
|
||||
finish();
|
||||
}, 3500); // end of sleep after tab selection and scrolling
|
||||
}, 3500); // end of sleep after initial saveStateDelayed()
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
@ -198,24 +198,20 @@ function test() {
|
||||
event.initEvent("input", true, false);
|
||||
gURLBar.dispatchEvent(event);
|
||||
|
||||
browser.addEventListener("load", function onLoad() {
|
||||
browser.removeEventListener("load", onLoad, true);
|
||||
executeSoon(function () {
|
||||
is(browser.userTypedValue, "example.org",
|
||||
"userTypedValue was set when changing gURLBar.value");
|
||||
is(browser.userTypedClear, 0,
|
||||
"userTypedClear was not changed when changing gURLBar.value");
|
||||
|
||||
executeSoon(function () {
|
||||
is(browser.userTypedValue, "example.org",
|
||||
"userTypedValue was set when changing gURLBar.value");
|
||||
is(browser.userTypedClear, 0,
|
||||
"userTypedClear was not changed when changing gURLBar.value");
|
||||
|
||||
// Now make sure ss gets these values too
|
||||
let newState = JSON.parse(ss.getBrowserState());
|
||||
is(newState.windows[0].tabs[0].userTypedValue, "example.org",
|
||||
"sessionstore got correct userTypedValue");
|
||||
is(newState.windows[0].tabs[0].userTypedClear, 0,
|
||||
"sessionstore got correct userTypedClear");
|
||||
runNextTest();
|
||||
});
|
||||
}, true);
|
||||
// Now make sure ss gets these values too
|
||||
let newState = JSON.parse(ss.getBrowserState());
|
||||
is(newState.windows[0].tabs[0].userTypedValue, "example.org",
|
||||
"sessionstore got correct userTypedValue");
|
||||
is(newState.windows[0].tabs[0].userTypedClear, 0,
|
||||
"sessionstore got correct userTypedClear");
|
||||
runNextTest();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -5,12 +5,10 @@
|
||||
function test() {
|
||||
let tab1 = gBrowser.addTab("about:rights");
|
||||
let tab2 = gBrowser.addTab("about:mozilla");
|
||||
tab1.linkedBrowser.addEventListener("load", mainPart, true);
|
||||
whenBrowserLoaded(tab1.linkedBrowser, mainPart);
|
||||
waitForExplicitFinish();
|
||||
|
||||
function mainPart() {
|
||||
tab1.linkedBrowser.removeEventListener("load", mainPart, true);
|
||||
|
||||
// Tell the session storer that the tab is pinned
|
||||
let newTabState = '{"entries":[{"url":"about:rights"}],"pinned":true,"userTypedValue":"Hello World!"}';
|
||||
ss.setTabState(tab1, newTabState);
|
||||
|
@ -4,9 +4,7 @@ function test() {
|
||||
var tab1 = gBrowser.addTab("data:text/plain;charset=utf-8,foo");
|
||||
gBrowser.pinTab(tab1);
|
||||
|
||||
tab1.linkedBrowser.addEventListener("load", function () {
|
||||
tab1.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
whenBrowserLoaded(tab1.linkedBrowser, function() {
|
||||
var tab2 = gBrowser.addTab();
|
||||
gBrowser.pinTab(tab2);
|
||||
|
||||
@ -19,5 +17,5 @@ function test() {
|
||||
gBrowser.removeTab(tab1);
|
||||
gBrowser.removeTab(tab2);
|
||||
finish();
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
@ -163,9 +163,7 @@ function onStateRestored(aSubject, aTopic, aData) {
|
||||
newWin.addEventListener("load", function(aEvent) {
|
||||
newWin.removeEventListener("load", arguments.callee, false);
|
||||
|
||||
newWin.gBrowser.selectedBrowser.addEventListener("load", function() {
|
||||
newWin.gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
whenBrowserLoaded(newWin.gBrowser.selectedBrowser, function() {
|
||||
// pin this tab
|
||||
if (shouldPinTab)
|
||||
newWin.gBrowser.pinTab(newWin.gBrowser.selectedTab);
|
||||
@ -197,7 +195,7 @@ function onStateRestored(aSubject, aTopic, aData) {
|
||||
else {
|
||||
newWin.BrowserTryToCloseWindow();
|
||||
}
|
||||
}, true);
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
|
||||
|
@ -82,12 +82,10 @@ function testTabRestoreData(aFormData, aExpectedValues, aCallback) {
|
||||
let tab = gBrowser.addTab(testURL);
|
||||
let tabState = { entries: [{ url: testURL, formdata: aFormData}] };
|
||||
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
whenBrowserLoaded(tab.linkedBrowser, function() {
|
||||
ss.setTabState(tab, JSON.stringify(tabState));
|
||||
|
||||
tab.addEventListener("SSTabRestored", function(aEvent) {
|
||||
tab.removeEventListener("SSTabRestored", arguments.callee);
|
||||
whenTabRestored(tab, function() {
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
let select = doc.getElementById("select_id");
|
||||
let value = select.options[select.selectedIndex].value;
|
||||
@ -98,9 +96,7 @@ function testTabRestoreData(aFormData, aExpectedValues, aCallback) {
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(tab);
|
||||
// Call stopPropagation on the event so we won't fire the
|
||||
// tabbrowser's SSTabRestored listeners.
|
||||
aEvent.stopPropagation();
|
||||
|
||||
aCallback();
|
||||
});
|
||||
|
||||
@ -127,5 +123,5 @@ function testTabRestoreData(aFormData, aExpectedValues, aCallback) {
|
||||
is(value, aExpectedValues[0],
|
||||
"Collection has been saved correctly");
|
||||
});
|
||||
}, true);
|
||||
});
|
||||
}
|
||||
|
@ -178,9 +178,6 @@ function testOnWindow(aIsPrivate, aCallback) {
|
||||
}
|
||||
|
||||
function waitForTabLoad(aWin, aURL, aCallback) {
|
||||
aWin.gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
|
||||
aWin.gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
|
||||
executeSoon(aCallback);
|
||||
}, true);
|
||||
whenBrowserLoaded(aWin.gBrowser.selectedBrowser, aCallback);
|
||||
aWin.gBrowser.selectedBrowser.loadURI(aURL);
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ function runTests() {
|
||||
|
||||
// Let the pending tab load.
|
||||
gBrowser.selectedTab = tab;
|
||||
yield whenBrowserLoaded(tab.linkedBrowser);
|
||||
yield whenTabRestored(tab);
|
||||
|
||||
// Ensure no 'image' or 'pending' attributes are stored.
|
||||
let {attributes} = JSON.parse(ss.getTabState(tab));
|
||||
|
@ -14,8 +14,7 @@ function test() {
|
||||
let testURL = "http://mochi.test:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser_form_restore_events_sample.html";
|
||||
let tab = gBrowser.addTab(testURL);
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
whenBrowserLoaded(tab.linkedBrowser, function() {
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
|
||||
// text fields
|
||||
@ -45,8 +44,7 @@ function test() {
|
||||
|
||||
|
||||
let tab2 = gBrowser.duplicateTab(tab);
|
||||
tab2.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab2.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
whenTabRestored(tab2, function() {
|
||||
let doc = tab2.linkedBrowser.contentDocument;
|
||||
let inputFired = doc.getElementById("inputFired").textContent.trim().split();
|
||||
let changeFired = doc.getElementById("changeFired").textContent.trim().split();
|
||||
@ -62,6 +60,6 @@ function test() {
|
||||
gBrowser.removeTab(tab);
|
||||
|
||||
finish();
|
||||
}, true);
|
||||
}, true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -137,5 +137,3 @@ add_task(function browsing() {
|
||||
gBrowser.removeTab(tab2);
|
||||
gBrowser.removeTab(tab1);
|
||||
});
|
||||
|
||||
|
||||
|
@ -311,6 +311,15 @@ function whenWindowLoaded(aWindow, aCallback = next) {
|
||||
}, false);
|
||||
}
|
||||
|
||||
function whenTabRestored(aTab, aCallback = next) {
|
||||
aTab.addEventListener("SSTabRestored", function onRestored(aEvent) {
|
||||
aTab.removeEventListener("SSTabRestored", onRestored, true);
|
||||
executeSoon(function executeWhenTabRestored() {
|
||||
aCallback();
|
||||
});
|
||||
}, true);
|
||||
}
|
||||
|
||||
var gUniqueCounter = 0;
|
||||
function r() {
|
||||
return Date.now() + "-" + (++gUniqueCounter);
|
||||
@ -349,7 +358,7 @@ let gProgressListener = {
|
||||
function gProgressListener_onStateChange(aBrowser, aWebProgress, aRequest,
|
||||
aStateFlags, aStatus) {
|
||||
if ((!this._checkRestoreState ||
|
||||
aBrowser.__SS_restoreState == TAB_STATE_RESTORING) &&
|
||||
(aBrowser.__SS_restoreState && aBrowser.__SS_restoreState == TAB_STATE_RESTORING)) &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_STOP &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK &&
|
||||
aStateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
|
||||
@ -364,12 +373,12 @@ let gProgressListener = {
|
||||
for (let win in BrowserWindowIterator()) {
|
||||
for (let i = 0; i < win.gBrowser.tabs.length; i++) {
|
||||
let browser = win.gBrowser.tabs[i].linkedBrowser;
|
||||
if (browser.__SS_restoreState == TAB_STATE_RESTORING)
|
||||
if (!browser.__SS_restoreState)
|
||||
wasRestored++;
|
||||
else if (browser.__SS_restoreState == TAB_STATE_RESTORING)
|
||||
isRestoring++;
|
||||
else if (browser.__SS_restoreState == TAB_STATE_NEEDS_RESTORE)
|
||||
needsRestore++;
|
||||
else
|
||||
wasRestored++;
|
||||
}
|
||||
}
|
||||
return [needsRestore, isRestoring, wasRestored];
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "nsJSPrincipals.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsPrincipal.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
|
||||
class nsIURI;
|
||||
|
||||
@ -53,6 +54,7 @@ public:
|
||||
virtual ~nsNullPrincipal();
|
||||
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> mCSP;
|
||||
};
|
||||
|
||||
#endif // nsNullPrincipal_h__
|
||||
|
@ -149,8 +149,11 @@ nsNullPrincipal::GetHashValue(uint32_t *aResult)
|
||||
NS_IMETHODIMP
|
||||
nsNullPrincipal::GetSecurityPolicy(void** aSecurityPolicy)
|
||||
{
|
||||
// We don't actually do security policy caching. And it's not like anyone
|
||||
// can set a security policy for us anyway.
|
||||
// Leftover from old security model, a "security policy" is a set of
|
||||
// rules for property access that can override the SOP. Policies are
|
||||
// associated with origins and since nsNullPinricipals never get the
|
||||
// same origin twice, it's not possible to specify a "security
|
||||
// policy" for it. Hence, we do not cache the security policy.
|
||||
*aSecurityPolicy = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -158,8 +161,11 @@ nsNullPrincipal::GetSecurityPolicy(void** aSecurityPolicy)
|
||||
NS_IMETHODIMP
|
||||
nsNullPrincipal::SetSecurityPolicy(void* aSecurityPolicy)
|
||||
{
|
||||
// We don't actually do security policy caching. And it's not like anyone
|
||||
// can set a security policy for us anyway.
|
||||
// Leftover from old security model, a "security policy" is a set of
|
||||
// rules for property access that can override the SOP. Policies are
|
||||
// associated with origins and since nsNullPinricipals never get the
|
||||
// same origin twice, it's not possible to specify a "security
|
||||
// policy" for it. Hence, we do not cache the security policy.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -172,16 +178,20 @@ nsNullPrincipal::GetURI(nsIURI** aURI)
|
||||
NS_IMETHODIMP
|
||||
nsNullPrincipal::GetCsp(nsIContentSecurityPolicy** aCsp)
|
||||
{
|
||||
// CSP on a null principal makes no sense
|
||||
*aCsp = nullptr;
|
||||
NS_IF_ADDREF(*aCsp = mCSP);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNullPrincipal::SetCsp(nsIContentSecurityPolicy* aCsp)
|
||||
{
|
||||
// CSP on a null principal makes no sense
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
// If CSP was already set, it should not be destroyed! Instead, it should
|
||||
// get set anew when a new principal is created.
|
||||
if (mCSP)
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
|
||||
mCSP = aCsp;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -131,7 +131,7 @@ CPPSRCS += $(CPP_UNIT_TESTS)
|
||||
CPP_UNIT_TEST_BINS := $(CPP_UNIT_TESTS:.cpp=$(BIN_SUFFIX))
|
||||
SIMPLE_PROGRAMS += $(CPP_UNIT_TEST_BINS)
|
||||
INCLUDES += -I$(DIST)/include/testing
|
||||
LIBS += $(XPCOM_GLUE_LDOPTS) $(NSPR_LIBS) $(MOZ_JS_LIBS) $(if $(JS_SHARED_LIBRARY),,$(MOZ_ZLIB_LIBS))
|
||||
LIBS += $(XPCOM_GLUE_LDOPTS) $(NSPR_LIBS) $(if $(JS_SHARED_LIBRARY),,$(MOZ_ZLIB_LIBS))
|
||||
|
||||
ifndef MOZ_PROFILE_GENERATE
|
||||
libs:: $(CPP_UNIT_TEST_BINS) $(call mkdir_deps,$(DIST)/cppunittests)
|
||||
@ -1709,3 +1709,7 @@ include $(topsrcdir)/config/makefiles/autotargets.mk
|
||||
ifneq ($(NULL),$(AUTO_DEPS))
|
||||
default all libs tools export:: $(AUTO_DEPS)
|
||||
endif
|
||||
|
||||
export:: $(GENERATED_FILES)
|
||||
|
||||
GARBAGE += $(GENERATED_FILES)
|
||||
|
@ -51,9 +51,9 @@ function ContentSecurityPolicy() {
|
||||
|
||||
this._request = "";
|
||||
this._requestOrigin = "";
|
||||
this._requestPrincipal = "";
|
||||
this._weakRequestPrincipal = { get : function() { return null; } };
|
||||
this._referrer = "";
|
||||
this._docRequest = null;
|
||||
this._weakDocRequest = { get : function() { return null; } };
|
||||
CSPdebug("CSP object initialized, no policies to enforce yet");
|
||||
|
||||
this._cache = { };
|
||||
@ -296,7 +296,7 @@ ContentSecurityPolicy.prototype = {
|
||||
return;
|
||||
|
||||
// Save the docRequest for fetching a policy-uri
|
||||
this._docRequest = aChannel;
|
||||
this._weakDocRequest = Cu.getWeakReference(aChannel);
|
||||
|
||||
// save the document URI (minus <fragment>) and referrer for reporting
|
||||
let uri = aChannel.URI.cloneIgnoringRef();
|
||||
@ -307,8 +307,9 @@ ContentSecurityPolicy.prototype = {
|
||||
this._requestOrigin = uri;
|
||||
|
||||
//store a reference to the principal, that can later be used in shouldLoad
|
||||
this._requestPrincipal = Components.classes["@mozilla.org/scriptsecuritymanager;1"].
|
||||
getService(Components.interfaces.nsIScriptSecurityManager).getChannelPrincipal(aChannel);
|
||||
this._weakRequestPrincipal = Cu.getWeakReference(Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Ci.nsIScriptSecurityManager)
|
||||
.getChannelPrincipal(aChannel));
|
||||
|
||||
if (aChannel.referrer) {
|
||||
let referrer = aChannel.referrer.cloneIgnoringRef();
|
||||
@ -358,13 +359,13 @@ ContentSecurityPolicy.prototype = {
|
||||
newpolicy = CSPRep.fromStringSpecCompliant(aPolicy,
|
||||
selfURI,
|
||||
aReportOnly,
|
||||
this._docRequest,
|
||||
this._weakDocRequest.get(),
|
||||
this);
|
||||
} else {
|
||||
newpolicy = CSPRep.fromString(aPolicy,
|
||||
selfURI,
|
||||
aReportOnly,
|
||||
this._docRequest,
|
||||
this._weakDocRequest.get(),
|
||||
this);
|
||||
}
|
||||
|
||||
@ -481,8 +482,8 @@ ContentSecurityPolicy.prototype = {
|
||||
// we need to set an nsIChannelEventSink on the channel object
|
||||
// so we can tell it to not follow redirects when posting the reports
|
||||
chan.notificationCallbacks = new CSPReportRedirectSink(policy);
|
||||
if (this._docRequest) {
|
||||
chan.loadGroup = this._docRequest.loadGroup;
|
||||
if (this._weakDocRequest.get()) {
|
||||
chan.loadGroup = this._weakDocRequest.get().loadGroup;
|
||||
}
|
||||
|
||||
chan.QueryInterface(Ci.nsIUploadChannel)
|
||||
@ -501,7 +502,7 @@ ContentSecurityPolicy.prototype = {
|
||||
.getService(Ci.nsIContentPolicy);
|
||||
if (contentPolicy.shouldLoad(Ci.nsIContentPolicy.TYPE_CSP_REPORT,
|
||||
chan.URI, this._requestOrigin,
|
||||
null, null, null, this._requestPrincipal)
|
||||
null, null, null, this._weakRequestPrincipal.get())
|
||||
!= Ci.nsIContentPolicy.ACCEPT) {
|
||||
continue; // skip unauthorized URIs
|
||||
}
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "nsObserverService.h"
|
||||
#include "nsFocusManager.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
@ -210,6 +211,16 @@ MarkContentViewer(nsIContentViewer* aViewer, bool aCleanupJS,
|
||||
EnumerateAll(MarkUserData, &nsCCUncollectableMarker::sGeneration);
|
||||
}
|
||||
}
|
||||
if (doc) {
|
||||
nsPIDOMWindow* inner = doc->GetInnerWindow();
|
||||
if (inner) {
|
||||
inner->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
|
||||
}
|
||||
nsPIDOMWindow* outer = doc->GetWindow();
|
||||
if (outer) {
|
||||
outer->MarkUncollectableForCCGeneration(nsCCUncollectableMarker::sGeneration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MarkDocShell(nsIDocShellTreeNode* aNode, bool aCleanupJS,
|
||||
@ -336,6 +347,8 @@ nsCCUncollectableMarker::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
++sGeneration;
|
||||
}
|
||||
|
||||
nsFocusManager::MarkUncollectableForCCGeneration(sGeneration);
|
||||
|
||||
nsresult rv;
|
||||
|
||||
// Iterate all toplevel windows
|
||||
|
@ -2463,8 +2463,11 @@ nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
nsresult rv = InitCSP(aChannel);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
// If this is not a data document, set CSP.
|
||||
if (!mLoadedAsData) {
|
||||
nsresult rv = InitCSP(aChannel);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
27
content/base/test/csp/file_CSP_bug941404.html
Normal file
27
content/base/test/csp/file_CSP_bug941404.html
Normal file
@ -0,0 +1,27 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
|
||||
<!-- this should be allowed (no CSP)-->
|
||||
<img src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=img_good&type=img/png"> </img>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
var req = new XMLHttpRequest();
|
||||
req.onload = function() {
|
||||
//this should be allowed (no CSP)
|
||||
try {
|
||||
var img = document.createElement("img");
|
||||
img.src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=img2_good&type=img/png";
|
||||
document.body.appendChild(img);
|
||||
} catch(e) {
|
||||
console.log("yo: "+e);
|
||||
}
|
||||
};
|
||||
req.open("get", "file_CSP_bug941404_xhr.html", true);
|
||||
req.responseType = "document";
|
||||
req.send();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
5
content/base/test/csp/file_CSP_bug941404_xhr.html
Normal file
5
content/base/test/csp/file_CSP_bug941404_xhr.html
Normal file
@ -0,0 +1,5 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1 @@
|
||||
Content-Security-Policy: default-src 'none' 'unsafe-inline' 'unsafe-eval'
|
15
content/base/test/csp/file_bug886164.html
Normal file
15
content/base/test/csp/file_bug886164.html
Normal file
@ -0,0 +1,15 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
<!-- sandbox="allow-same-origin" -->
|
||||
<!-- Content-Security-Policy: default-src 'self' -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=img_bad&type=img/png"> </img>
|
||||
|
||||
<!-- these should load ok -->
|
||||
<img src="/tests/content/base/test/csp/file_CSP.sjs?testid=img_good&type=img/png" />
|
||||
<script src='/tests/content/base/test/csp/file_CSP.sjs?testid=scripta_bad&type=text/javascript'></script>
|
||||
|
||||
</body>
|
||||
</html>
|
1
content/base/test/csp/file_bug886164.html^headers^
Normal file
1
content/base/test/csp/file_bug886164.html^headers^
Normal file
@ -0,0 +1 @@
|
||||
Content-Security-Policy: default-src 'self'
|
14
content/base/test/csp/file_bug886164_2.html
Normal file
14
content/base/test/csp/file_bug886164_2.html
Normal file
@ -0,0 +1,14 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
<!-- sandbox -->
|
||||
<!-- Content-Security-Policy: default-src 'self' -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=img2_bad&type=img/png"> </img>
|
||||
|
||||
<!-- these should load ok -->
|
||||
<img src="/tests/content/base/test/csp/file_CSP.sjs?testid=img2a_good&type=img/png" />
|
||||
|
||||
</body>
|
||||
</html>
|
1
content/base/test/csp/file_bug886164_2.html^headers^
Normal file
1
content/base/test/csp/file_bug886164_2.html^headers^
Normal file
@ -0,0 +1 @@
|
||||
Content-Security-Policy: default-src 'self'
|
12
content/base/test/csp/file_bug886164_3.html
Normal file
12
content/base/test/csp/file_bug886164_3.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
<!-- sandbox -->
|
||||
<!-- Content-Security-Policy: default-src 'none' -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=img3_bad&type=img/png"> </img>
|
||||
<img src="/tests/content/base/test/csp/file_CSP.sjs?testid=img3a_bad&type=img/png" />
|
||||
|
||||
</body>
|
||||
</html>
|
1
content/base/test/csp/file_bug886164_3.html^headers^
Normal file
1
content/base/test/csp/file_bug886164_3.html^headers^
Normal file
@ -0,0 +1 @@
|
||||
Content-Security-Policy: default-src 'none'
|
12
content/base/test/csp/file_bug886164_4.html
Normal file
12
content/base/test/csp/file_bug886164_4.html
Normal file
@ -0,0 +1,12 @@
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<body>
|
||||
<!-- sandbox -->
|
||||
<!-- Content-Security-Policy: default-src 'none' -->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=img4_bad&type=img/png"> </img>
|
||||
<img src="/tests/content/base/test/csp/file_CSP.sjs?testid=img4a_bad&type=img/png" />
|
||||
|
||||
</body>
|
||||
</html>
|
1
content/base/test/csp/file_bug886164_4.html^headers^
Normal file
1
content/base/test/csp/file_bug886164_4.html^headers^
Normal file
@ -0,0 +1 @@
|
||||
Content-Security-Policy: default-src 'none'
|
26
content/base/test/csp/file_bug886164_5.html
Normal file
26
content/base/test/csp/file_bug886164_5.html
Normal file
@ -0,0 +1,26 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head> <meta charset="utf-8"> </head>
|
||||
<script type="text/javascript">
|
||||
function ok(result, desc) {
|
||||
window.parent.postMessage({ok: result, desc: desc}, "*");
|
||||
}
|
||||
|
||||
function doStuff() {
|
||||
ok(true, "documents sandboxed with allow-scripts should be able to run inline scripts");
|
||||
}
|
||||
</script>
|
||||
<script src='file_iframe_sandbox_pass.js'></script>
|
||||
<body onLoad='ok(true, "documents sandboxed with allow-scripts should be able to run script from event listeners");doStuff();'>
|
||||
I am sandboxed but with only inline "allow-scripts"
|
||||
|
||||
<!-- sandbox="allow-scripts" -->
|
||||
<!-- Content-Security-Policy: default-src 'none' 'unsafe-inline'-->
|
||||
|
||||
<!-- these should be stopped by CSP -->
|
||||
<img src="/tests/content/base/test/csp/file_CSP.sjs?testid=img5_bad&type=img/png" />
|
||||
<img src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=img5a_bad&type=img/png"> </img>
|
||||
<script src='/tests/content/base/test/csp/file_CSP.sjs?testid=script5_bad&type=text/javascript'></script>
|
||||
<script src='http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=script5a_bad&type=text/javascript'></script>
|
||||
</body>
|
||||
</html>
|
1
content/base/test/csp/file_bug886164_5.html^headers^
Normal file
1
content/base/test/csp/file_bug886164_5.html^headers^
Normal file
@ -0,0 +1 @@
|
||||
Content-Security-Policy: default-src 'none' 'unsafe-inline';
|
35
content/base/test/csp/file_bug886164_6.html
Normal file
35
content/base/test/csp/file_bug886164_6.html
Normal file
@ -0,0 +1,35 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
</head>
|
||||
<script type="text/javascript">
|
||||
function ok(result, desc) {
|
||||
window.parent.postMessage({ok: result, desc: desc}, "*");
|
||||
}
|
||||
|
||||
function doStuff() {
|
||||
ok(true, "documents sandboxed with allow-scripts should be able to run inline scripts");
|
||||
|
||||
document.getElementById('a_form').submit();
|
||||
|
||||
// trigger the javascript: url test
|
||||
sendMouseEvent({type:'click'}, 'a_link');
|
||||
}
|
||||
</script>
|
||||
<script src='file_iframe_sandbox_pass.js'></script>
|
||||
<body onLoad='ok(true, "documents sandboxed with allow-scripts should be able to run script from event listeners");doStuff();'>
|
||||
I am sandboxed but with "allow-scripts"
|
||||
<img src="http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=img6_bad&type=img/png"> </img>
|
||||
<script src='http://example.org/tests/content/base/test/csp/file_CSP.sjs?testid=script6_bad&type=text/javascript'></script>
|
||||
|
||||
<form method="get" action="file_iframe_sandbox_form_fail.html" id="a_form">
|
||||
First name: <input type="text" name="firstname">
|
||||
Last name: <input type="text" name="lastname">
|
||||
<input type="submit" onclick="doSubmit()" id="a_button">
|
||||
</form>
|
||||
|
||||
<a href = 'javascript:ok(true, "documents sandboxed with allow-scripts should be able to run script from javascript: URLs");' id='a_link'>click me</a>
|
||||
</body>
|
||||
</html>
|
1
content/base/test/csp/file_bug886164_6.html^headers^
Normal file
1
content/base/test/csp/file_bug886164_6.html^headers^
Normal file
@ -0,0 +1 @@
|
||||
Content-Security-Policy: default-src 'self' 'unsafe-inline';
|
@ -68,6 +68,18 @@ support-files =
|
||||
file_bug836922_npolicies.html^headers^
|
||||
file_bug836922_npolicies_ro_violation.sjs
|
||||
file_bug836922_npolicies_violation.sjs
|
||||
file_bug886164.html
|
||||
file_bug886164.html^headers^
|
||||
file_bug886164_2.html
|
||||
file_bug886164_2.html^headers^
|
||||
file_bug886164_3.html
|
||||
file_bug886164_3.html^headers^
|
||||
file_bug886164_4.html
|
||||
file_bug886164_4.html^headers^
|
||||
file_bug886164_5.html
|
||||
file_bug886164_5.html^headers^
|
||||
file_bug886164_6.html
|
||||
file_bug886164_6.html^headers^
|
||||
file_csp_bug768029.html
|
||||
file_csp_bug768029.sjs
|
||||
file_csp_bug773891.html
|
||||
@ -87,6 +99,9 @@ support-files =
|
||||
file_policyuri_regression_from_multipolicy_policy
|
||||
file_nonce_source.html
|
||||
file_nonce_source.html^headers^
|
||||
file_CSP_bug941404.html
|
||||
file_CSP_bug941404_xhr.html
|
||||
file_CSP_bug941404_xhr.html^headers^
|
||||
|
||||
[test_CSP.html]
|
||||
[test_CSP_bug663567.html]
|
||||
@ -101,8 +116,10 @@ support-files =
|
||||
[test_CSP_inlinestyle.html]
|
||||
[test_bothCSPheaders.html]
|
||||
[test_bug836922_npolicies.html]
|
||||
[test_bug886164.html]
|
||||
[test_csp_redirects.html]
|
||||
[test_CSP_bug910139.html]
|
||||
[test_CSP_bug909029.html]
|
||||
[test_policyuri_regression_from_multipolicy.html]
|
||||
[test_nonce_source.html]
|
||||
[test_CSP_bug941404.html]
|
||||
|
115
content/base/test/csp/test_CSP_bug941404.html
Normal file
115
content/base/test/csp/test_CSP_bug941404.html
Normal file
@ -0,0 +1,115 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Bug 941404 - Data documents should not set CSP</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<iframe style="width:200px;height:200px;" id='cspframe'></iframe>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
|
||||
var path = "/tests/content/base/test/csp/";
|
||||
|
||||
// These are test results: -1 means it hasn't run,
|
||||
// true/false is the pass/fail result.
|
||||
window.tests = {
|
||||
img_good: -1,
|
||||
img2_good: -1,
|
||||
};
|
||||
|
||||
|
||||
//csp related
|
||||
|
||||
// This is used to watch the blocked data bounce off CSP and allowed data
|
||||
// get sent out to the wire.
|
||||
function examiner() {
|
||||
SpecialPowers.addObserver(this, "csp-on-violate-policy", false);
|
||||
SpecialPowers.addObserver(this, "http-on-modify-request", false);
|
||||
}
|
||||
|
||||
examiner.prototype = {
|
||||
observe: function(subject, topic, data) {
|
||||
// subject should be an nsURI, and should be either allowed or blocked.
|
||||
if (!SpecialPowers.can_QI(subject))
|
||||
return;
|
||||
|
||||
var testpat = new RegExp("testid=([a-z0-9_]+)");
|
||||
|
||||
//_good things better be allowed!
|
||||
//_bad things better be stopped!
|
||||
|
||||
if (topic === "http-on-modify-request") {
|
||||
//these things were allowed by CSP
|
||||
var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIHttpChannel"), "URI.asciiSpec");
|
||||
if (!testpat.test(asciiSpec)) return;
|
||||
var testid = testpat.exec(asciiSpec)[1];
|
||||
|
||||
window.testResult(testid,
|
||||
/_good/.test(testid),
|
||||
asciiSpec + " allowed by csp");
|
||||
}
|
||||
|
||||
if(topic === "csp-on-violate-policy") {
|
||||
//these were blocked... record that they were blocked
|
||||
var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
|
||||
if (!testpat.test(asciiSpec)) return;
|
||||
var testid = testpat.exec(asciiSpec)[1];
|
||||
window.testResult(testid,
|
||||
/_bad/.test(testid),
|
||||
asciiSpec + " blocked by \"" + data + "\"");
|
||||
}
|
||||
},
|
||||
|
||||
// must eventually call this to remove the listener,
|
||||
// or mochitests might get borked.
|
||||
remove: function() {
|
||||
SpecialPowers.removeObserver(this, "csp-on-violate-policy");
|
||||
SpecialPowers.removeObserver(this, "http-on-modify-request");
|
||||
}
|
||||
}
|
||||
|
||||
window.examiner = new examiner();
|
||||
|
||||
window.testResult = function(testname, result, msg) {
|
||||
//test already complete.... forget it... remember the first result.
|
||||
if (window.tests[testname] != -1)
|
||||
return;
|
||||
|
||||
window.tests[testname] = result;
|
||||
is(result, true, testname + ' test: ' + msg);
|
||||
|
||||
// if any test is incomplete, keep waiting
|
||||
for (var v in window.tests)
|
||||
if(tests[v] == -1) {
|
||||
console.log(v + " is not complete");
|
||||
return;
|
||||
}
|
||||
|
||||
// ... otherwise, finish
|
||||
window.examiner.remove();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{'set':[["security.csp.speccompliant", true]]},
|
||||
function() {
|
||||
// save this for last so that our listeners are registered.
|
||||
// ... this loads the testbed of good and bad requests.
|
||||
document.getElementById('cspframe').src = 'file_CSP_bug941404.html';
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
183
content/base/test/csp/test_bug886164.html
Normal file
183
content/base/test/csp/test_bug886164.html
Normal file
@ -0,0 +1,183 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Bug 886164 - Enforce CSP in sandboxed iframe</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<iframe style="width:200px;height:200px;" id='cspframe' sandbox="allow-same-origin"></iframe>
|
||||
<iframe style="width:200px;height:200px;" id='cspframe2' sandbox></iframe>
|
||||
<iframe style="width:200px;height:200px;" id='cspframe3' sandbox="allow-same-origin"></iframe>
|
||||
<iframe style="width:200px;height:200px;" id='cspframe4' sandbox></iframe>
|
||||
<iframe style="width:200px;height:200px;" id='cspframe5' sandbox="allow-scripts"></iframe>
|
||||
<iframe style="width:200px;height:200px;" id='cspframe6' sandbox="allow-same-origin allow-scripts"></iframe>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
|
||||
var path = "/tests/content/base/test/csp/";
|
||||
|
||||
// These are test results: -1 means it hasn't run,
|
||||
// true/false is the pass/fail result.
|
||||
window.tests = {
|
||||
// sandbox allow-same-origin; 'self'
|
||||
img_good: -1, // same origin
|
||||
img_bad: -1, //example.com
|
||||
|
||||
// sandbox; 'self'
|
||||
img2_bad: -1, //example.com
|
||||
img2a_good: -1, // same origin & is image
|
||||
|
||||
// sandbox allow-same-origin; 'none'
|
||||
img3_bad: -1,
|
||||
img3a_bad: -1,
|
||||
|
||||
// sandbox; 'none'
|
||||
img4_bad: -1,
|
||||
img4a_bad: -1,
|
||||
|
||||
// sandbox allow-scripts; 'none' 'unsafe-inline'
|
||||
img5_bad: -1,
|
||||
img5a_bad: -1,
|
||||
script5_bad: -1,
|
||||
script5a_bad: -1,
|
||||
|
||||
// sandbox allow-same-origin allow-scripts; 'self' 'unsafe-inline'
|
||||
img6_bad: -1,
|
||||
script6_bad: -1,
|
||||
};
|
||||
|
||||
// a postMessage handler that is used by sandboxed iframes without
|
||||
// 'allow-same-origin' to communicate pass/fail back to this main page.
|
||||
// it expects to be called with an object like {ok: true/false, desc:
|
||||
// <description of the test> which it then forwards to ok()
|
||||
window.addEventListener("message", receiveMessage, false);
|
||||
|
||||
function receiveMessage(event)
|
||||
{
|
||||
ok_wrapper(event.data.ok, event.data.desc);
|
||||
}
|
||||
|
||||
var cspTestsDone = false;
|
||||
var iframeSandboxTestsDone = false;
|
||||
|
||||
// iframe related
|
||||
var completedTests = 0;
|
||||
var passedTests = 0;
|
||||
|
||||
function ok_wrapper(result, desc) {
|
||||
ok(result, desc);
|
||||
|
||||
completedTests++;
|
||||
|
||||
if (result) {
|
||||
passedTests++;
|
||||
}
|
||||
|
||||
if (completedTests === 5) {
|
||||
iframeSandboxTestsDone = true;
|
||||
if (cspTestsDone) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//csp related
|
||||
|
||||
// This is used to watch the blocked data bounce off CSP and allowed data
|
||||
// get sent out to the wire.
|
||||
function examiner() {
|
||||
SpecialPowers.addObserver(this, "csp-on-violate-policy", false);
|
||||
SpecialPowers.addObserver(this, "http-on-modify-request", false);
|
||||
}
|
||||
examiner.prototype = {
|
||||
observe: function(subject, topic, data) {
|
||||
// subject should be an nsURI, and should be either allowed or blocked.
|
||||
if (!SpecialPowers.can_QI(subject))
|
||||
return;
|
||||
|
||||
var testpat = new RegExp("testid=([a-z0-9_]+)");
|
||||
|
||||
//_good things better be allowed!
|
||||
//_bad things better be stopped!
|
||||
|
||||
if (topic === "http-on-modify-request") {
|
||||
//these things were allowed by CSP
|
||||
var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIHttpChannel"), "URI.asciiSpec");
|
||||
if (!testpat.test(asciiSpec)) return;
|
||||
var testid = testpat.exec(asciiSpec)[1];
|
||||
|
||||
window.testResult(testid,
|
||||
/_good/.test(testid),
|
||||
asciiSpec + " allowed by csp");
|
||||
}
|
||||
|
||||
if(topic === "csp-on-violate-policy") {
|
||||
//these were blocked... record that they were blocked
|
||||
var asciiSpec = SpecialPowers.getPrivilegedProps(SpecialPowers.do_QueryInterface(subject, "nsIURI"), "asciiSpec");
|
||||
if (!testpat.test(asciiSpec)) return;
|
||||
var testid = testpat.exec(asciiSpec)[1];
|
||||
window.testResult(testid,
|
||||
/_bad/.test(testid),
|
||||
asciiSpec + " blocked by \"" + data + "\"");
|
||||
}
|
||||
},
|
||||
|
||||
// must eventually call this to remove the listener,
|
||||
// or mochitests might get borked.
|
||||
remove: function() {
|
||||
SpecialPowers.removeObserver(this, "csp-on-violate-policy");
|
||||
SpecialPowers.removeObserver(this, "http-on-modify-request");
|
||||
}
|
||||
}
|
||||
|
||||
window.examiner = new examiner();
|
||||
|
||||
window.testResult = function(testname, result, msg) {
|
||||
//test already complete.... forget it... remember the first result.
|
||||
if (window.tests[testname] != -1)
|
||||
return;
|
||||
|
||||
window.tests[testname] = result;
|
||||
ok(result, testname + ' test: ' + msg);
|
||||
|
||||
// if any test is incomplete, keep waiting
|
||||
for (var v in window.tests)
|
||||
if(tests[v] == -1)
|
||||
return;
|
||||
|
||||
// ... otherwise, finish
|
||||
window.examiner.remove();
|
||||
cspTestsDone = true;
|
||||
if (iframeSandboxTestsDone) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{'set':[["security.csp.speccompliant", true]]},
|
||||
function() {
|
||||
// save this for last so that our listeners are registered.
|
||||
// ... this loads the testbed of good and bad requests.
|
||||
document.getElementById('cspframe').src = 'file_bug886164.html';
|
||||
document.getElementById('cspframe2').src = 'file_bug886164_2.html';
|
||||
document.getElementById('cspframe3').src = 'file_bug886164_3.html';
|
||||
document.getElementById('cspframe4').src = 'file_bug886164_4.html';
|
||||
document.getElementById('cspframe5').src = 'file_bug886164_5.html';
|
||||
document.getElementById('cspframe6').src = 'file_bug886164_6.html';
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -12,10 +12,11 @@
|
||||
<body>
|
||||
<iframe style="width:200px;height:200px;" id='testframe'></iframe>
|
||||
<script class="testbody" type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{'set':[["security.csp.speccompliant", true]]},
|
||||
function() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
function () {
|
||||
var testframe = document.getElementById('testframe');
|
||||
testframe.src = 'file_policyuri_regression_from_multipolicy.html';
|
||||
testframe.addEventListener('load', function checkInlineScriptExecuted () {
|
||||
|
@ -1173,6 +1173,10 @@ WebGLContext::ForceClearFramebufferWithDefaultValues(GLbitfield mask, const bool
|
||||
bool
|
||||
WebGLContext::PresentScreenBuffer()
|
||||
{
|
||||
if (IsContextLost()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mShouldPresent) {
|
||||
return false;
|
||||
}
|
||||
|
@ -371,7 +371,7 @@ public:
|
||||
return GetTexParameter(target, pname);
|
||||
}
|
||||
JS::Value GetUniform(JSContext* cx, WebGLProgram *prog,
|
||||
WebGLUniformLocation *location, ErrorResult& rv);
|
||||
WebGLUniformLocation *location);
|
||||
already_AddRefed<WebGLUniformLocation>
|
||||
GetUniformLocation(WebGLProgram *prog, const nsAString& name);
|
||||
void Hint(GLenum target, GLenum mode);
|
||||
@ -425,7 +425,7 @@ public:
|
||||
nsLayoutUtils::SurfaceFromElementResult res = SurfaceFromElement(elt);
|
||||
rv = SurfaceFromElementResultToImageSurface(res, getter_AddRefs(isurf),
|
||||
&srcFormat);
|
||||
if (rv.Failed())
|
||||
if (rv.Failed() || !isurf)
|
||||
return;
|
||||
|
||||
uint32_t byteLength = isurf->Stride() * isurf->Height();
|
||||
@ -464,7 +464,7 @@ public:
|
||||
nsLayoutUtils::SurfaceFromElementResult res = SurfaceFromElement(elt);
|
||||
rv = SurfaceFromElementResultToImageSurface(res, getter_AddRefs(isurf),
|
||||
&srcFormat);
|
||||
if (rv.Failed())
|
||||
if (rv.Failed() || !isurf)
|
||||
return;
|
||||
|
||||
uint32_t byteLength = isurf->Stride() * isurf->Height();
|
||||
|
@ -1807,7 +1807,7 @@ WebGLContext::GetTexParameter(GLenum target, GLenum pname)
|
||||
|
||||
JS::Value
|
||||
WebGLContext::GetUniform(JSContext* cx, WebGLProgram *prog,
|
||||
WebGLUniformLocation *location, ErrorResult& rv)
|
||||
WebGLUniformLocation *location)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return JS::NullValue();
|
||||
@ -1876,20 +1876,20 @@ WebGLContext::GetUniform(JSContext* cx, WebGLProgram *prog,
|
||||
}
|
||||
|
||||
if (index == uniforms) {
|
||||
rv.Throw(NS_ERROR_FAILURE); // XXX GL error? shouldn't happen.
|
||||
GenerateWarning("getUniform: internal error: hit an OpenGL driver bug");
|
||||
return JS::NullValue();
|
||||
}
|
||||
|
||||
GLenum baseType;
|
||||
GLint unitSize;
|
||||
if (!BaseTypeAndSizeFromUniformType(uniformType, &baseType, &unitSize)) {
|
||||
rv.Throw(NS_ERROR_FAILURE);
|
||||
GenerateWarning("getUniform: internal error: unknown uniform type 0x%x", uniformType);
|
||||
return JS::NullValue();
|
||||
}
|
||||
|
||||
// this should never happen
|
||||
if (unitSize > 16) {
|
||||
rv.Throw(NS_ERROR_FAILURE);
|
||||
GenerateWarning("getUniform: internal error: unexpected uniform unit size %d", unitSize);
|
||||
return JS::NullValue();
|
||||
}
|
||||
|
||||
@ -1901,7 +1901,7 @@ WebGLContext::GetUniform(JSContext* cx, WebGLProgram *prog,
|
||||
} else {
|
||||
JSObject* obj = Float32Array::Create(cx, this, unitSize, fv);
|
||||
if (!obj) {
|
||||
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
ErrorOutOfMemory("getUniform: out of memory");
|
||||
}
|
||||
return JS::ObjectOrNullValue(obj);
|
||||
}
|
||||
@ -1913,7 +1913,7 @@ WebGLContext::GetUniform(JSContext* cx, WebGLProgram *prog,
|
||||
} else {
|
||||
JSObject* obj = Int32Array::Create(cx, this, unitSize, iv);
|
||||
if (!obj) {
|
||||
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
ErrorOutOfMemory("getUniform: out of memory");
|
||||
}
|
||||
return JS::ObjectOrNullValue(obj);
|
||||
}
|
||||
@ -1928,7 +1928,7 @@ WebGLContext::GetUniform(JSContext* cx, WebGLProgram *prog,
|
||||
uv[k] = JS::BooleanValue(iv[k] ? true : false);
|
||||
JSObject* obj = JS_NewArrayObject(cx, unitSize, uv);
|
||||
if (!obj) {
|
||||
rv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
ErrorOutOfMemory("getUniform: out of memory");
|
||||
}
|
||||
return JS::ObjectOrNullValue(obj);
|
||||
}
|
||||
@ -2639,11 +2639,14 @@ nsresult
|
||||
WebGLContext::SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromElementResult& res,
|
||||
gfxImageSurface **imageOut, WebGLTexelFormat *format)
|
||||
{
|
||||
*imageOut = nullptr;
|
||||
*format = WebGLTexelFormat::None;
|
||||
|
||||
if (!res.mSurface)
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_OK;
|
||||
if (res.mSurface->GetType() != gfxSurfaceTypeImage) {
|
||||
// SurfaceFromElement lied!
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// We disallow loading cross-domain images and videos that have not been validated
|
||||
|
@ -37,7 +37,7 @@ class WebGLImageConverter
|
||||
* texels with typed pointers and this value will tell us by how much we need
|
||||
* to increment these pointers to advance to the next texel.
|
||||
*/
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format>
|
||||
template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) Format>
|
||||
static size_t NumElementsPerTexelForFormat() {
|
||||
switch (Format) {
|
||||
case WebGLTexelFormat::R8:
|
||||
@ -73,9 +73,9 @@ class WebGLImageConverter
|
||||
* to return immediately in these cases to allow the compiler to avoid generating
|
||||
* useless code.
|
||||
*/
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) SrcFormat,
|
||||
MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) DstFormat,
|
||||
MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelPremultiplicationOp) PremultiplicationOp>
|
||||
template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) SrcFormat,
|
||||
MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) DstFormat,
|
||||
MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelPremultiplicationOp) PremultiplicationOp>
|
||||
void run()
|
||||
{
|
||||
// check for never-called cases. We early-return to allow the compiler
|
||||
@ -146,9 +146,9 @@ class WebGLImageConverter
|
||||
typename DataTypeForFormat<DstFormat>::Type
|
||||
DstType;
|
||||
|
||||
const MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) IntermediateSrcFormat
|
||||
const MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) IntermediateSrcFormat
|
||||
= IntermediateFormat<SrcFormat>::Value;
|
||||
const MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) IntermediateDstFormat
|
||||
const MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) IntermediateDstFormat
|
||||
= IntermediateFormat<DstFormat>::Value;
|
||||
typedef
|
||||
typename DataTypeForFormat<IntermediateSrcFormat>::Type
|
||||
@ -213,8 +213,8 @@ class WebGLImageConverter
|
||||
return;
|
||||
}
|
||||
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) SrcFormat,
|
||||
MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) DstFormat>
|
||||
template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) SrcFormat,
|
||||
MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) DstFormat>
|
||||
void run(WebGLTexelPremultiplicationOp premultiplicationOp)
|
||||
{
|
||||
#define WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP(PremultiplicationOp) \
|
||||
@ -232,7 +232,7 @@ class WebGLImageConverter
|
||||
#undef WEBGLIMAGECONVERTER_CASE_PREMULTIPLICATIONOP
|
||||
}
|
||||
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) SrcFormat>
|
||||
template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) SrcFormat>
|
||||
void run(WebGLTexelFormat dstFormat,
|
||||
WebGLTexelPremultiplicationOp premultiplicationOp)
|
||||
{
|
||||
|
@ -46,14 +46,7 @@ MOZ_END_ENUM_CLASS(WebGLTexelPremultiplicationOp)
|
||||
|
||||
namespace WebGLTexelConversions {
|
||||
|
||||
// remove this as soon as B2G and Windows use newer compilers
|
||||
#ifdef MOZ_HAVE_CXX11_STRONG_ENUMS
|
||||
#define MOZ_ENUM_CLASS_INTEGER_TYPE(X) X
|
||||
#else
|
||||
#define MOZ_ENUM_CLASS_INTEGER_TYPE(X) X::Enum
|
||||
#endif
|
||||
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format>
|
||||
template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) Format>
|
||||
struct IsFloatFormat
|
||||
{
|
||||
static const bool Value =
|
||||
@ -64,7 +57,7 @@ struct IsFloatFormat
|
||||
Format == WebGLTexelFormat::A32F;
|
||||
};
|
||||
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format>
|
||||
template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) Format>
|
||||
struct Is16bppFormat
|
||||
{
|
||||
static const bool Value =
|
||||
@ -73,7 +66,7 @@ struct Is16bppFormat
|
||||
Format == WebGLTexelFormat::RGB565;
|
||||
};
|
||||
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format,
|
||||
template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) Format,
|
||||
bool IsFloat = IsFloatFormat<Format>::Value,
|
||||
bool Is16bpp = Is16bppFormat<Format>::Value>
|
||||
struct DataTypeForFormat
|
||||
@ -81,22 +74,22 @@ struct DataTypeForFormat
|
||||
typedef uint8_t Type;
|
||||
};
|
||||
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format>
|
||||
template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) Format>
|
||||
struct DataTypeForFormat<Format, true, false>
|
||||
{
|
||||
typedef float Type;
|
||||
};
|
||||
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format>
|
||||
template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) Format>
|
||||
struct DataTypeForFormat<Format, false, true>
|
||||
{
|
||||
typedef uint16_t Type;
|
||||
};
|
||||
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format>
|
||||
template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) Format>
|
||||
struct IntermediateFormat
|
||||
{
|
||||
static const MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Value
|
||||
static const MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) Value
|
||||
= IsFloatFormat<Format>::Value
|
||||
? WebGLTexelFormat::RGBA32F
|
||||
: WebGLTexelFormat::RGBA8;
|
||||
@ -172,7 +165,7 @@ MOZ_ALWAYS_INLINE bool HasColor(WebGLTexelFormat format) {
|
||||
//----------------------------------------------------------------------
|
||||
// Pixel unpacking routines.
|
||||
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format, typename SrcType, typename DstType>
|
||||
template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) Format, typename SrcType, typename DstType>
|
||||
MOZ_ALWAYS_INLINE void
|
||||
unpack(const SrcType* __restrict src,
|
||||
DstType* __restrict dst)
|
||||
@ -332,8 +325,8 @@ unpack<WebGLTexelFormat::A32F, float, float>(const float* __restrict src, float*
|
||||
// Pixel packing routines.
|
||||
//
|
||||
|
||||
template<MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelFormat) Format,
|
||||
MOZ_ENUM_CLASS_INTEGER_TYPE(WebGLTexelPremultiplicationOp) PremultiplicationOp,
|
||||
template<MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelFormat) Format,
|
||||
MOZ_ENUM_CLASS_ENUM_TYPE(WebGLTexelPremultiplicationOp) PremultiplicationOp,
|
||||
typename SrcType,
|
||||
typename DstType>
|
||||
MOZ_ALWAYS_INLINE void
|
||||
|
@ -96,6 +96,8 @@ MOZ_END_ENUM_CLASS(WebGLImageDataStatus)
|
||||
* textures from DOM elements. See gfxImageSurface::Format().
|
||||
*/
|
||||
MOZ_BEGIN_ENUM_CLASS(WebGLTexelFormat, int)
|
||||
// returned by SurfaceFromElementResultToImageSurface to indicate absence of image data
|
||||
None,
|
||||
// dummy error code returned by GetWebGLTexelFormat in error cases,
|
||||
// after assertion failure (so this never happens in debug builds)
|
||||
BadFormat,
|
||||
|
@ -117,7 +117,6 @@ UNIFIED_SOURCES += [
|
||||
'DOMMediaStream.cpp',
|
||||
'EncodedBufferCache.cpp',
|
||||
'FileBlockCache.cpp',
|
||||
'Latency.cpp',
|
||||
'MediaCache.cpp',
|
||||
'MediaDecoder.cpp',
|
||||
'MediaDecoderReader.cpp',
|
||||
@ -144,8 +143,10 @@ UNIFIED_SOURCES += [
|
||||
]
|
||||
|
||||
# DecoderTraits.cpp needs to be built separately because of Mac OS X headers.
|
||||
# Latency.cpp needs to be built separately because it forces NSPR logging.
|
||||
SOURCES += [
|
||||
'DecoderTraits.cpp',
|
||||
'Latency.cpp',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -51,7 +51,6 @@ UNIFIED_SOURCES += [
|
||||
'LoadContext.cpp',
|
||||
'nsAboutRedirector.cpp',
|
||||
'nsDefaultURIFixup.cpp',
|
||||
'nsDocShell.cpp',
|
||||
'nsDocShellEditorData.cpp',
|
||||
'nsDocShellEnumerator.cpp',
|
||||
'nsDocShellLoadInfo.cpp',
|
||||
@ -62,6 +61,11 @@ UNIFIED_SOURCES += [
|
||||
'SerializedLoadContext.cpp',
|
||||
]
|
||||
|
||||
# nsDocShell.cpp cannot be built in unified mode because it forces NSPR logging.
|
||||
SOURCES += [
|
||||
'nsDocShell.cpp',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
MSVC_ENABLE_PGO = True
|
||||
|
@ -82,7 +82,6 @@ UNIFIED_SOURCES += [
|
||||
'nsFocusManager.cpp',
|
||||
'nsGlobalWindowCommands.cpp',
|
||||
'nsHistory.cpp',
|
||||
'nsJSEnvironment.cpp',
|
||||
'nsJSTimeoutHandler.cpp',
|
||||
'nsJSUtils.cpp',
|
||||
'nsLocation.cpp',
|
||||
@ -107,6 +106,8 @@ SOURCES += [
|
||||
'nsDOMWindowUtils.cpp',
|
||||
# This file has a #error "Never include windows.h in this file!"
|
||||
'nsGlobalWindow.cpp',
|
||||
# This file forces NSPR logging.
|
||||
'nsJSEnvironment.cpp',
|
||||
# nsPluginArray.cpp includes npapi.h indirectly, and that includes a lot of system headers
|
||||
'nsPluginArray.cpp',
|
||||
]
|
||||
|
@ -3436,6 +3436,43 @@ nsFocusManager::SetFocusedWindowInternal(nsPIDOMWindow* aWindow)
|
||||
mFocusedWindow = aWindow;
|
||||
}
|
||||
|
||||
void
|
||||
nsFocusManager::MarkUncollectableForCCGeneration(uint32_t aGeneration)
|
||||
{
|
||||
if (!sInstance) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sInstance->mActiveWindow) {
|
||||
sInstance->mActiveWindow->
|
||||
MarkUncollectableForCCGeneration(aGeneration);
|
||||
}
|
||||
if (sInstance->mFocusedWindow) {
|
||||
sInstance->mFocusedWindow->
|
||||
MarkUncollectableForCCGeneration(aGeneration);
|
||||
}
|
||||
if (sInstance->mWindowBeingLowered) {
|
||||
sInstance->mWindowBeingLowered->
|
||||
MarkUncollectableForCCGeneration(aGeneration);
|
||||
}
|
||||
if (sInstance->mFocusedContent) {
|
||||
sInstance->mFocusedContent->OwnerDoc()->
|
||||
MarkUncollectableForCCGeneration(aGeneration);
|
||||
}
|
||||
if (sInstance->mFirstBlurEvent) {
|
||||
sInstance->mFirstBlurEvent->OwnerDoc()->
|
||||
MarkUncollectableForCCGeneration(aGeneration);
|
||||
}
|
||||
if (sInstance->mFirstFocusEvent) {
|
||||
sInstance->mFirstFocusEvent->OwnerDoc()->
|
||||
MarkUncollectableForCCGeneration(aGeneration);
|
||||
}
|
||||
if (sInstance->mMouseDownEventHandlingDocument) {
|
||||
sInstance->mMouseDownEventHandlingDocument->
|
||||
MarkUncollectableForCCGeneration(aGeneration);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
NS_NewFocusManager(nsIFocusManager** aResult)
|
||||
{
|
||||
|
@ -121,6 +121,7 @@ public:
|
||||
|
||||
static bool sMouseFocusesFormControl;
|
||||
|
||||
static void MarkUncollectableForCCGeneration(uint32_t aGeneration);
|
||||
protected:
|
||||
|
||||
nsFocusManager();
|
||||
|
@ -550,7 +550,8 @@ nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow)
|
||||
mIsActive(false), mIsBackground(false),
|
||||
mInnerWindow(nullptr), mOuterWindow(aOuterWindow),
|
||||
// Make sure no actual window ends up with mWindowID == 0
|
||||
mWindowID(++gNextWindowID), mHasNotifiedGlobalCreated(false)
|
||||
mWindowID(++gNextWindowID), mHasNotifiedGlobalCreated(false),
|
||||
mMarkedCCGeneration(0)
|
||||
{}
|
||||
|
||||
nsPIDOMWindow::~nsPIDOMWindow() {}
|
||||
@ -1619,7 +1620,7 @@ MarkXBLHandlers(nsXBLPrototypeHandler* aKey, JS::Heap<JSObject*>& aData, void* a
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)
|
||||
if (tmp->IsBlackForCC()) {
|
||||
if (tmp->IsBlackForCC(false)) {
|
||||
if (tmp->mCachedXBLPrototypeHandlers) {
|
||||
tmp->mCachedXBLPrototypeHandlers->Enumerate(MarkXBLHandlers, nullptr);
|
||||
}
|
||||
@ -1632,11 +1633,11 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(nsGlobalWindow)
|
||||
return tmp->IsBlackForCC();
|
||||
return tmp->IsBlackForCC(true);
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsGlobalWindow)
|
||||
return tmp->IsBlackForCC();
|
||||
return tmp->IsBlackForCC(false);
|
||||
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
|
||||
|
||||
inline void
|
||||
@ -1659,10 +1660,6 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_DESCRIBE(nsGlobalWindow, tmp->mRefCnt.get())
|
||||
}
|
||||
|
||||
if (!cb.WantAllTraces() && tmp->IsBlackForCC()) {
|
||||
return NS_SUCCESS_INTERRUPTED_TRAVERSE;
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContext)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
|
||||
@ -1791,12 +1788,16 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsGlobalWindow)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
bool
|
||||
nsGlobalWindow::IsBlackForCC()
|
||||
nsGlobalWindow::IsBlackForCC(bool aTracingNeeded)
|
||||
{
|
||||
return
|
||||
(mDoc &&
|
||||
nsCCUncollectableMarker::InGeneration(mDoc->GetMarkedCCGeneration())) ||
|
||||
(nsCCUncollectableMarker::sGeneration && IsBlack());
|
||||
if (!nsCCUncollectableMarker::sGeneration) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (nsCCUncollectableMarker::InGeneration(GetMarkedCCGeneration()) ||
|
||||
IsBlack()) &&
|
||||
(!aTracingNeeded ||
|
||||
HasNothingToTrace(static_cast<nsIDOMEventTarget*>(this)));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -355,7 +355,7 @@ public:
|
||||
void PoisonOuterWindowProxy(JSObject *aObject);
|
||||
virtual void OnFinalize(JSObject* aObject);
|
||||
|
||||
virtual bool IsBlackForCC();
|
||||
virtual bool IsBlackForCC(bool aTracingNeeded = true);
|
||||
|
||||
// nsIScriptObjectPrincipal
|
||||
virtual nsIPrincipal* GetPrincipal();
|
||||
|
@ -27,8 +27,8 @@ NS_HandleScriptError(nsIScriptGlobalObject *aScriptGlobal,
|
||||
|
||||
|
||||
#define NS_ISCRIPTGLOBALOBJECT_IID \
|
||||
{ 0xa6c0bfae, 0x8be4, 0x4747, \
|
||||
{ 0xaf, 0x1a, 0xe3, 0xf0, 0x3f, 0xb6, 0x0e, 0xb8 } }
|
||||
{ 0x30c64680, 0x909a, 0x4435, \
|
||||
{ 0x90, 0x3b, 0x29, 0x3e, 0xb5, 0x5d, 0xc7, 0xa0 } }
|
||||
|
||||
/**
|
||||
* The global object which keeps a script context for each supported script
|
||||
@ -80,7 +80,7 @@ public:
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
virtual bool IsBlackForCC() { return false; }
|
||||
virtual bool IsBlackForCC(bool aTracingNeeded = true) { return false; }
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptGlobalObject,
|
||||
|
@ -60,8 +60,8 @@ enum UIStateChangeType
|
||||
};
|
||||
|
||||
#define NS_PIDOMWINDOW_IID \
|
||||
{ 0x4f4eadf9, 0xe795, 0x48e5, \
|
||||
{ 0x89, 0x4b, 0x04, 0x40, 0xb2, 0x5d, 0xa6, 0xfa } }
|
||||
{ 0xf26953de, 0xa799, 0x4a92, \
|
||||
{ 0x87, 0x49, 0x7c, 0x37, 0xe5, 0x90, 0x3f, 0x37 } }
|
||||
|
||||
class nsPIDOMWindow : public nsIDOMWindowInternal
|
||||
{
|
||||
@ -653,6 +653,15 @@ public:
|
||||
// WebIDL-ish APIs
|
||||
nsPerformance* GetPerformance();
|
||||
|
||||
void MarkUncollectableForCCGeneration(uint32_t aGeneration)
|
||||
{
|
||||
mMarkedCCGeneration = aGeneration;
|
||||
}
|
||||
|
||||
uint32_t GetMarkedCCGeneration()
|
||||
{
|
||||
return mMarkedCCGeneration;
|
||||
}
|
||||
protected:
|
||||
// The nsPIDOMWindow constructor. The aOuterWindow argument should
|
||||
// be null if and only if the created window itself is an outer
|
||||
@ -736,6 +745,8 @@ protected:
|
||||
// This is only used by the inner window. Set to true once we've sent
|
||||
// the (chrome|content)-document-global-created notification.
|
||||
bool mHasNotifiedGlobalCreated;
|
||||
|
||||
uint32_t mMarkedCCGeneration;
|
||||
};
|
||||
|
||||
|
||||
|
@ -156,6 +156,8 @@ public:
|
||||
*/
|
||||
bool IsBlackAndDoesNotNeedTracing(nsISupports* aThis);
|
||||
|
||||
bool HasNothingToTrace(nsISupports* aThis);
|
||||
|
||||
// Only meant to be called by code that preserves a wrapper.
|
||||
void SetPreservingWrapper(bool aPreserve)
|
||||
{
|
||||
|
@ -36,17 +36,20 @@ SearchGray(void* aGCThing, const char* aName, void* aClosure)
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
nsWrapperCache::HasNothingToTrace(nsISupports* aThis)
|
||||
{
|
||||
nsXPCOMCycleCollectionParticipant* participant = nullptr;
|
||||
CallQueryInterface(aThis, &participant);
|
||||
bool hasGrayObjects = false;
|
||||
participant->Trace(aThis, TraceCallbackFunc(SearchGray), &hasGrayObjects);
|
||||
return !hasGrayObjects;
|
||||
}
|
||||
|
||||
inline bool
|
||||
nsWrapperCache::IsBlackAndDoesNotNeedTracing(nsISupports* aThis)
|
||||
{
|
||||
if (IsBlack()) {
|
||||
nsXPCOMCycleCollectionParticipant* participant = nullptr;
|
||||
CallQueryInterface(aThis, &participant);
|
||||
bool hasGrayObjects = false;
|
||||
participant->Trace(aThis, TraceCallbackFunc(SearchGray), &hasGrayObjects);
|
||||
return !hasGrayObjects;
|
||||
}
|
||||
return false;
|
||||
return IsBlack() && HasNothingToTrace(aThis);
|
||||
}
|
||||
|
||||
inline void
|
||||
|
@ -2147,7 +2147,7 @@ ThreadsafeCheckIsChrome(JSContext* aCx, JSObject* aObj)
|
||||
{
|
||||
using mozilla::dom::workers::GetWorkerPrivateFromContext;
|
||||
return NS_IsMainThread() ? xpc::AccessCheck::isChrome(aObj):
|
||||
GetWorkerPrivateFromContext(aCx)->IsChromeWorker();
|
||||
GetWorkerPrivateFromContext(aCx)->UsesSystemPrincipal();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -4,16 +4,8 @@
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
EncodingUtils.$(OBJ_SUFFIX): labelsencodings.properties.h
|
||||
FallbackEncoding.$(OBJ_SUFFIX): localesfallbacks.properties.h
|
||||
|
||||
PROPS2ARRAYS = $(topsrcdir)/intl/locale/src/props2arrays.py
|
||||
labelsencodings.properties.h: $(PROPS2ARRAYS) labelsencodings.properties
|
||||
$(PYTHON) $^ $@
|
||||
localesfallbacks.properties.h: $(PROPS2ARRAYS) localesfallbacks.properties
|
||||
$(PYTHON) $^ $@
|
||||
|
||||
GARBAGE += \
|
||||
labelsencodings.properties.h \
|
||||
localesfallbacks.properties.h \
|
||||
$(NULL)
|
||||
|
@ -30,3 +30,7 @@ LOCAL_INCLUDES += [
|
||||
'/intl/locale/src',
|
||||
]
|
||||
|
||||
GENERATED_FILES += [
|
||||
'labelsencodings.properties.h',
|
||||
'localesfallbacks.properties.h',
|
||||
]
|
||||
|
@ -33,7 +33,7 @@ EXPORTS.mozilla.dom.file += [
|
||||
'LockedFile.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
UNIFIED_SOURCES += [
|
||||
'ArchiveEvent.cpp',
|
||||
'ArchiveReader.cpp',
|
||||
'ArchiveRequest.cpp',
|
||||
|
@ -278,7 +278,7 @@ IDBRequest::CaptureCaller()
|
||||
const char* filename = nullptr;
|
||||
uint32_t lineNo = 0;
|
||||
if (!nsJSUtils::GetCallingLocation(cx, &filename, &lineNo)) {
|
||||
MOZ_CRASH("Failed to get caller.");
|
||||
NS_WARNING("Failed to get caller.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -112,3 +112,4 @@ support-files =
|
||||
[test_webapp_clearBrowserData_inproc_inproc.html]
|
||||
[test_webapp_clearBrowserData_inproc_oop.html]
|
||||
[test_webapp_clearBrowserData_oop_inproc.html]
|
||||
[test_bug937006.html]
|
||||
|
37
dom/indexedDB/test/test_bug937006.html
Normal file
37
dom/indexedDB/test/test_bug937006.html
Normal file
@ -0,0 +1,37 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 937006 - "Hit MOZ_CRASH(Failed to get caller.)" using setTimeout on IndexedDB call</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
|
||||
</head>
|
||||
<body onload="runTest();">
|
||||
<script type="text/javascript;version=1.7">
|
||||
|
||||
function runTest() {
|
||||
if (!SpecialPowers.isMainProcess()) {
|
||||
window.runTest = function() {
|
||||
todo(false, "Figure out this test for child processes!");
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// doing this IDBRequest should not be able to retrieve the filename and
|
||||
// line number.
|
||||
//setTimeout(indexedDB.deleteDatabase.bind(indexedDB), 0, 'x');
|
||||
setTimeout(function() {
|
||||
ok(true, "Still alive");
|
||||
SimpleTest.finish();
|
||||
}, 10);
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -23,6 +23,8 @@
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
using namespace workers;
|
||||
|
||||
NS_IMPL_ISUPPORTS0(PromiseNativeHandler)
|
||||
|
||||
// PromiseTask
|
||||
@ -54,36 +56,65 @@ private:
|
||||
nsRefPtr<Promise> mPromise;
|
||||
};
|
||||
|
||||
// This class processes the promise's callbacks with promise's result.
|
||||
class PromiseResolverTask MOZ_FINAL : public nsRunnable
|
||||
class WorkerPromiseTask MOZ_FINAL : public WorkerRunnable
|
||||
{
|
||||
public:
|
||||
PromiseResolverTask(Promise* aPromise,
|
||||
JS::Handle<JS::Value> aValue,
|
||||
Promise::PromiseState aState)
|
||||
WorkerPromiseTask(WorkerPrivate* aWorkerPrivate, Promise* aPromise)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThread,
|
||||
UnchangedBusyCount, SkipWhenClearing)
|
||||
, mPromise(aPromise)
|
||||
{
|
||||
MOZ_ASSERT(aPromise);
|
||||
MOZ_COUNT_CTOR(WorkerPromiseTask);
|
||||
}
|
||||
|
||||
~WorkerPromiseTask()
|
||||
{
|
||||
MOZ_COUNT_DTOR(WorkerPromiseTask);
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
mPromise->mTaskPending = false;
|
||||
mPromise->RunTask();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<Promise> mPromise;
|
||||
};
|
||||
|
||||
class PromiseResolverMixin
|
||||
{
|
||||
public:
|
||||
PromiseResolverMixin(Promise* aPromise,
|
||||
JS::Handle<JS::Value> aValue,
|
||||
Promise::PromiseState aState)
|
||||
: mPromise(aPromise)
|
||||
, mValue(aValue)
|
||||
, mState(aState)
|
||||
{
|
||||
MOZ_ASSERT(aPromise);
|
||||
MOZ_ASSERT(mState != Promise::Pending);
|
||||
MOZ_COUNT_CTOR(PromiseResolverTask);
|
||||
MOZ_COUNT_CTOR(PromiseResolverMixin);
|
||||
|
||||
JSContext* cx = nsContentUtils::GetSafeJSContext();
|
||||
JSContext* cx = nsContentUtils::GetDefaultJSContextForThread();
|
||||
|
||||
/* It's safe to use unsafeGet() here: the unsafeness comes from the
|
||||
* possibility of updating the value of mJSObject without triggering the
|
||||
* barriers. However if the value will always be marked, post barriers
|
||||
* unnecessary. */
|
||||
JS_AddNamedValueRootRT(JS_GetRuntime(cx), mValue.unsafeGet(),
|
||||
"PromiseResolverTask.mValue");
|
||||
"PromiseResolverMixin.mValue");
|
||||
}
|
||||
|
||||
~PromiseResolverTask()
|
||||
virtual ~PromiseResolverMixin()
|
||||
{
|
||||
MOZ_COUNT_DTOR(PromiseResolverTask);
|
||||
NS_ASSERT_OWNINGTHREAD(PromiseResolverMixin);
|
||||
MOZ_COUNT_DTOR(PromiseResolverMixin);
|
||||
|
||||
JSContext* cx = nsContentUtils::GetSafeJSContext();
|
||||
JSContext* cx = nsContentUtils::GetDefaultJSContextForThread();
|
||||
|
||||
/* It's safe to use unsafeGet() here: the unsafeness comes from the
|
||||
* possibility of updating the value of mJSObject without triggering the
|
||||
@ -92,18 +123,66 @@ public:
|
||||
JS_RemoveValueRootRT(JS_GetRuntime(cx), mValue.unsafeGet());
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
protected:
|
||||
void
|
||||
RunInternal()
|
||||
{
|
||||
NS_ASSERT_OWNINGTHREAD(PromiseResolverMixin);
|
||||
mPromise->RunResolveTask(
|
||||
JS::Handle<JS::Value>::fromMarkedLocation(mValue.address()),
|
||||
mState, Promise::SyncTask);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<Promise> mPromise;
|
||||
JS::Heap<JS::Value> mValue;
|
||||
Promise::PromiseState mState;
|
||||
NS_DECL_OWNINGTHREAD;
|
||||
};
|
||||
|
||||
// This class processes the promise's callbacks with promise's result.
|
||||
class PromiseResolverTask MOZ_FINAL : public nsRunnable,
|
||||
public PromiseResolverMixin
|
||||
{
|
||||
public:
|
||||
PromiseResolverTask(Promise* aPromise,
|
||||
JS::Handle<JS::Value> aValue,
|
||||
Promise::PromiseState aState)
|
||||
: PromiseResolverMixin(aPromise, aValue, aState)
|
||||
{}
|
||||
|
||||
~PromiseResolverTask()
|
||||
{}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
RunInternal();
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
class WorkerPromiseResolverTask MOZ_FINAL : public WorkerRunnable,
|
||||
public PromiseResolverMixin
|
||||
{
|
||||
public:
|
||||
WorkerPromiseResolverTask(WorkerPrivate* aWorkerPrivate,
|
||||
Promise* aPromise,
|
||||
JS::Handle<JS::Value> aValue,
|
||||
Promise::PromiseState aState)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThread,
|
||||
UnchangedBusyCount, SkipWhenClearing),
|
||||
PromiseResolverMixin(aPromise, aValue, aState)
|
||||
{}
|
||||
|
||||
~WorkerPromiseResolverTask()
|
||||
{}
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
RunInternal();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Promise
|
||||
@ -166,27 +245,23 @@ Promise::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
||||
return PromiseBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
Promise::PrefEnabled()
|
||||
{
|
||||
return Preferences::GetBool("dom.promise.enabled", false);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
Promise::EnabledForScope(JSContext* aCx, JSObject* /* unused */)
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
// No direct return so the chrome/certified app checks happen below.
|
||||
if (Preferences::GetBool("dom.promise.enabled", false)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx);
|
||||
return workerPrivate->PromiseEnabled() || workerPrivate->UsesSystemPrincipal();
|
||||
}
|
||||
// Enable if the pref is enabled or if we're chrome or if we're a
|
||||
// certified app.
|
||||
if (PrefEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Note that we have no concept of a certified app in workers.
|
||||
// XXXbz well, why not?
|
||||
if (!NS_IsMainThread()) {
|
||||
return workers::GetWorkerPrivateFromContext(aCx)->IsChromeWorker();
|
||||
}
|
||||
|
||||
// FIXME(nsm): Remove these checks once promises are enabled by default.
|
||||
nsIPrincipal* prin = nsContentUtils::GetSubjectPrincipal();
|
||||
return nsContentUtils::IsSystemPrincipal(prin) ||
|
||||
prin->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED;
|
||||
@ -278,10 +353,15 @@ Promise::Constructor(const GlobalObject& aGlobal,
|
||||
PromiseInit& aInit, ErrorResult& aRv)
|
||||
{
|
||||
JSContext* cx = aGlobal.GetContext();
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
nsCOMPtr<nsPIDOMWindow> window;
|
||||
|
||||
// On workers, let the window be null.
|
||||
if (MOZ_LIKELY(NS_IsMainThread())) {
|
||||
window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = new Promise(window);
|
||||
@ -322,10 +402,13 @@ Promise::Constructor(const GlobalObject& aGlobal,
|
||||
Promise::Resolve(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
const Optional<JS::Handle<JS::Value>>& aValue, ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
nsCOMPtr<nsPIDOMWindow> window;
|
||||
if (MOZ_LIKELY(NS_IsMainThread())) {
|
||||
window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = new Promise(window);
|
||||
@ -339,10 +422,13 @@ Promise::Resolve(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
Promise::Reject(const GlobalObject& aGlobal, JSContext* aCx,
|
||||
const Optional<JS::Handle<JS::Value>>& aValue, ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
nsCOMPtr<nsPIDOMWindow> window;
|
||||
if (MOZ_LIKELY(NS_IsMainThread())) {
|
||||
window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (!window) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<Promise> promise = new Promise(window);
|
||||
@ -413,8 +499,15 @@ Promise::AppendCallbacks(PromiseCallback* aResolveCallback,
|
||||
// callbacks with promise's result. If promise's state is rejected, queue a
|
||||
// task to process our reject callbacks with promise's result.
|
||||
if (mState != Pending && !mTaskPending) {
|
||||
nsRefPtr<PromiseTask> task = new PromiseTask(this);
|
||||
NS_DispatchToCurrentThread(task);
|
||||
if (MOZ_LIKELY(NS_IsMainThread())) {
|
||||
nsRefPtr<PromiseTask> task = new PromiseTask(this);
|
||||
NS_DispatchToCurrentThread(task);
|
||||
} else {
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
nsRefPtr<WorkerPromiseTask> task = new WorkerPromiseTask(worker, this);
|
||||
worker->Dispatch(task);
|
||||
}
|
||||
mTaskPending = true;
|
||||
}
|
||||
}
|
||||
@ -430,7 +523,7 @@ Promise::RunTask()
|
||||
mResolveCallbacks.Clear();
|
||||
mRejectCallbacks.Clear();
|
||||
|
||||
JSContext* cx = nsContentUtils::GetSafeJSContext();
|
||||
JSContext* cx = nsContentUtils::GetDefaultJSContextForThread();
|
||||
JSAutoRequest ar(cx);
|
||||
JS::Rooted<JS::Value> value(cx, mResult);
|
||||
|
||||
@ -453,16 +546,27 @@ Promise::MaybeReportRejected()
|
||||
|
||||
MOZ_ASSERT(mResult.isObject(), "How did we get a JSErrorReport?");
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> win =
|
||||
do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(&mResult.toObject()));
|
||||
// Remains null in case of worker.
|
||||
nsCOMPtr<nsPIDOMWindow> win;
|
||||
bool isChromeError = false;
|
||||
|
||||
if (MOZ_LIKELY(NS_IsMainThread())) {
|
||||
win =
|
||||
do_QueryInterface(nsJSUtils::GetStaticScriptGlobal(&mResult.toObject()));
|
||||
nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(&mResult.toObject());
|
||||
isChromeError = nsContentUtils::IsSystemPrincipal(principal);
|
||||
} else {
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
isChromeError = worker->IsChromeWorker();
|
||||
}
|
||||
|
||||
nsIPrincipal* principal = nsContentUtils::GetObjectPrincipal(&mResult.toObject());
|
||||
// Now post an event to do the real reporting async
|
||||
NS_DispatchToCurrentThread(
|
||||
NS_DispatchToMainThread(
|
||||
new AsyncErrorReporter(JS_GetObjectRuntime(&mResult.toObject()),
|
||||
report,
|
||||
nullptr,
|
||||
nsContentUtils::IsSystemPrincipal(principal),
|
||||
isChromeError,
|
||||
win));
|
||||
}
|
||||
|
||||
@ -539,9 +643,17 @@ Promise::RunResolveTask(JS::Handle<JS::Value> aValue,
|
||||
// If the synchronous flag is unset, queue a task to process our
|
||||
// accept callbacks with value.
|
||||
if (aAsynchronous == AsyncTask) {
|
||||
nsRefPtr<PromiseResolverTask> task =
|
||||
new PromiseResolverTask(this, aValue, aState);
|
||||
NS_DispatchToCurrentThread(task);
|
||||
if (MOZ_LIKELY(NS_IsMainThread())) {
|
||||
nsRefPtr<PromiseResolverTask> task =
|
||||
new PromiseResolverTask(this, aValue, aState);
|
||||
NS_DispatchToCurrentThread(task);
|
||||
} else {
|
||||
WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
|
||||
MOZ_ASSERT(worker);
|
||||
nsRefPtr<WorkerPromiseResolverTask> task =
|
||||
new WorkerPromiseResolverTask(worker, this, aValue, aState);
|
||||
worker->Dispatch(task);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -29,10 +29,13 @@ class Promise MOZ_FINAL : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
friend class NativePromiseCallback;
|
||||
friend class PromiseTask;
|
||||
friend class PromiseResolverMixin;
|
||||
friend class PromiseResolverTask;
|
||||
friend class ResolvePromiseCallback;
|
||||
friend class PromiseTask;
|
||||
friend class RejectPromiseCallback;
|
||||
friend class ResolvePromiseCallback;
|
||||
friend class WorkerPromiseResolverTask;
|
||||
friend class WorkerPromiseTask;
|
||||
friend class WrapperPromiseCallback;
|
||||
|
||||
public:
|
||||
@ -42,7 +45,6 @@ public:
|
||||
Promise(nsPIDOMWindow* aWindow);
|
||||
~Promise();
|
||||
|
||||
static bool PrefEnabled();
|
||||
static bool EnabledForScope(JSContext* aCx, JSObject* /* unused */);
|
||||
|
||||
void MaybeResolve(JSContext* aCx,
|
||||
|
@ -75,7 +75,13 @@ void
|
||||
ResolvePromiseCallback::Call(JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
// Run resolver's algorithm with value and the synchronous flag set.
|
||||
AutoJSContext cx;
|
||||
JSContext *cx = nsContentUtils::GetDefaultJSContextForThread();
|
||||
|
||||
Maybe<AutoCxPusher> pusher;
|
||||
if (NS_IsMainThread()) {
|
||||
pusher.construct(cx);
|
||||
}
|
||||
|
||||
Maybe<JSAutoCompartment> ac;
|
||||
EnterCompartment(ac, cx, aValue);
|
||||
|
||||
@ -110,7 +116,13 @@ void
|
||||
RejectPromiseCallback::Call(JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
// Run resolver's algorithm with value and the synchronous flag set.
|
||||
AutoJSContext cx;
|
||||
JSContext *cx = nsContentUtils::GetDefaultJSContextForThread();
|
||||
|
||||
Maybe<AutoCxPusher> pusher;
|
||||
if (NS_IsMainThread()) {
|
||||
pusher.construct(cx);
|
||||
}
|
||||
|
||||
Maybe<JSAutoCompartment> ac;
|
||||
EnterCompartment(ac, cx, aValue);
|
||||
|
||||
@ -146,7 +158,17 @@ WrapperPromiseCallback::~WrapperPromiseCallback()
|
||||
void
|
||||
WrapperPromiseCallback::Call(JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
AutoJSContext cx;
|
||||
// AutoCxPusher and co. interact with xpconnect, which crashes on
|
||||
// workers. On workers we'll get the right context from
|
||||
// GetDefaultJSContextForThread(), and since there is only one context, we
|
||||
// don't need to push or pop it from the stack.
|
||||
JSContext* cx = nsContentUtils::GetDefaultJSContextForThread();
|
||||
|
||||
Maybe<AutoCxPusher> pusher;
|
||||
if (NS_IsMainThread()) {
|
||||
pusher.construct(cx);
|
||||
}
|
||||
|
||||
Maybe<JSAutoCompartment> ac;
|
||||
EnterCompartment(ac, cx, aValue);
|
||||
|
||||
|
@ -37,7 +37,7 @@ public:
|
||||
};
|
||||
|
||||
// WrapperPromiseCallback execs a JS Callback with a value, and then the return
|
||||
// value is sent to the aNextPromise->resolveFunction() or to
|
||||
// value is sent to the aNextPromise->ResolveFunction() or to
|
||||
// aNextPromise->RejectFunction() if the JS Callback throws.
|
||||
class WrapperPromiseCallback MOZ_FINAL : public PromiseCallback
|
||||
{
|
||||
|
@ -63,6 +63,15 @@ function promiseReject() {
|
||||
});
|
||||
}
|
||||
|
||||
function promiseRejectNoHandler() {
|
||||
// This test only checks that the code that reports unhandled errors in the
|
||||
// Promises implementation does not crash or leak.
|
||||
var promise = new Promise(function(res, rej) {
|
||||
noSuchMethod();
|
||||
});
|
||||
runTest();
|
||||
}
|
||||
|
||||
function promiseRejectNoArg() {
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
reject();
|
||||
@ -474,7 +483,8 @@ var tests = [ promiseResolve, promiseReject,
|
||||
promiseThenNoArg,
|
||||
promiseThenUndefinedResolveFunction,
|
||||
promiseThenNullResolveFunction,
|
||||
promiseCatchNoArg
|
||||
promiseCatchNoArg,
|
||||
promiseRejectNoHandler,
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
|
@ -621,7 +621,6 @@ interface WebGLRenderingContext {
|
||||
|
||||
any getTexParameter(GLenum target, GLenum pname);
|
||||
|
||||
[Throws]
|
||||
any getUniform(WebGLProgram? program, WebGLUniformLocation? location);
|
||||
|
||||
[NewObject]
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "WorkerPrivate.h"
|
||||
#include "ChromeWorkerScope.h"
|
||||
#include "File.h"
|
||||
#include "RuntimeService.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "js/OldDebugAPI.h"
|
||||
@ -19,6 +20,7 @@
|
||||
#include "mozilla/dom/ImageDataBinding.h"
|
||||
#include "mozilla/dom/MessageEventBinding.h"
|
||||
#include "mozilla/dom/MessagePortBinding.h"
|
||||
#include "mozilla/dom/PromiseBinding.h"
|
||||
#include "mozilla/dom/TextDecoderBinding.h"
|
||||
#include "mozilla/dom/TextEncoderBinding.h"
|
||||
#include "mozilla/dom/XMLHttpRequestBinding.h"
|
||||
@ -61,6 +63,8 @@ WorkerPrivate::RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
|
||||
!ImageDataBinding::GetConstructorObject(aCx, aGlobal) ||
|
||||
!MessageEventBinding::GetConstructorObject(aCx, aGlobal) ||
|
||||
!MessagePortBinding::GetConstructorObject(aCx, aGlobal) ||
|
||||
(PromiseEnabled() &&
|
||||
!PromiseBinding::GetConstructorObject(aCx, aGlobal)) ||
|
||||
!TextDecoderBinding::GetConstructorObject(aCx, aGlobal) ||
|
||||
!TextEncoderBinding::GetConstructorObject(aCx, aGlobal) ||
|
||||
!XMLHttpRequestBinding_workers::GetConstructorObject(aCx, aGlobal) ||
|
||||
@ -77,4 +81,4 @@ WorkerPrivate::RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -176,25 +176,10 @@ static_assert(NS_ARRAY_LENGTH(gStringChars) == ID_COUNT,
|
||||
#if !(defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
|
||||
#define DUMP_CONTROLLED_BY_PREF 1
|
||||
#define PREF_DOM_WINDOW_DUMP_ENABLED "browser.dom.window.dump.enabled"
|
||||
|
||||
// Protected by RuntimeService::mMutex.
|
||||
// Initialized by DumpPrefChanged via RuntimeService::Init().
|
||||
bool gWorkersDumpEnabled;
|
||||
|
||||
static int
|
||||
DumpPrefChanged(const char* aPrefName, void* aClosure)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
bool enabled = Preferences::GetBool(PREF_DOM_WINDOW_DUMP_ENABLED, false);
|
||||
|
||||
Mutex* mutex = static_cast<Mutex*>(aClosure);
|
||||
MutexAutoLock lock(*mutex);
|
||||
gWorkersDumpEnabled = enabled;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define PREF_PROMISE_ENABLED "dom.promise.enabled"
|
||||
|
||||
class LiteralRebindingCString : public nsDependentCString
|
||||
{
|
||||
public:
|
||||
@ -1159,6 +1144,7 @@ END_WORKERS_NAMESPACE
|
||||
|
||||
// This is only touched on the main thread. Initialized in Init() below.
|
||||
JSSettings RuntimeService::sDefaultJSSettings;
|
||||
bool RuntimeService::sDefaultPreferences[WORKERPREF_COUNT] = { false };
|
||||
|
||||
RuntimeService::RuntimeService()
|
||||
: mMutex("RuntimeService::mMutex"), mObserved(false),
|
||||
@ -1569,6 +1555,11 @@ RuntimeService::Init()
|
||||
WORKER_DEFAULT_ALLOCATION_THRESHOLD);
|
||||
}
|
||||
|
||||
// If dump is not controlled by pref, it's set to true.
|
||||
#ifndef DUMP_CONTROLLED_BY_PREF
|
||||
sDefaultPreferences[WORKERPREF_DUMP] = true;
|
||||
#endif
|
||||
|
||||
mIdleThreadTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||
NS_ENSURE_STATE(mIdleThreadTimer);
|
||||
|
||||
@ -1624,10 +1615,14 @@ RuntimeService::Init()
|
||||
#endif
|
||||
#if DUMP_CONTROLLED_BY_PREF
|
||||
NS_FAILED(Preferences::RegisterCallbackAndCall(
|
||||
DumpPrefChanged,
|
||||
WorkerPrefChanged,
|
||||
PREF_DOM_WINDOW_DUMP_ENABLED,
|
||||
&mMutex)) ||
|
||||
reinterpret_cast<void *>(WORKERPREF_DUMP))) ||
|
||||
#endif
|
||||
NS_FAILED(Preferences::RegisterCallbackAndCall(
|
||||
WorkerPrefChanged,
|
||||
PREF_PROMISE_ENABLED,
|
||||
reinterpret_cast<void *>(WORKERPREF_PROMISE))) ||
|
||||
NS_FAILED(Preferences::RegisterCallback(LoadJSContextOptions,
|
||||
PREF_JS_OPTIONS_PREFIX,
|
||||
nullptr)) ||
|
||||
@ -1790,10 +1785,13 @@ RuntimeService::Cleanup()
|
||||
NS_FAILED(Preferences::UnregisterCallback(LoadJSContextOptions,
|
||||
PREF_WORKERS_OPTIONS_PREFIX,
|
||||
nullptr)) ||
|
||||
NS_FAILED(Preferences::UnregisterCallback(WorkerPrefChanged,
|
||||
PREF_PROMISE_ENABLED,
|
||||
reinterpret_cast<void *>(WORKERPREF_PROMISE))) ||
|
||||
#if DUMP_CONTROLLED_BY_PREF
|
||||
NS_FAILED(Preferences::UnregisterCallback(DumpPrefChanged,
|
||||
NS_FAILED(Preferences::UnregisterCallback(WorkerPrefChanged,
|
||||
PREF_DOM_WINDOW_DUMP_ENABLED,
|
||||
&mMutex)) ||
|
||||
reinterpret_cast<void *>(WORKERPREF_DUMP))) ||
|
||||
#endif
|
||||
#ifdef JS_GC_ZEAL
|
||||
NS_FAILED(Preferences::UnregisterCallback(
|
||||
@ -2171,6 +2169,12 @@ RuntimeService::UpdateAllWorkerJSContextOptions()
|
||||
sDefaultJSSettings.chrome.options);
|
||||
}
|
||||
|
||||
void
|
||||
RuntimeService::UpdateAllWorkerPreference(WorkerPreference aPref, bool aValue)
|
||||
{
|
||||
BROADCAST_ALL_WORKERS(UpdatePreference, aPref, aValue);
|
||||
}
|
||||
|
||||
void
|
||||
RuntimeService::UpdateAllWorkerMemoryParameter(JSGCParamKey aKey,
|
||||
uint32_t aValue)
|
||||
@ -2230,16 +2234,33 @@ RuntimeService::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
RuntimeService::WorkersDumpEnabled()
|
||||
/* static */ int
|
||||
RuntimeService::WorkerPrefChanged(const char* aPrefName, void* aClosure)
|
||||
{
|
||||
#if DUMP_CONTROLLED_BY_PREF
|
||||
MutexAutoLock lock(mMutex);
|
||||
// In optimized builds we check a pref that controls if we should
|
||||
// enable output from dump() or not, in debug builds it's always
|
||||
// enabled.
|
||||
return gWorkersDumpEnabled;
|
||||
#else
|
||||
return true;
|
||||
AssertIsOnMainThread();
|
||||
|
||||
uintptr_t tmp = reinterpret_cast<uintptr_t>(aClosure);
|
||||
MOZ_ASSERT(tmp < WORKERPREF_COUNT);
|
||||
WorkerPreference key = static_cast<WorkerPreference>(tmp);
|
||||
|
||||
if (key == WORKERPREF_PROMISE) {
|
||||
sDefaultPreferences[WORKERPREF_PROMISE] =
|
||||
Preferences::GetBool(PREF_PROMISE_ENABLED, false);
|
||||
#ifdef DUMP_CONTROLLED_BY_PREF
|
||||
} else if (key == WORKERPREF_DUMP) {
|
||||
key = WORKERPREF_DUMP;
|
||||
sDefaultPreferences[WORKERPREF_DUMP] =
|
||||
Preferences::GetBool(PREF_DOM_WINDOW_DUMP_ENABLED, false);
|
||||
#endif
|
||||
}
|
||||
|
||||
// This function should never be registered as a callback for a preference it
|
||||
// does not handle.
|
||||
MOZ_ASSERT(key != WORKERPREF_COUNT);
|
||||
|
||||
RuntimeService* rts = RuntimeService::GetService();
|
||||
if (rts) {
|
||||
rts->UpdateAllWorkerPreference(key, sDefaultPreferences[key]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -101,6 +101,7 @@ class RuntimeService MOZ_FINAL : public nsIObserver
|
||||
nsCString mSystemCharset;
|
||||
|
||||
static JSSettings sDefaultJSSettings;
|
||||
static bool sDefaultPreferences[WORKERPREF_COUNT];
|
||||
|
||||
public:
|
||||
struct NavigatorStrings
|
||||
@ -181,6 +182,13 @@ public:
|
||||
aSettings = sDefaultJSSettings;
|
||||
}
|
||||
|
||||
static void
|
||||
GetDefaultPreferences(bool aPreferences[WORKERPREF_COUNT])
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
memcpy(aPreferences, sDefaultPreferences, WORKERPREF_COUNT * sizeof(bool));
|
||||
}
|
||||
|
||||
static void
|
||||
SetDefaultJSContextOptions(const JS::ContextOptions& aContentOptions,
|
||||
const JS::ContextOptions& aChromeOptions)
|
||||
@ -193,6 +201,9 @@ public:
|
||||
void
|
||||
UpdateAllWorkerJSContextOptions();
|
||||
|
||||
void
|
||||
UpdateAllWorkerPreference(WorkerPreference aPref, bool aValue);
|
||||
|
||||
static void
|
||||
SetDefaultJSGCSettings(JSGCParamKey aKey, uint32_t aValue)
|
||||
{
|
||||
@ -241,9 +252,6 @@ public:
|
||||
void
|
||||
GarbageCollectAllWorkers(bool aShrinking);
|
||||
|
||||
bool
|
||||
WorkersDumpEnabled();
|
||||
|
||||
private:
|
||||
RuntimeService();
|
||||
~RuntimeService();
|
||||
@ -281,6 +289,9 @@ private:
|
||||
|
||||
static void
|
||||
ShutdownIdleThreads(nsITimer* aTimer, void* aClosure);
|
||||
|
||||
static int
|
||||
WorkerPrefChanged(const char* aPrefName, void* aClosure);
|
||||
};
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
@ -1465,6 +1465,29 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class UpdatePreferenceRunnable : public WorkerControlRunnable
|
||||
{
|
||||
WorkerPreference mPref;
|
||||
bool mValue;
|
||||
|
||||
public:
|
||||
UpdatePreferenceRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
WorkerPreference aPref,
|
||||
bool aValue)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount),
|
||||
mPref(aPref),
|
||||
mValue(aValue)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
aWorkerPrivate->UpdatePreferenceInternal(aCx, mPref, mValue);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class UpdateJSWorkerMemoryParameterRunnable : public WorkerControlRunnable
|
||||
{
|
||||
uint32_t mValue;
|
||||
@ -2778,6 +2801,21 @@ WorkerPrivateParent<Derived>::UpdateJSContextOptions(JSContext* aCx,
|
||||
}
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
WorkerPrivateParent<Derived>::UpdatePreference(JSContext* aCx, WorkerPreference aPref, bool aValue)
|
||||
{
|
||||
AssertIsOnParentThread();
|
||||
MOZ_ASSERT(aPref >= 0 && aPref < WORKERPREF_COUNT);
|
||||
|
||||
nsRefPtr<UpdatePreferenceRunnable> runnable =
|
||||
new UpdatePreferenceRunnable(ParentAsWorkerPrivate(), aPref, aValue);
|
||||
if (!runnable->Dispatch(aCx)) {
|
||||
NS_WARNING("Failed to update worker preferences!");
|
||||
JS_ClearPendingException(aCx);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
WorkerPrivateParent<Derived>::UpdateJSWorkerMemoryParameter(JSContext* aCx,
|
||||
@ -3284,6 +3322,15 @@ WorkerPrivate::WorkerPrivate(JSContext* aCx,
|
||||
{
|
||||
MOZ_ASSERT_IF(IsSharedWorker(), !aSharedWorkerName.IsVoid());
|
||||
MOZ_ASSERT_IF(!IsSharedWorker(), aSharedWorkerName.IsEmpty());
|
||||
|
||||
if (aParent) {
|
||||
aParent->AssertIsOnWorkerThread();
|
||||
aParent->GetAllPreferences(mPreferences);
|
||||
}
|
||||
else {
|
||||
AssertIsOnMainThread();
|
||||
RuntimeService::GetDefaultPreferences(mPreferences);
|
||||
}
|
||||
}
|
||||
|
||||
WorkerPrivate::~WorkerPrivate()
|
||||
@ -5083,6 +5130,19 @@ WorkerPrivate::UpdateJSContextOptionsInternal(JSContext* aCx,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPrivate::UpdatePreferenceInternal(JSContext* aCx, WorkerPreference aPref, bool aValue)
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
MOZ_ASSERT(aPref >= 0 && aPref < WORKERPREF_COUNT);
|
||||
|
||||
mPreferences[aPref] = aValue;
|
||||
|
||||
for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
|
||||
mChildWorkers[index]->UpdatePreference(aCx, aPref, aValue);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPrivate::UpdateJSWorkerMemoryParameterInternal(JSContext* aCx,
|
||||
JSGCParamKey aKey,
|
||||
|
@ -476,6 +476,9 @@ public:
|
||||
UpdateJSContextOptions(JSContext* aCx, const JS::ContextOptions& aChromeOptions,
|
||||
const JS::ContextOptions& aContentOptions);
|
||||
|
||||
void
|
||||
UpdatePreference(JSContext* aCx, WorkerPreference aPref, bool aValue);
|
||||
|
||||
void
|
||||
UpdateJSWorkerMemoryParameter(JSContext* aCx, JSGCParamKey key,
|
||||
uint32_t value);
|
||||
@ -815,6 +818,8 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
|
||||
nsCOMPtr<nsIThread> mThread;
|
||||
#endif
|
||||
|
||||
bool mPreferences[WORKERPREF_COUNT];
|
||||
|
||||
protected:
|
||||
~WorkerPrivate();
|
||||
|
||||
@ -977,6 +982,9 @@ public:
|
||||
UpdateJSContextOptionsInternal(JSContext* aCx, const JS::ContextOptions& aContentOptions,
|
||||
const JS::ContextOptions& aChromeOptions);
|
||||
|
||||
void
|
||||
UpdatePreferenceInternal(JSContext* aCx, WorkerPreference aPref, bool aValue);
|
||||
|
||||
void
|
||||
UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, uint32_t aValue);
|
||||
|
||||
@ -1069,6 +1077,20 @@ public:
|
||||
bool
|
||||
RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal);
|
||||
|
||||
bool
|
||||
DumpEnabled() const
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
return mPreferences[WORKERPREF_DUMP];
|
||||
}
|
||||
|
||||
bool
|
||||
PromiseEnabled() const
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
return mPreferences[WORKERPREF_PROMISE];
|
||||
}
|
||||
|
||||
private:
|
||||
WorkerPrivate(JSContext* aCx, WorkerPrivate* aParent,
|
||||
const nsAString& aScriptURL, bool aIsChromeWorker,
|
||||
@ -1146,6 +1168,13 @@ private:
|
||||
bool aToMessagePort,
|
||||
uint64_t aMessagePortSerial,
|
||||
ErrorResult& aRv);
|
||||
|
||||
void
|
||||
GetAllPreferences(bool aPreferences[WORKERPREF_COUNT]) const
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
memcpy(aPreferences, mPreferences, WORKERPREF_COUNT * sizeof(bool));
|
||||
}
|
||||
};
|
||||
|
||||
// This class is only used to trick the DOM bindings. We never create
|
||||
|
@ -234,10 +234,7 @@ WorkerGlobalScope::Dump(const Optional<nsAString>& aString) const
|
||||
return;
|
||||
}
|
||||
|
||||
RuntimeService* runtimeService = RuntimeService::GetService();
|
||||
MOZ_ASSERT(runtimeService);
|
||||
|
||||
if (!runtimeService->WorkersDumpEnabled()) {
|
||||
if (!mWorkerPrivate->DumpEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -162,6 +162,13 @@ struct JSSettings
|
||||
}
|
||||
};
|
||||
|
||||
enum WorkerPreference
|
||||
{
|
||||
WORKERPREF_DUMP = 0, // browser.dom.window.dump.enabled
|
||||
WORKERPREF_PROMISE, // dom.promise.enabled
|
||||
WORKERPREF_COUNT
|
||||
};
|
||||
|
||||
// All of these are implemented in RuntimeService.cpp
|
||||
bool
|
||||
ResolveWorkerClasses(JSContext* aCx, JS::Handle<JSObject*> aObj, JS::Handle<jsid> aId,
|
||||
|
@ -27,6 +27,7 @@ support-files =
|
||||
multi_sharedWorker_sharedWorker.js
|
||||
navigator_worker.js
|
||||
newError_worker.js
|
||||
promise_worker.js
|
||||
recursion_worker.js
|
||||
recursiveOnerror_worker.js
|
||||
relativeLoad_import.js
|
||||
@ -84,6 +85,7 @@ support-files =
|
||||
[test_multi_sharedWorker_lifetimes.html]
|
||||
[test_navigator.html]
|
||||
[test_newError.html]
|
||||
[test_promise.html]
|
||||
[test_recursion.html]
|
||||
[test_recursiveOnerror.html]
|
||||
[test_relativeLoad.html]
|
||||
|
395
dom/workers/test/promise_worker.js
Normal file
395
dom/workers/test/promise_worker.js
Normal file
@ -0,0 +1,395 @@
|
||||
function ok(a, msg) {
|
||||
dump("OK: " + !!a + " => " + a + " " + msg + "\n");
|
||||
postMessage({type: 'status', status: !!a, msg: a + ": " + msg });
|
||||
}
|
||||
|
||||
function is(a, b, msg) {
|
||||
dump("IS: " + (a===b) + " => " + a + " | " + b + " " + msg + "\n");
|
||||
postMessage({type: 'status', status: a === b, msg: a + " === " + b + ": " + msg });
|
||||
}
|
||||
|
||||
function isnot(a, b, msg) {
|
||||
dump("ISNOT: " + (a!==b) + " => " + a + " | " + b + " " + msg + "\n");
|
||||
postMessage({type: 'status', status: a !== b, msg: a + " !== " + b + ": " + msg });
|
||||
}
|
||||
|
||||
function promiseResolve() {
|
||||
ok(Promise, "Promise object should exist");
|
||||
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
ok(resolve, "Promise.resolve exists");
|
||||
ok(reject, "Promise.reject exists");
|
||||
|
||||
resolve(42);
|
||||
}).then(function(what) {
|
||||
ok(true, "Then - resolveCb has been called");
|
||||
is(what, 42, "ResolveCb received 42");
|
||||
runTest();
|
||||
}, function() {
|
||||
ok(false, "Then - rejectCb has been called");
|
||||
runTest();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function promiseReject() {
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
reject(42);
|
||||
}).then(function(what) {
|
||||
ok(false, "Then - resolveCb has been called");
|
||||
runTest();
|
||||
}, function(what) {
|
||||
ok(true, "Then - rejectCb has been called");
|
||||
is(what, 42, "RejectCb received 42");
|
||||
runTest();
|
||||
});
|
||||
}
|
||||
|
||||
function promiseException() {
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
throw 42;
|
||||
}).then(function(what) {
|
||||
ok(false, "Then - resolveCb has been called");
|
||||
runTest();
|
||||
}, function(what) {
|
||||
ok(true, "Then - rejectCb has been called");
|
||||
is(what, 42, "RejectCb received 42");
|
||||
runTest();
|
||||
});
|
||||
}
|
||||
|
||||
function promiseAsync() {
|
||||
var global = "foo";
|
||||
var f = new Promise(function(r1, r2) {
|
||||
is(global, "foo", "Global should be foo");
|
||||
r1(42);
|
||||
is(global, "foo", "Global should still be foo");
|
||||
setTimeout(function() {
|
||||
is(global, "bar", "Global should still be bar!");
|
||||
runTest();
|
||||
}, 0);
|
||||
}).then(function() {
|
||||
global = "bar";
|
||||
});
|
||||
is(global, "foo", "Global should still be foo (2)");
|
||||
}
|
||||
|
||||
function promiseDoubleThen() {
|
||||
var steps = 0;
|
||||
var promise = new Promise(function(r1, r2) {
|
||||
r1(42);
|
||||
});
|
||||
|
||||
promise.then(function(what) {
|
||||
ok(true, "Then.resolve has been called");
|
||||
is(what, 42, "Value == 42");
|
||||
steps++;
|
||||
}, function(what) {
|
||||
ok(false, "Then.reject has been called");
|
||||
});
|
||||
|
||||
promise.then(function(what) {
|
||||
ok(true, "Then.resolve has been called");
|
||||
is(steps, 1, "Then.resolve - step == 1");
|
||||
is(what, 42, "Value == 42");
|
||||
runTest();
|
||||
}, function(what) {
|
||||
ok(false, "Then.reject has been called");
|
||||
});
|
||||
}
|
||||
|
||||
function promiseThenException() {
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
resolve(42);
|
||||
});
|
||||
|
||||
promise.then(function(what) {
|
||||
ok(true, "Then.resolve has been called");
|
||||
throw "booh";
|
||||
}).catch(function(e) {
|
||||
ok(true, "Catch has been called!");
|
||||
runTest();
|
||||
});
|
||||
}
|
||||
|
||||
function promiseThenCatchThen() {
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
resolve(42);
|
||||
});
|
||||
|
||||
var promise2 = promise.then(function(what) {
|
||||
ok(true, "Then.resolve has been called");
|
||||
is(what, 42, "Value == 42");
|
||||
return what + 1;
|
||||
}, function(what) {
|
||||
ok(false, "Then.reject has been called");
|
||||
});
|
||||
|
||||
isnot(promise, promise2, "These 2 promise objs are different");
|
||||
|
||||
promise2.then(function(what) {
|
||||
ok(true, "Then.resolve has been called");
|
||||
is(what, 43, "Value == 43");
|
||||
return what + 1;
|
||||
}, function(what) {
|
||||
ok(false, "Then.reject has been called");
|
||||
}).catch(function() {
|
||||
ok(false, "Catch has been called");
|
||||
}).then(function(what) {
|
||||
ok(true, "Then.resolve has been called");
|
||||
is(what, 44, "Value == 44");
|
||||
runTest();
|
||||
}, function(what) {
|
||||
ok(false, "Then.reject has been called");
|
||||
});
|
||||
}
|
||||
|
||||
function promiseRejectThenCatchThen() {
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
reject(42);
|
||||
});
|
||||
|
||||
var promise2 = promise.then(function(what) {
|
||||
ok(false, "Then.resolve has been called");
|
||||
}, function(what) {
|
||||
ok(true, "Then.reject has been called");
|
||||
is(what, 42, "Value == 42");
|
||||
return what + 1;
|
||||
});
|
||||
|
||||
isnot(promise, promise2, "These 2 promise objs are different");
|
||||
|
||||
promise2.then(function(what) {
|
||||
ok(true, "Then.resolve has been called");
|
||||
is(what, 43, "Value == 43");
|
||||
return what+1;
|
||||
}).catch(function(what) {
|
||||
ok(false, "Catch has been called");
|
||||
}).then(function(what) {
|
||||
ok(true, "Then.resolve has been called");
|
||||
is(what, 44, "Value == 44");
|
||||
runTest();
|
||||
});
|
||||
}
|
||||
|
||||
function promiseRejectThenCatchThen2() {
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
reject(42);
|
||||
});
|
||||
|
||||
promise.then(function(what) {
|
||||
ok(true, "Then.resolve has been called");
|
||||
is(what, 42, "Value == 42");
|
||||
return what+1;
|
||||
}).catch(function(what) {
|
||||
is(what, 42, "Value == 42");
|
||||
ok(true, "Catch has been called");
|
||||
return what+1;
|
||||
}).then(function(what) {
|
||||
ok(true, "Then.resolve has been called");
|
||||
is(what, 43, "Value == 43");
|
||||
runTest();
|
||||
});
|
||||
}
|
||||
|
||||
function promiseRejectThenCatchExceptionThen() {
|
||||
var promise = new Promise(function(resolve, reject) {
|
||||
reject(42);
|
||||
});
|
||||
|
||||
promise.then(function(what) {
|
||||
ok(false, "Then.resolve has been called");
|
||||
}, function(what) {
|
||||
ok(true, "Then.reject has been called");
|
||||
is(what, 42, "Value == 42");
|
||||
throw(what + 1);
|
||||
}).catch(function(what) {
|
||||
ok(true, "Catch has been called");
|
||||
is(what, 43, "Value == 43");
|
||||
return what + 1;
|
||||
}).then(function(what) {
|
||||
ok(true, "Then.resolve has been called");
|
||||
is(what, 44, "Value == 44");
|
||||
runTest();
|
||||
});
|
||||
}
|
||||
|
||||
function promiseThenCatchOrderingResolve() {
|
||||
var global = 0;
|
||||
var f = new Promise(function(r1, r2) {
|
||||
r1(42);
|
||||
});
|
||||
|
||||
f.then(function() {
|
||||
f.then(function() {
|
||||
global++;
|
||||
});
|
||||
f.catch(function() {
|
||||
global++;
|
||||
});
|
||||
f.then(function() {
|
||||
global++;
|
||||
});
|
||||
setTimeout(function() {
|
||||
is(global, 2, "Many steps... should return 2");
|
||||
runTest();
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
|
||||
function promiseThenCatchOrderingReject() {
|
||||
var global = 0;
|
||||
var f = new Promise(function(r1, r2) {
|
||||
r2(42);
|
||||
})
|
||||
|
||||
f.then(function() {}, function() {
|
||||
f.then(function() {
|
||||
global++;
|
||||
});
|
||||
f.catch(function() {
|
||||
global++;
|
||||
});
|
||||
f.then(function() {}, function() {
|
||||
global++;
|
||||
});
|
||||
setTimeout(function() {
|
||||
is(global, 2, "Many steps... should return 2");
|
||||
runTest();
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
|
||||
function promiseNestedPromise() {
|
||||
new Promise(function(resolve, reject) {
|
||||
resolve(new Promise(function(resolve, reject) {
|
||||
ok(true, "Nested promise is executed");
|
||||
resolve(42);
|
||||
}));
|
||||
}).then(function(value) {
|
||||
is(value, 42, "Nested promise is executed and then == 42");
|
||||
runTest();
|
||||
});
|
||||
}
|
||||
|
||||
function promiseNestedNestedPromise() {
|
||||
new Promise(function(resolve, reject) {
|
||||
resolve(new Promise(function(resolve, reject) {
|
||||
ok(true, "Nested promise is executed");
|
||||
resolve(42);
|
||||
}).then(function(what) { return what+1; }));
|
||||
}).then(function(value) {
|
||||
is(value, 43, "Nested promise is executed and then == 43");
|
||||
runTest();
|
||||
});
|
||||
}
|
||||
|
||||
function promiseWrongNestedPromise() {
|
||||
new Promise(function(resolve, reject) {
|
||||
resolve(new Promise(function(r, r2) {
|
||||
ok(true, "Nested promise is executed");
|
||||
r(42);
|
||||
}));
|
||||
reject(42);
|
||||
}).then(function(value) {
|
||||
is(value, 42, "Nested promise is executed and then == 42");
|
||||
runTest();
|
||||
}, function(value) {
|
||||
ok(false, "This is wrong");
|
||||
});
|
||||
}
|
||||
|
||||
function promiseLoop() {
|
||||
new Promise(function(resolve, reject) {
|
||||
resolve(new Promise(function(r1, r2) {
|
||||
ok(true, "Nested promise is executed");
|
||||
r1(new Promise(function(r1, r2) {
|
||||
ok(true, "Nested nested promise is executed");
|
||||
r1(42);
|
||||
}));
|
||||
}));
|
||||
}).then(function(value) {
|
||||
is(value, 42, "Nested nested promise is executed and then == 42");
|
||||
runTest();
|
||||
}, function(value) {
|
||||
ok(false, "This is wrong");
|
||||
});
|
||||
}
|
||||
|
||||
function promiseStaticReject() {
|
||||
var promise = Promise.reject(42).then(function(what) {
|
||||
ok(false, "This should not be called");
|
||||
}, function(what) {
|
||||
is(what, 42, "Value == 42");
|
||||
runTest();
|
||||
});
|
||||
}
|
||||
|
||||
function promiseStaticResolve() {
|
||||
var promise = Promise.resolve(42).then(function(what) {
|
||||
is(what, 42, "Value == 42");
|
||||
runTest();
|
||||
}, function() {
|
||||
ok(false, "This should not be called");
|
||||
});
|
||||
}
|
||||
|
||||
function promiseResolveNestedPromise() {
|
||||
var promise = Promise.resolve(new Promise(function(r, r2) {
|
||||
ok(true, "Nested promise is executed");
|
||||
r(42);
|
||||
}, function() {
|
||||
ok(false, "This should not be called");
|
||||
})).then(function(what) {
|
||||
is(what, 42, "Value == 42");
|
||||
runTest();
|
||||
}, function() {
|
||||
ok(false, "This should not be called");
|
||||
});
|
||||
}
|
||||
|
||||
function promiseRejectNoHandler() {
|
||||
// This test only checks that the code that reports unhandled errors in the
|
||||
// Promises implementation does not crash or leak.
|
||||
var promise = new Promise(function(res, rej) {
|
||||
noSuchMethod();
|
||||
});
|
||||
runTest();
|
||||
}
|
||||
|
||||
var tests = [
|
||||
promiseResolve,
|
||||
promiseReject,
|
||||
promiseException,
|
||||
promiseAsync,
|
||||
promiseDoubleThen,
|
||||
promiseThenException,
|
||||
promiseThenCatchThen,
|
||||
promiseRejectThenCatchThen,
|
||||
promiseRejectThenCatchThen2,
|
||||
promiseRejectThenCatchExceptionThen,
|
||||
promiseThenCatchOrderingResolve,
|
||||
promiseThenCatchOrderingReject,
|
||||
promiseNestedPromise,
|
||||
promiseNestedNestedPromise,
|
||||
promiseWrongNestedPromise,
|
||||
promiseLoop,
|
||||
promiseStaticReject,
|
||||
promiseStaticResolve,
|
||||
promiseResolveNestedPromise,
|
||||
promiseRejectNoHandler,
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
postMessage({ type: 'finish' });
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
onmessage = function() {
|
||||
runTest();
|
||||
}
|
44
dom/workers/test/test_promise.html
Normal file
44
dom/workers/test/test_promise.html
Normal file
@ -0,0 +1,44 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for Promise object in workers</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
function runTest() {
|
||||
var worker = new Worker("promise_worker.js");
|
||||
|
||||
worker.onmessage = function(event) {
|
||||
|
||||
if (event.data.type == 'finish') {
|
||||
SimpleTest.finish();
|
||||
} else if (event.data.type == 'status') {
|
||||
ok(event.data.status, event.data.msg);
|
||||
}
|
||||
}
|
||||
|
||||
worker.onerror = function(event) {
|
||||
ok(false, "Worker had an error: " + event.data);
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
||||
worker.postMessage(true);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [["dom.promise.enabled", true]]}, runTest);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -4,15 +4,11 @@
|
||||
# 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/.
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'nsAuthFactory.cpp',
|
||||
'nsAuthGSSAPI.cpp',
|
||||
'nsAuthSASL.cpp',
|
||||
]
|
||||
|
||||
# contains constants whose names conflict with constants in other files
|
||||
SOURCES += [
|
||||
'nsHttpNegotiateAuth.cpp',
|
||||
'nsAuthFactory.cpp', # forces NSPR logging
|
||||
'nsAuthGSSAPI.cpp', # forces NSPR logging
|
||||
'nsAuthSASL.cpp',
|
||||
'nsHttpNegotiateAuth.cpp', # contains constants whose names conflict with constants in other files
|
||||
]
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
@ -21,8 +17,8 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
]
|
||||
DEFINES['USE_SSPI'] = True
|
||||
else:
|
||||
UNIFIED_SOURCES += [
|
||||
'nsAuthSambaNTLM.cpp',
|
||||
SOURCES += [
|
||||
'nsAuthSambaNTLM.cpp', # forces NSPR logging
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user