зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to m-c a=merge
This commit is contained in:
Коммит
3770ad1b24
|
@ -205,6 +205,8 @@
|
|||
<true/>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.productivity</string>
|
||||
<key>LSFileQuarantineEnabled</key>
|
||||
<true/>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>10.9.0</string>
|
||||
<key>NSSupportsAutomaticGraphicsSwitching</key>
|
||||
|
|
|
@ -379,9 +379,6 @@ pref("browser.search.hiddenOneOffs", "");
|
|||
|
||||
pref("browser.search.reset.enabled", true);
|
||||
|
||||
pref("browser.usedOnWindows10", false);
|
||||
pref("browser.usedOnWindows10.introURL", "https://www.mozilla.org/%LOCALE%/firefox/windows-10/welcome/?utm_source=firefox-browser&utm_medium=firefox-browser");
|
||||
|
||||
pref("browser.sessionhistory.max_entries", 50);
|
||||
|
||||
// Built-in default permissions.
|
||||
|
|
|
@ -6453,7 +6453,7 @@
|
|||
class="tab-throbber"
|
||||
role="presentation"
|
||||
layer="true" />
|
||||
<xul:image xbl:inherits="src=image,fadein,pinned,selected=visuallyselected,busy,crashed,sharing"
|
||||
<xul:image xbl:inherits="src=image,loadingprincipal=iconLoadingPrincipal,fadein,pinned,selected=visuallyselected,busy,crashed,sharing"
|
||||
anonid="tab-icon-image"
|
||||
class="tab-icon-image"
|
||||
validate="never"
|
||||
|
|
|
@ -64,31 +64,31 @@ const PAGECONTENT_TRANSLATED =
|
|||
"</iframe>" +
|
||||
"</div></body></html>";
|
||||
|
||||
function openSelectPopup(selectPopup, withMouse, selector = "select")
|
||||
function openSelectPopup(selectPopup, withMouse, selector = "select", win = window)
|
||||
{
|
||||
let popupShownPromise = BrowserTestUtils.waitForEvent(selectPopup, "popupshown");
|
||||
|
||||
if (withMouse) {
|
||||
return Promise.all([popupShownPromise,
|
||||
BrowserTestUtils.synthesizeMouseAtCenter(selector, { }, gBrowser.selectedBrowser)]);
|
||||
BrowserTestUtils.synthesizeMouseAtCenter(selector, { }, win.gBrowser.selectedBrowser)]);
|
||||
}
|
||||
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { altKey: true, code: "ArrowDown" });
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown", { altKey: true, code: "ArrowDown" }, win);
|
||||
return popupShownPromise;
|
||||
}
|
||||
|
||||
function hideSelectPopup(selectPopup, mode = "enter")
|
||||
function hideSelectPopup(selectPopup, mode = "enter", win = window)
|
||||
{
|
||||
let popupHiddenPromise = BrowserTestUtils.waitForEvent(selectPopup, "popuphidden");
|
||||
|
||||
if (mode == "escape") {
|
||||
EventUtils.synthesizeKey("KEY_Escape", { code: "Escape" });
|
||||
EventUtils.synthesizeKey("KEY_Escape", { code: "Escape" }, win);
|
||||
}
|
||||
else if (mode == "enter") {
|
||||
EventUtils.synthesizeKey("KEY_Enter", { code: "Enter" });
|
||||
EventUtils.synthesizeKey("KEY_Enter", { code: "Enter" }, win);
|
||||
}
|
||||
else if (mode == "click") {
|
||||
EventUtils.synthesizeMouseAtCenter(selectPopup.lastChild, { });
|
||||
EventUtils.synthesizeMouseAtCenter(selectPopup.lastChild, { }, win);
|
||||
}
|
||||
|
||||
return popupHiddenPromise;
|
||||
|
@ -402,13 +402,11 @@ add_task(function* test_event_order() {
|
|||
});
|
||||
});
|
||||
|
||||
// This test checks select elements with a large number of options to ensure that
|
||||
// the popup appears within the browser area.
|
||||
add_task(function* test_large_popup() {
|
||||
const pageUrl = "data:text/html," + escape(PAGECONTENT_SMALL);
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
|
||||
function* performLargePopupTests(win)
|
||||
{
|
||||
let browser = win.gBrowser.selectedBrowser;
|
||||
|
||||
yield ContentTask.spawn(tab.linkedBrowser, null, function*() {
|
||||
yield ContentTask.spawn(browser, null, function*() {
|
||||
let doc = content.document;
|
||||
let select = doc.getElementById("one");
|
||||
for (var i = 0; i < 180; i++) {
|
||||
|
@ -419,8 +417,8 @@ add_task(function* test_large_popup() {
|
|||
select.focus();
|
||||
});
|
||||
|
||||
let selectPopup = document.getElementById("ContentSelectDropdown").menupopup;
|
||||
let browserRect = tab.linkedBrowser.getBoundingClientRect();
|
||||
let selectPopup = win.document.getElementById("ContentSelectDropdown").menupopup;
|
||||
let browserRect = browser.getBoundingClientRect();
|
||||
|
||||
let positions = [
|
||||
"margin-top: 300px;",
|
||||
|
@ -430,15 +428,15 @@ add_task(function* test_large_popup() {
|
|||
|
||||
let position;
|
||||
while (true) {
|
||||
yield openSelectPopup(selectPopup, false);
|
||||
yield openSelectPopup(selectPopup, false, "select", win);
|
||||
|
||||
let rect = selectPopup.getBoundingClientRect();
|
||||
ok(rect.top >= browserRect.top, "Popup top position in within browser area");
|
||||
ok(rect.bottom <= browserRect.bottom, "Popup bottom position in within browser area");
|
||||
|
||||
// Don't check the scroll position for the last step as the popup will be cut off.
|
||||
if (positions.length == 1) {
|
||||
let cs = window.getComputedStyle(selectPopup);
|
||||
if (positions.length > 0) {
|
||||
let cs = win.getComputedStyle(selectPopup);
|
||||
let bpBottom = parseFloat(cs.paddingBottom) + parseFloat(cs.borderBottomWidth);
|
||||
|
||||
is(selectPopup.childNodes[60].getBoundingClientRect().bottom,
|
||||
|
@ -446,24 +444,49 @@ add_task(function* test_large_popup() {
|
|||
"Popup scroll at correct position " + bpBottom);
|
||||
}
|
||||
|
||||
yield hideSelectPopup(selectPopup);
|
||||
yield hideSelectPopup(selectPopup, "enter", win);
|
||||
|
||||
position = positions.shift();
|
||||
if (!position) {
|
||||
break;
|
||||
}
|
||||
|
||||
let contentPainted = BrowserTestUtils.contentPainted(tab.linkedBrowser);
|
||||
yield ContentTask.spawn(tab.linkedBrowser, position, function*(position) {
|
||||
let contentPainted = BrowserTestUtils.contentPainted(browser);
|
||||
yield ContentTask.spawn(browser, position, function*(position) {
|
||||
let select = content.document.getElementById("one");
|
||||
select.setAttribute("style", position);
|
||||
});
|
||||
yield contentPainted;
|
||||
}
|
||||
}
|
||||
|
||||
// This test checks select elements with a large number of options to ensure that
|
||||
// the popup appears within the browser area.
|
||||
add_task(function* test_large_popup() {
|
||||
const pageUrl = "data:text/html," + escape(PAGECONTENT_SMALL);
|
||||
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, pageUrl);
|
||||
|
||||
yield* performLargePopupTests(window);
|
||||
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
// This test checks the same as the previous test but in a new smaller window.
|
||||
add_task(function* test_large_popup_in_small_window() {
|
||||
let newwin = yield BrowserTestUtils.openNewBrowserWindow({ width: 400, height: 400 });
|
||||
|
||||
const pageUrl = "data:text/html," + escape(PAGECONTENT_SMALL);
|
||||
let browserLoadedPromise = BrowserTestUtils.browserLoaded(newwin.gBrowser.selectedBrowser);
|
||||
yield BrowserTestUtils.loadURI(newwin.gBrowser.selectedBrowser, pageUrl);
|
||||
yield browserLoadedPromise;
|
||||
|
||||
newwin.gBrowser.selectedBrowser.focus();
|
||||
|
||||
yield* performLargePopupTests(newwin);
|
||||
|
||||
yield BrowserTestUtils.closeWindow(newwin);
|
||||
});
|
||||
|
||||
// This test checks that a mousemove event is fired correctly at the menu and
|
||||
// not at the browser, ensuring that any mouse capture has been cleared.
|
||||
add_task(function* test_mousemove_correcttarget() {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
pref("startup.homepage_override_url", "");
|
||||
pref("startup.homepage_welcome_url", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/firstrun/");
|
||||
pref("startup.homepage_welcome_url.additional", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/firstrun/learnmore/");
|
||||
pref("startup.homepage_welcome_url.additional", "");
|
||||
// Interval: Time between checks for a new version (in seconds)
|
||||
pref("app.update.interval", 43200); // 12 hours
|
||||
// The time interval between the downloading of mar file chunks in the
|
||||
|
|
|
@ -22,7 +22,7 @@ function getIconFile() {
|
|||
NetUtil.asyncFetch({
|
||||
uri: "http://www.example.com/browser/browser/components/contextualidentity/test/browser/favicon-normal32.png",
|
||||
loadUsingSystemPrincipal: true,
|
||||
contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE
|
||||
contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE_FAVICON
|
||||
}, function(inputStream, status) {
|
||||
let size = inputStream.available();
|
||||
gFaviconData = NetUtil.readInputStreamToString(inputStream, size);
|
||||
|
|
|
@ -157,11 +157,6 @@ FirefoxProfileMigrator.prototype._getResourcesInternal = function(sourceProfileD
|
|||
// session with the "what's new" page:
|
||||
Services.prefs.setCharPref("browser.startup.homepage_override.mstone", mstone);
|
||||
Services.prefs.setCharPref("browser.startup.homepage_override.buildID", buildID);
|
||||
// Also set the Windows 10 pref to avoid the win10 intro page to show up
|
||||
// on startup.
|
||||
if (AppConstants.isPlatformAndVersionAtLeast("win", "10")) {
|
||||
Services.prefs.setBoolPref("browser.usedOnWindows10", true);
|
||||
}
|
||||
// It's too early in startup for the pref service to have a profile directory,
|
||||
// so we have to manually tell it where to save the prefs file.
|
||||
let newPrefsFile = currentProfileDir.clone();
|
||||
|
|
|
@ -525,22 +525,6 @@ nsBrowserContentHandler.prototype = {
|
|||
if (overridePage == "about:blank")
|
||||
overridePage = "";
|
||||
|
||||
// Temporary override page for users who are running Firefox on Windows 10 for their first time.
|
||||
let platformVersion = Services.sysinfo.getProperty("version");
|
||||
if (AppConstants.platform == "win" &&
|
||||
Services.vc.compare(platformVersion, "10") == 0 &&
|
||||
!Services.prefs.getBoolPref("browser.usedOnWindows10")) {
|
||||
Services.prefs.setBoolPref("browser.usedOnWindows10", true);
|
||||
let firstUseOnWindows10URL = Services.urlFormatter.formatURLPref("browser.usedOnWindows10.introURL");
|
||||
|
||||
if (firstUseOnWindows10URL && firstUseOnWindows10URL.length) {
|
||||
additionalPage = firstUseOnWindows10URL;
|
||||
if (override == OVERRIDE_NEW_PROFILE) {
|
||||
additionalPage += "&utm_content=firstrun";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!additionalPage) {
|
||||
additionalPage = LaterRun.getURL() || "";
|
||||
}
|
||||
|
|
|
@ -3,6 +3,12 @@ skip-if = buildapp == "mulet"
|
|||
tags = usercontextid firstpartyisolation originattributes
|
||||
support-files =
|
||||
dummy.html
|
||||
file_favicon.html
|
||||
file_favicon.png
|
||||
file_favicon.png^headers^
|
||||
file_favicon_cache.html
|
||||
file_favicon_cache.png
|
||||
file_favicon_thirdParty.html
|
||||
file_firstPartyBasic.html
|
||||
file_sharedworker.html
|
||||
file_sharedworker.js
|
||||
|
@ -24,6 +30,8 @@ support-files =
|
|||
worker_blobify.js
|
||||
worker_deblobify.js
|
||||
|
||||
[browser_favicon_firstParty.js]
|
||||
[browser_favicon_userContextId.js]
|
||||
[browser_firstPartyIsolation.js]
|
||||
[browser_localStorageIsolation.js]
|
||||
[browser_blobURLIsolation.js]
|
||||
|
|
|
@ -0,0 +1,334 @@
|
|||
/**
|
||||
* Bug 1277803 - A test case for testing favicon loading across different first party domains.
|
||||
*/
|
||||
|
||||
const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/PlacesUtils.jsm");
|
||||
|
||||
const FIRST_PARTY_ONE = "example.com";
|
||||
const FIRST_PARTY_TWO = "example.org";
|
||||
const THIRD_PARTY = "mochi.test:8888";
|
||||
|
||||
const TEST_SITE_ONE = "http://" + FIRST_PARTY_ONE;
|
||||
const TEST_SITE_TWO = "http://" + FIRST_PARTY_TWO;
|
||||
const THIRD_PARTY_SITE = "http://" + THIRD_PARTY;
|
||||
const TEST_DIRECTORY = "/browser/browser/components/originattributes/test/browser/";
|
||||
|
||||
const TEST_PAGE = TEST_DIRECTORY + "file_favicon.html";
|
||||
const TEST_THIRD_PARTY_PAGE = TEST_DIRECTORY + "file_favicon_thirdParty.html";
|
||||
const TEST_CACHE_PAGE = TEST_DIRECTORY + "file_favicon_cache.html";
|
||||
|
||||
const FAVICON_URI = TEST_DIRECTORY + "file_favicon.png";
|
||||
const TEST_FAVICON_CACHE_URI = TEST_DIRECTORY + "file_favicon_cache.png";
|
||||
|
||||
let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
||||
let makeURI = Cu.import("resource://gre/modules/BrowserUtils.jsm", {}).BrowserUtils.makeURI;
|
||||
|
||||
function clearAllImageCaches() {
|
||||
let tools = SpecialPowers.Cc["@mozilla.org/image/tools;1"]
|
||||
.getService(SpecialPowers.Ci.imgITools);
|
||||
let imageCache = tools.getImgCacheForDocument(window.document);
|
||||
imageCache.clearCache(true); // true=chrome
|
||||
imageCache.clearCache(false); // false=content
|
||||
}
|
||||
|
||||
function clearAllPlacesFavicons() {
|
||||
let faviconService = Cc["@mozilla.org/browser/favicon-service;1"]
|
||||
.getService(Ci.nsIFaviconService);
|
||||
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic === "places-favicons-expired") {
|
||||
resolve();
|
||||
Services.obs.removeObserver(observer, "places-favicons-expired", false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(observer, "places-favicons-expired", false);
|
||||
faviconService.expireAllFavicons();
|
||||
});
|
||||
}
|
||||
|
||||
function observeFavicon(aFirstPartyDomain, aExpectedCookie, aPageURI) {
|
||||
let faviconReqXUL = false;
|
||||
let faviconReqPlaces = false;
|
||||
let expectedPrincipal = Services.scriptSecurityManager
|
||||
.createCodebasePrincipal(aPageURI, { firstPartyDomain: aFirstPartyDomain });
|
||||
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
// Make sure that the topic is 'http-on-modify-request'.
|
||||
if (aTopic === "http-on-modify-request") {
|
||||
// We check the firstPartyDomain for the originAttributes of the loading
|
||||
// channel. All requests for the favicon should contain the correct
|
||||
// firstPartyDomain. There are two requests for a favicon loading, one
|
||||
// from the Places library and one from the XUL image. The difference
|
||||
// of them is the loading principal. The Places will use the content
|
||||
// principal and the XUL image will use the system principal.
|
||||
|
||||
let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
|
||||
let reqLoadInfo = httpChannel.loadInfo;
|
||||
let loadingPrincipal = reqLoadInfo.loadingPrincipal;
|
||||
let triggeringPrincipal = reqLoadInfo.triggeringPrincipal;
|
||||
|
||||
// Make sure this is a favicon request.
|
||||
if (!httpChannel.URI.spec.endsWith(FAVICON_URI)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the first party domain.
|
||||
is(reqLoadInfo.originAttributes.firstPartyDomain, aFirstPartyDomain,
|
||||
"The loadInfo has correct first party domain");
|
||||
|
||||
if (loadingPrincipal.equals(systemPrincipal)) {
|
||||
faviconReqXUL = true;
|
||||
ok(triggeringPrincipal.equals(expectedPrincipal),
|
||||
"The triggeringPrincipal of favicon loading from XUL should be the content principal.");
|
||||
} else {
|
||||
faviconReqPlaces = true;
|
||||
ok(loadingPrincipal.equals(expectedPrincipal),
|
||||
"The loadingPrincipal of favicon loading from Places should be the content prinicpal");
|
||||
}
|
||||
|
||||
let faviconCookie = httpChannel.getRequestHeader("cookie");
|
||||
|
||||
is(faviconCookie, aExpectedCookie, "The cookie of the favicon loading is correct.");
|
||||
} else {
|
||||
ok(false, "Received unexpected topic: ", aTopic);
|
||||
}
|
||||
|
||||
if (faviconReqXUL && faviconReqPlaces) {
|
||||
Services.obs.removeObserver(observer, "http-on-modify-request", false);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(observer, "http-on-modify-request", false);
|
||||
});
|
||||
}
|
||||
|
||||
function waitOnFaviconResponse(aFaviconURL) {
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic === "http-on-examine-response" ||
|
||||
aTopic === "http-on-examine-cached-response") {
|
||||
|
||||
let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
|
||||
let loadInfo = httpChannel.loadInfo;
|
||||
|
||||
if (httpChannel.URI.spec !== aFaviconURL) {
|
||||
return;
|
||||
}
|
||||
|
||||
let result = {
|
||||
topic: aTopic,
|
||||
firstPartyDomain: loadInfo.originAttributes.firstPartyDomain
|
||||
};
|
||||
|
||||
resolve(result);
|
||||
Services.obs.removeObserver(observer, "http-on-examine-response", false);
|
||||
Services.obs.removeObserver(observer, "http-on-examine-cached-response", false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(observer, "http-on-examine-response", false);
|
||||
Services.obs.addObserver(observer, "http-on-examine-cached-response", false);
|
||||
});
|
||||
}
|
||||
|
||||
function waitOnFaviconLoaded(aFaviconURL) {
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
onPageChanged(uri, attr, value, id) {
|
||||
|
||||
if (attr === Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON &&
|
||||
value === aFaviconURL) {
|
||||
resolve();
|
||||
PlacesUtils.history.removeObserver(observer, false);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
PlacesUtils.history.addObserver(observer, false);
|
||||
});
|
||||
}
|
||||
|
||||
function* openTab(aURL) {
|
||||
let tab = gBrowser.addTab(aURL);
|
||||
|
||||
// Select tab and make sure its browser is focused.
|
||||
gBrowser.selectedTab = tab;
|
||||
tab.ownerGlobal.focus();
|
||||
|
||||
let browser = gBrowser.getBrowserForTab(tab);
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
return {tab, browser};
|
||||
}
|
||||
|
||||
function* assignCookiesUnderFirstParty(aURL, aFirstParty, aCookieValue) {
|
||||
// Open a tab under the given aFirstParty, and this tab will have an
|
||||
// iframe which loads the aURL.
|
||||
let tabInfo = yield openTabInFirstParty(aURL, aFirstParty);
|
||||
|
||||
// Add cookies into the iframe.
|
||||
yield ContentTask.spawn(tabInfo.browser, aCookieValue, function* (value) {
|
||||
content.document.cookie = value;
|
||||
});
|
||||
|
||||
yield BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
}
|
||||
|
||||
function* generateCookies(aThirdParty) {
|
||||
// we generate two different cookies for two first party domains.
|
||||
let cookies = [];
|
||||
cookies.push(Math.random().toString());
|
||||
cookies.push(Math.random().toString());
|
||||
|
||||
let firstSiteURL;
|
||||
let secondSiteURL;
|
||||
|
||||
if (aThirdParty) {
|
||||
// Add cookies into the third party site with different first party domain.
|
||||
firstSiteURL = THIRD_PARTY_SITE;
|
||||
secondSiteURL = THIRD_PARTY_SITE;
|
||||
} else {
|
||||
// Add cookies into sites.
|
||||
firstSiteURL = TEST_SITE_ONE;
|
||||
secondSiteURL = TEST_SITE_TWO;
|
||||
}
|
||||
|
||||
yield assignCookiesUnderFirstParty(firstSiteURL, TEST_SITE_ONE, cookies[0]);
|
||||
yield assignCookiesUnderFirstParty(secondSiteURL, TEST_SITE_TWO, cookies[1]);
|
||||
|
||||
return cookies;
|
||||
}
|
||||
|
||||
function* doTest(aTestPage, aExpectedCookies, aFaviconURL) {
|
||||
let firstPageURI = makeURI(TEST_SITE_ONE + aTestPage);
|
||||
let secondPageURI = makeURI(TEST_SITE_TWO + aTestPage);
|
||||
|
||||
// Start to observer the event of that favicon has been fully loaded.
|
||||
let promiseFaviconLoaded = waitOnFaviconLoaded(aFaviconURL);
|
||||
|
||||
// Open the tab for the first site.
|
||||
let tabInfo = yield openTab(TEST_SITE_ONE + aTestPage);
|
||||
|
||||
// Waiting until favicon requests are all made.
|
||||
yield observeFavicon(FIRST_PARTY_ONE, aExpectedCookies[0], firstPageURI);
|
||||
|
||||
// Waiting until favicon loaded.
|
||||
yield promiseFaviconLoaded;
|
||||
|
||||
// Close the tab.
|
||||
yield BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
|
||||
// Open the tab for the second site.
|
||||
tabInfo = yield openTab(TEST_SITE_TWO + aTestPage);
|
||||
|
||||
// Waiting until favicon requests are all made.
|
||||
yield observeFavicon(FIRST_PARTY_TWO, aExpectedCookies[1], secondPageURI);
|
||||
|
||||
yield BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
}
|
||||
|
||||
add_task(function* setup() {
|
||||
// Make sure first party isolation is enabled.
|
||||
yield SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.firstparty.isolate", true]
|
||||
]});
|
||||
});
|
||||
|
||||
// A clean up function to prevent affecting other tests.
|
||||
registerCleanupFunction(() => {
|
||||
// Clear all cookies.
|
||||
let cookieMgr = Cc["@mozilla.org/cookiemanager;1"]
|
||||
.getService(Ci.nsICookieManager);
|
||||
cookieMgr.removeAll();
|
||||
|
||||
// Clear all image caches and network caches.
|
||||
clearAllImageCaches();
|
||||
|
||||
let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Ci.nsICacheStorageService);
|
||||
networkCache.clear();
|
||||
});
|
||||
|
||||
add_task(function* test_favicon_firstParty() {
|
||||
for (let testThirdParty of [false, true]) {
|
||||
// Clear all image caches and network caches before running the test.
|
||||
clearAllImageCaches();
|
||||
|
||||
let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Ci.nsICacheStorageService);
|
||||
networkCache.clear();
|
||||
|
||||
// Clear Places favicon caches.
|
||||
yield clearAllPlacesFavicons();
|
||||
|
||||
let cookies = yield generateCookies(testThirdParty);
|
||||
|
||||
if (testThirdParty) {
|
||||
yield doTest(TEST_THIRD_PARTY_PAGE, cookies, THIRD_PARTY_SITE + FAVICON_URI);
|
||||
} else {
|
||||
yield doTest(TEST_PAGE, cookies, TEST_SITE_ONE + FAVICON_URI);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_favicon_cache_firstParty() {
|
||||
// Clear all image caches and network caches before running the test.
|
||||
clearAllImageCaches();
|
||||
|
||||
let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Ci.nsICacheStorageService);
|
||||
networkCache.clear();
|
||||
|
||||
// Open the tab for the first site.
|
||||
let tabInfoA = yield openTab(TEST_SITE_ONE + TEST_CACHE_PAGE);
|
||||
|
||||
// Start to observer the event of that favicon has been fully loaded and cached.
|
||||
let promiseForFaviconLoaded = waitOnFaviconLoaded(THIRD_PARTY_SITE + TEST_FAVICON_CACHE_URI);
|
||||
|
||||
// Wait for the favicon response of the first tab.
|
||||
let response = yield waitOnFaviconResponse(THIRD_PARTY_SITE + TEST_FAVICON_CACHE_URI);
|
||||
|
||||
// Make sure the favicon is loaded through the network and its first party domain is correct.
|
||||
is(response.topic, "http-on-examine-response", "The favicon image should be loaded through network.");
|
||||
is(response.firstPartyDomain, FIRST_PARTY_ONE, "We should only observe the network response for the first first party.");
|
||||
|
||||
// Waiting until the favicon has been loaded and cached.
|
||||
yield promiseForFaviconLoaded;
|
||||
|
||||
// Open the tab again for checking the image cache is working correctly.
|
||||
let tabInfoB = yield openTab(TEST_SITE_ONE + TEST_CACHE_PAGE);
|
||||
|
||||
// Start to observe the favicon response, the second tab actually will not
|
||||
// make any network request since the favicon will be loaded by the cache for
|
||||
// both Places and XUL image. So here, we are going to observe the favicon
|
||||
// response for the third tab which opens with the second first party.
|
||||
let promiseForFaviconResponse = waitOnFaviconResponse(THIRD_PARTY_SITE + TEST_FAVICON_CACHE_URI);
|
||||
|
||||
// Open the tab for the second site.
|
||||
let tabInfoC = yield openTab(TEST_SITE_TWO + TEST_CACHE_PAGE);
|
||||
|
||||
// Wait for the favicon response. In this case, we suppose to catch the
|
||||
// response for the third tab but not the second tab since it will not
|
||||
// go through the network.
|
||||
response = yield promiseForFaviconResponse;
|
||||
|
||||
// Check that the favicon response has came from the network and it has the
|
||||
// correct first party domain.
|
||||
is(response.topic, "http-on-examine-response", "The favicon image should be loaded through network again.");
|
||||
is(response.firstPartyDomain, FIRST_PARTY_TWO, "We should only observe the network response for the second first party.");
|
||||
|
||||
yield BrowserTestUtils.removeTab(tabInfoA.tab);
|
||||
yield BrowserTestUtils.removeTab(tabInfoB.tab);
|
||||
yield BrowserTestUtils.removeTab(tabInfoC.tab);
|
||||
});
|
|
@ -0,0 +1,250 @@
|
|||
/**
|
||||
* Bug 1277803 - A test caes for testing favicon loading across different userContextId.
|
||||
*/
|
||||
|
||||
const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
|
||||
const TEST_SITE = "http://mochi.test:8888";
|
||||
|
||||
const TEST_PAGE = TEST_SITE + "/browser/browser/components/originattributes/" +
|
||||
"test/browser/file_favicon.html";
|
||||
const FAVICON_URI = TEST_SITE + "/browser/browser/components/originattributes/" +
|
||||
"test/browser/file_favicon.png";
|
||||
const TEST_THIRD_PARTY_PAGE = "http://example.com/browser/browser/components/" +
|
||||
"originattributes/test/browser/file_favicon_thirdParty.html";
|
||||
|
||||
const USER_CONTEXT_ID_PERSONAL = 1;
|
||||
const USER_CONTEXT_ID_WORK = 2;
|
||||
|
||||
let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
||||
let makeURI = Cu.import("resource://gre/modules/BrowserUtils.jsm", {}).BrowserUtils.makeURI;
|
||||
|
||||
function clearAllImageCaches() {
|
||||
var tools = SpecialPowers.Cc["@mozilla.org/image/tools;1"]
|
||||
.getService(SpecialPowers.Ci.imgITools);
|
||||
var imageCache = tools.getImgCacheForDocument(window.document);
|
||||
imageCache.clearCache(true); // true=chrome
|
||||
imageCache.clearCache(false); // false=content
|
||||
}
|
||||
|
||||
function clearAllPlacesFavicons() {
|
||||
let faviconService = Cc["@mozilla.org/browser/favicon-service;1"]
|
||||
.getService(Ci.nsIFaviconService);
|
||||
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic === "places-favicons-expired") {
|
||||
resolve();
|
||||
Services.obs.removeObserver(observer, "places-favicons-expired", false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(observer, "places-favicons-expired", false);
|
||||
faviconService.expireAllFavicons();
|
||||
});
|
||||
}
|
||||
|
||||
function FaviconObserver(aUserContextId, aExpectedCookie, aPageURI) {
|
||||
this.reset(aUserContextId, aExpectedCookie, aPageURI);
|
||||
}
|
||||
|
||||
FaviconObserver.prototype = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
// Make sure that the topic is 'http-on-modify-request'.
|
||||
if (aTopic === "http-on-modify-request") {
|
||||
// We check the userContextId for the originAttributes of the loading
|
||||
// channel. All requests for the favicon should contain the correct
|
||||
// userContextId. There are two requests for a favicon loading, one
|
||||
// from the Places library and one from the XUL image. The difference
|
||||
// of them is the loading principal. The Places will use the content
|
||||
// principal and the XUL image will use the system principal.
|
||||
|
||||
let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
|
||||
let reqLoadInfo = httpChannel.loadInfo;
|
||||
let loadingPrincipal;
|
||||
let triggeringPrincipal;
|
||||
|
||||
// Make sure this is a favicon request.
|
||||
if (httpChannel.URI.spec !== FAVICON_URI) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (reqLoadInfo) {
|
||||
loadingPrincipal = reqLoadInfo.loadingPrincipal;
|
||||
triggeringPrincipal = reqLoadInfo.triggeringPrincipal;
|
||||
}
|
||||
|
||||
// Check the userContextId.
|
||||
is(reqLoadInfo.originAttributes.userContextId, this._curUserContextId,
|
||||
"The loadInfo has correct userContextId");
|
||||
|
||||
if (loadingPrincipal.equals(systemPrincipal)) {
|
||||
this._faviconReqXUL = true;
|
||||
ok(triggeringPrincipal.equals(this._expectedPrincipal),
|
||||
"The triggeringPrincipal of favicon loading from XUL should be the content principal.");
|
||||
} else {
|
||||
this._faviconReqPlaces = true;
|
||||
ok(loadingPrincipal.equals(this._expectedPrincipal),
|
||||
"The loadingPrincipal of favicon loading from Places should be the content prinicpal");
|
||||
}
|
||||
|
||||
let faviconCookie = httpChannel.getRequestHeader("cookie");
|
||||
|
||||
is(faviconCookie, this._expectedCookie, "The cookie of the favicon loading is correct.");
|
||||
} else {
|
||||
ok(false, "Received unexpected topic: ", aTopic);
|
||||
}
|
||||
|
||||
if (this._faviconReqXUL && this._faviconReqPlaces) {
|
||||
this._faviconLoaded.resolve();
|
||||
}
|
||||
},
|
||||
|
||||
reset(aUserContextId, aExpectedCookie, aPageURI) {
|
||||
this._curUserContextId = aUserContextId;
|
||||
this._expectedCookie = aExpectedCookie;
|
||||
this._expectedPrincipal = Services.scriptSecurityManager
|
||||
.createCodebasePrincipal(aPageURI, { userContextId: aUserContextId });
|
||||
this._faviconReqXUL = false;
|
||||
this._faviconReqPlaces = false;
|
||||
this._faviconLoaded = new Promise.defer();
|
||||
},
|
||||
|
||||
get promise() {
|
||||
return this._faviconLoaded.promise;
|
||||
}
|
||||
};
|
||||
|
||||
function waitOnFaviconLoaded(aFaviconURL) {
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
onPageChanged(uri, attr, value, id) {
|
||||
|
||||
if (attr === Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON &&
|
||||
value === aFaviconURL) {
|
||||
resolve();
|
||||
PlacesUtils.history.removeObserver(observer, false);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
PlacesUtils.history.addObserver(observer, false);
|
||||
});
|
||||
}
|
||||
|
||||
function* generateCookies() {
|
||||
// we generate two different cookies for two userContextIds.
|
||||
let cookies = [];
|
||||
cookies.push(Math.random().toString());
|
||||
cookies.push(Math.random().toString());
|
||||
|
||||
// Then, we add cookies into the site for 'personal' and 'work'.
|
||||
let tabInfoA = yield openTabInUserContext(TEST_SITE, USER_CONTEXT_ID_PERSONAL);
|
||||
let tabInfoB = yield openTabInUserContext(TEST_SITE, USER_CONTEXT_ID_WORK);
|
||||
|
||||
yield ContentTask.spawn(tabInfoA.browser, cookies[0], function* (value) {
|
||||
content.document.cookie = value;
|
||||
});
|
||||
|
||||
yield ContentTask.spawn(tabInfoB.browser, cookies[1], function* (value) {
|
||||
content.document.cookie = value;
|
||||
});
|
||||
|
||||
yield BrowserTestUtils.removeTab(tabInfoA.tab);
|
||||
yield BrowserTestUtils.removeTab(tabInfoB.tab);
|
||||
|
||||
return cookies;
|
||||
}
|
||||
|
||||
function* doTest(aTestPage) {
|
||||
let cookies = yield generateCookies();
|
||||
let pageURI = makeURI(aTestPage);
|
||||
|
||||
// Create the observer object for observing request channels of the personal
|
||||
// container.
|
||||
let observer = new FaviconObserver(USER_CONTEXT_ID_PERSONAL, cookies[0], pageURI);
|
||||
|
||||
Services.obs.addObserver(observer, "http-on-modify-request", false);
|
||||
|
||||
// Open the tab with the personal container.
|
||||
let tabInfo = yield openTabInUserContext(aTestPage, USER_CONTEXT_ID_PERSONAL);
|
||||
|
||||
// Waiting for favicon requests are all made.
|
||||
yield observer.promise;
|
||||
// Waiting for favicon loaded.
|
||||
yield waitOnFaviconLoaded(FAVICON_URI);
|
||||
|
||||
// Close the tab.
|
||||
yield BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
|
||||
// Reset the observer for observing requests for the work container.
|
||||
observer.reset(USER_CONTEXT_ID_WORK, cookies[1], pageURI);
|
||||
tabInfo = yield openTabInUserContext(aTestPage, USER_CONTEXT_ID_WORK);
|
||||
|
||||
// Waiting for favicon requests are all made.
|
||||
yield observer.promise;
|
||||
|
||||
Services.obs.removeObserver(observer, "http-on-modify-request", false);
|
||||
|
||||
yield BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
}
|
||||
|
||||
add_task(function* setup() {
|
||||
// Make sure userContext is enabled.
|
||||
yield SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.userContext.enabled", true]
|
||||
]});
|
||||
});
|
||||
|
||||
// A clean up function to prevent affecting other tests.
|
||||
registerCleanupFunction(() => {
|
||||
// Clear all cookies.
|
||||
let cookieMgr = Cc["@mozilla.org/cookiemanager;1"]
|
||||
.getService(Ci.nsICookieManager);
|
||||
cookieMgr.removeAll();
|
||||
|
||||
// Clear all image caches and network caches.
|
||||
clearAllImageCaches();
|
||||
|
||||
let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Ci.nsICacheStorageService);
|
||||
networkCache.clear();
|
||||
|
||||
// Clear Places favicon caches.
|
||||
clearAllPlacesFavicons();
|
||||
});
|
||||
|
||||
add_task(function* test_favicon_userContextId() {
|
||||
// Clear all image caches before running the test.
|
||||
clearAllImageCaches();
|
||||
|
||||
// Clear all network caches.
|
||||
let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Ci.nsICacheStorageService);
|
||||
networkCache.clear();
|
||||
|
||||
// Clear Places favicon caches.
|
||||
yield clearAllPlacesFavicons();
|
||||
|
||||
yield doTest(TEST_PAGE);
|
||||
});
|
||||
|
||||
add_task(function* test_thirdPartyFavicon_userContextId() {
|
||||
// Clear all image caches before running the test.
|
||||
clearAllImageCaches();
|
||||
|
||||
// Clear all network caches.
|
||||
let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Ci.nsICacheStorageService);
|
||||
networkCache.clear();
|
||||
|
||||
// Clear Places favicon caches.
|
||||
yield clearAllPlacesFavicons();
|
||||
|
||||
yield doTest(TEST_THIRD_PARTY_PAGE);
|
||||
});
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<title>Favicon Test for originAttributes</title>
|
||||
<link rel="icon" type="image/png" href="file_favicon.png" />
|
||||
</head>
|
||||
<body>
|
||||
Favicon!!
|
||||
</body>
|
||||
</html>
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 344 B |
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-cache
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<title>Favicon Test for originAttributes</title>
|
||||
<link rel="icon" type="image/png" href="http://mochi.test:8888/browser/browser/components/originattributes/test/browser/file_favicon_cache.png" />
|
||||
</head>
|
||||
<body>
|
||||
Third Party Favicon!!
|
||||
</body>
|
||||
</html>
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 344 B |
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<title>Favicon Test for originAttributes</title>
|
||||
<link rel="icon" type="image/png" href="http://mochi.test:8888/browser/browser/components/originattributes/test/browser/file_favicon.png" />
|
||||
</head>
|
||||
<body>
|
||||
Third Party Favicon!!
|
||||
</body>
|
||||
</html>
|
|
@ -230,9 +230,9 @@
|
|||
<label id="fxaDisplayName" hidden="true"/>
|
||||
<label id="fxaEmailAddress1"/>
|
||||
<hbox class="fxaAccountBoxButtons">
|
||||
<button id="fxaUnlinkButton" label="&disconnect.label;" accesskey="&disconnect.label.accesskey;"/>
|
||||
<button id="fxaUnlinkButton" label="&disconnect.label;" accesskey="&disconnect.accesskey;"/>
|
||||
<html:a id="verifiedManage" target="_blank"
|
||||
accesskey="&verifiedManage.label.accesskey;"
|
||||
accesskey="&verifiedManage.accesskey;"
|
||||
onkeypress="gSyncPane.openManageFirefoxAccount(event);"><!--
|
||||
-->&verifiedManage.label;</html:a>
|
||||
</hbox>
|
||||
|
@ -254,8 +254,8 @@
|
|||
</description>
|
||||
</hbox>
|
||||
<hbox class="fxaAccountBoxButtons">
|
||||
<button id="verifyFxaAccount" accesskey="&verify.label.accesskey;">&verify.label;</button>
|
||||
<button id="unverifiedUnlinkFxaAccount" accesskey="&forget.label.accesskey;">&forget.label;</button>
|
||||
<button id="verifyFxaAccount" accesskey="&verify.accesskey;">&verify.label;</button>
|
||||
<button id="unverifiedUnlinkFxaAccount" accesskey="&forget.accesskey;">&forget.label;</button>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
@ -275,8 +275,8 @@
|
|||
</description>
|
||||
</hbox>
|
||||
<hbox class="fxaAccountBoxButtons">
|
||||
<button id="rejectReSignIn" accessky="&signIn.label.accesskey;">&signIn.label;</button>
|
||||
<button id="rejectUnlinkFxaAccount" accesskey="&rejectUnlinkFxaAccount.forget.label.accesskey;">&forget.label;</button>
|
||||
<button id="rejectReSignIn" accessky="&signIn.accesskey;">&signIn.label;</button>
|
||||
<button id="rejectUnlinkFxaAccount" accesskey="&forget.accesskey;">&forget.label;</button>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
@ -326,14 +326,14 @@
|
|||
<hbox>
|
||||
<button id="fxaChangeDeviceName"
|
||||
label="&changeSyncDeviceName.label;"
|
||||
accesskey="&changeSyncDeviceName.label.accesskey;"/>
|
||||
accesskey="&changeSyncDeviceName.accesskey;"/>
|
||||
<button id="fxaCancelChangeDeviceName"
|
||||
label="&cancelChangeSyncDeviceName.label;"
|
||||
accesskey="&cancelChangeSyncDeviceName.label.accesskey;"
|
||||
accesskey="&cancelChangeSyncDeviceName.accesskey;"
|
||||
hidden="true"/>
|
||||
<button id="fxaSaveChangeDeviceName"
|
||||
label="&saveChangeSyncDeviceName.label;"
|
||||
accesskey="&saveChangeSyncDeviceName.label.accesskey;"
|
||||
accesskey="&saveChangeSyncDeviceName.accesskey;"
|
||||
hidden="true"/>
|
||||
</hbox>
|
||||
</hbox>
|
||||
|
|
|
@ -15,6 +15,9 @@ support-files =
|
|||
popup.html
|
||||
title.sjs
|
||||
empty_file.html
|
||||
file_favicon.html
|
||||
file_favicon.png
|
||||
file_favicon.png^headers^
|
||||
|
||||
[browser_privatebrowsing_DownloadLastDirWithCPS.js]
|
||||
[browser_privatebrowsing_about.js]
|
||||
|
@ -29,6 +32,7 @@ tags = trackingprotection
|
|||
[browser_privatebrowsing_downloadLastDir.js]
|
||||
[browser_privatebrowsing_downloadLastDir_c.js]
|
||||
[browser_privatebrowsing_downloadLastDir_toggle.js]
|
||||
[browser_privatebrowsing_favicon.js]
|
||||
[browser_privatebrowsing_geoprompt.js]
|
||||
[browser_privatebrowsing_lastpbcontextexited.js]
|
||||
[browser_privatebrowsing_localStorage.js]
|
||||
|
|
|
@ -0,0 +1,290 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This test make sure that the favicon of the private browsing is isolated.
|
||||
|
||||
const { classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
const TEST_SITE = "http://mochi.test:8888";
|
||||
const TEST_DIRECTORY = "/browser/browser/components/privatebrowsing/test/browser/";
|
||||
|
||||
const TEST_PAGE = TEST_SITE + TEST_DIRECTORY + "file_favicon.html";
|
||||
const FAVICON_URI = TEST_SITE + TEST_DIRECTORY + "file_favicon.png";
|
||||
|
||||
let systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
||||
let makeURI = Cu.import("resource://gre/modules/BrowserUtils.jsm", {}).BrowserUtils.makeURI;
|
||||
|
||||
function clearAllImageCaches() {
|
||||
let tools = SpecialPowers.Cc["@mozilla.org/image/tools;1"]
|
||||
.getService(SpecialPowers.Ci.imgITools);
|
||||
let imageCache = tools.getImgCacheForDocument(window.document);
|
||||
imageCache.clearCache(true); // true=chrome
|
||||
imageCache.clearCache(false); // false=content
|
||||
}
|
||||
|
||||
function clearAllPlacesFavicons() {
|
||||
let faviconService = Cc["@mozilla.org/browser/favicon-service;1"]
|
||||
.getService(Ci.nsIFaviconService);
|
||||
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic === "places-favicons-expired") {
|
||||
resolve();
|
||||
Services.obs.removeObserver(observer, "places-favicons-expired", false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(observer, "places-favicons-expired", false);
|
||||
faviconService.expireAllFavicons();
|
||||
});
|
||||
}
|
||||
|
||||
function observeFavicon(aIsPrivate, aExpectedCookie, aPageURI) {
|
||||
let faviconReqXUL = false;
|
||||
let faviconReqPlaces = false;
|
||||
let attr = {};
|
||||
|
||||
if (aIsPrivate) {
|
||||
attr.privateBrowsingId = 1;
|
||||
}
|
||||
|
||||
let expectedPrincipal = Services.scriptSecurityManager
|
||||
.createCodebasePrincipal(aPageURI, attr);
|
||||
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
// Make sure that the topic is 'http-on-modify-request'.
|
||||
if (aTopic === "http-on-modify-request") {
|
||||
// We check the privateBrowsingId for the originAttributes of the loading
|
||||
// channel. All requests for the favicon should contain the correct
|
||||
// privateBrowsingId. There are two requests for a favicon loading, one
|
||||
// from the Places library and one from the XUL image. The difference
|
||||
// of them is the loading principal. The Places will use the content
|
||||
// principal and the XUL image will use the system principal.
|
||||
|
||||
let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
|
||||
let reqLoadInfo = httpChannel.loadInfo;
|
||||
let loadingPrincipal = reqLoadInfo.loadingPrincipal;
|
||||
let triggeringPrincipal = reqLoadInfo.triggeringPrincipal;
|
||||
|
||||
// Make sure this is a favicon request.
|
||||
if (httpChannel.URI.spec !== FAVICON_URI) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the privateBrowsingId.
|
||||
if (aIsPrivate) {
|
||||
is(reqLoadInfo.originAttributes.privateBrowsingId, 1, "The loadInfo has correct privateBrowsingId");
|
||||
} else {
|
||||
is(reqLoadInfo.originAttributes.privateBrowsingId, 0, "The loadInfo has correct privateBrowsingId");
|
||||
}
|
||||
|
||||
if (loadingPrincipal.equals(systemPrincipal)) {
|
||||
faviconReqXUL = true;
|
||||
ok(triggeringPrincipal.equals(expectedPrincipal),
|
||||
"The triggeringPrincipal of favicon loading from XUL should be the content principal.");
|
||||
} else {
|
||||
faviconReqPlaces = true;
|
||||
ok(loadingPrincipal.equals(expectedPrincipal),
|
||||
"The loadingPrincipal of favicon loading from Places should be the content prinicpal");
|
||||
}
|
||||
|
||||
let faviconCookie = httpChannel.getRequestHeader("cookie");
|
||||
|
||||
is(faviconCookie, aExpectedCookie, "The cookie of the favicon loading is correct.");
|
||||
} else {
|
||||
ok(false, "Received unexpected topic: ", aTopic);
|
||||
}
|
||||
|
||||
if (faviconReqXUL && faviconReqPlaces) {
|
||||
resolve();
|
||||
Services.obs.removeObserver(observer, "http-on-modify-request", false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(observer, "http-on-modify-request", false);
|
||||
});
|
||||
}
|
||||
|
||||
function waitOnFaviconResponse(aFaviconURL) {
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic === "http-on-examine-response" ||
|
||||
aTopic === "http-on-examine-cached-response") {
|
||||
|
||||
let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
|
||||
let loadInfo = httpChannel.loadInfo;
|
||||
|
||||
if (httpChannel.URI.spec !== aFaviconURL) {
|
||||
return;
|
||||
}
|
||||
|
||||
let result = {
|
||||
topic: aTopic,
|
||||
privateBrowsingId: loadInfo.originAttributes.privateBrowsingId
|
||||
};
|
||||
|
||||
resolve(result);
|
||||
Services.obs.removeObserver(observer, "http-on-examine-response", false);
|
||||
Services.obs.removeObserver(observer, "http-on-examine-cached-response", false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(observer, "http-on-examine-response", false);
|
||||
Services.obs.addObserver(observer, "http-on-examine-cached-response", false);
|
||||
});
|
||||
}
|
||||
|
||||
function waitOnFaviconLoaded(aFaviconURL) {
|
||||
return new Promise(resolve => {
|
||||
let observer = {
|
||||
onPageChanged(uri, attr, value, id) {
|
||||
|
||||
if (attr === Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON &&
|
||||
value === aFaviconURL) {
|
||||
resolve();
|
||||
PlacesUtils.history.removeObserver(observer, false);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
PlacesUtils.history.addObserver(observer, false);
|
||||
});
|
||||
}
|
||||
|
||||
function* assignCookies(aBrowser, aURL, aCookieValue){
|
||||
let tabInfo = yield openTab(aBrowser, aURL);
|
||||
|
||||
yield ContentTask.spawn(tabInfo.browser, aCookieValue, function* (value) {
|
||||
content.document.cookie = value;
|
||||
});
|
||||
|
||||
yield BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
}
|
||||
|
||||
function* openTab(aBrowser, aURL) {
|
||||
let tab = aBrowser.addTab(aURL);
|
||||
|
||||
// Select tab and make sure its browser is focused.
|
||||
aBrowser.selectedTab = tab;
|
||||
tab.ownerGlobal.focus();
|
||||
|
||||
let browser = aBrowser.getBrowserForTab(tab);
|
||||
yield BrowserTestUtils.browserLoaded(browser);
|
||||
return {tab, browser};
|
||||
}
|
||||
|
||||
// A clean up function to prevent affecting other tests.
|
||||
registerCleanupFunction(() => {
|
||||
// Clear all cookies.
|
||||
let cookieMgr = Cc["@mozilla.org/cookiemanager;1"]
|
||||
.getService(Ci.nsICookieManager);
|
||||
cookieMgr.removeAll();
|
||||
|
||||
// Clear all image caches and network caches.
|
||||
clearAllImageCaches();
|
||||
|
||||
let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Ci.nsICacheStorageService);
|
||||
networkCache.clear();
|
||||
});
|
||||
|
||||
add_task(function* test_favicon_privateBrowsing() {
|
||||
// Clear all image caches before running the test.
|
||||
clearAllImageCaches();
|
||||
|
||||
// Clear all favicons in Places.
|
||||
yield clearAllPlacesFavicons();
|
||||
|
||||
// Create a private browsing window.
|
||||
let privateWindow = yield BrowserTestUtils.openNewBrowserWindow({ private: true });
|
||||
let pageURI = makeURI(TEST_PAGE);
|
||||
|
||||
// Generate two random cookies for non-private window and private window
|
||||
// respectively.
|
||||
let cookies = [];
|
||||
cookies.push(Math.random().toString());
|
||||
cookies.push(Math.random().toString());
|
||||
|
||||
// Open a tab in private window and add a cookie into it.
|
||||
yield assignCookies(privateWindow.gBrowser, TEST_SITE, cookies[0]);
|
||||
|
||||
// Open a tab in non-private window and add a cookie into it.
|
||||
yield assignCookies(gBrowser, TEST_SITE, cookies[1]);
|
||||
|
||||
// Add the observer earlier in case we don't capture events in time.
|
||||
let promiseObserveFavicon = observeFavicon(true, cookies[0], pageURI);
|
||||
|
||||
// Open a tab for the private window.
|
||||
let tabInfo = yield openTab(privateWindow.gBrowser, TEST_PAGE);
|
||||
|
||||
// Waiting until favicon requests are all made.
|
||||
yield promiseObserveFavicon;
|
||||
|
||||
// Close the tab.
|
||||
yield BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
|
||||
// Add the observer earlier in case we don't capture events in time.
|
||||
promiseObserveFavicon = observeFavicon(false, cookies[1], pageURI);
|
||||
|
||||
// Open a tab for the non-private window.
|
||||
tabInfo = yield openTab(gBrowser, TEST_PAGE);
|
||||
|
||||
// Waiting until favicon requests are all made.
|
||||
yield promiseObserveFavicon;
|
||||
|
||||
// Close the tab.
|
||||
yield BrowserTestUtils.removeTab(tabInfo.tab);
|
||||
yield BrowserTestUtils.closeWindow(privateWindow);
|
||||
});
|
||||
|
||||
add_task(function* test_favicon_cache_privateBrowsing() {
|
||||
// Clear all image cahces and network cache before running the test.
|
||||
clearAllImageCaches();
|
||||
|
||||
let networkCache = Cc["@mozilla.org/netwerk/cache-storage-service;1"]
|
||||
.getService(Ci.nsICacheStorageService);
|
||||
networkCache.clear();
|
||||
|
||||
// Clear all favicons in Places.
|
||||
yield clearAllPlacesFavicons();
|
||||
|
||||
// Create a private browsing window.
|
||||
let privateWindow = yield BrowserTestUtils.openNewBrowserWindow({ private: true });
|
||||
|
||||
// Add an observer for making sure the favicon has been loaded and cached.
|
||||
let promiseFaviconLoaded = waitOnFaviconLoaded(FAVICON_URI);
|
||||
|
||||
// Open a tab for the non-private window.
|
||||
let tabInfoNonPrivate = yield openTab(gBrowser, TEST_PAGE);
|
||||
|
||||
let response = yield waitOnFaviconResponse(FAVICON_URI);
|
||||
|
||||
yield promiseFaviconLoaded;
|
||||
|
||||
// Check that the favicon response has come from the network and it has the
|
||||
// correct privateBrowsingId.
|
||||
is(response.topic, "http-on-examine-response", "The favicon image should be loaded through network.");
|
||||
is(response.privateBrowsingId, 0, "We should observe the network response for the non-private tab.");
|
||||
|
||||
// Open a tab for the private window.
|
||||
let tabInfoPrivate = yield openTab(privateWindow.gBrowser, TEST_PAGE);
|
||||
|
||||
// Wait for the favicon response of the private tab.
|
||||
response = yield waitOnFaviconResponse(FAVICON_URI);
|
||||
|
||||
// Make sure the favicon is loaded through the network and its privateBrowsingId is correct.
|
||||
is(response.topic, "http-on-examine-response", "The favicon image should be loaded through the network again.");
|
||||
is(response.privateBrowsingId, 1, "We should observe the network response for the private tab.");
|
||||
|
||||
yield BrowserTestUtils.removeTab(tabInfoPrivate.tab);
|
||||
yield BrowserTestUtils.removeTab(tabInfoNonPrivate.tab);
|
||||
yield BrowserTestUtils.closeWindow(privateWindow);
|
||||
});
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<title>Favicon Test for originAttributes</title>
|
||||
<link rel="icon" type="image/png" href="file_favicon.png" />
|
||||
</head>
|
||||
<body>
|
||||
Favicon!!
|
||||
</body>
|
||||
</html>
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 344 B |
|
@ -0,0 +1 @@
|
|||
Cache-Control: no-cache
|
|
@ -40,11 +40,11 @@
|
|||
<!ENTITY syncDeviceName.label "Device Name:">
|
||||
<!ENTITY fxaSyncDeviceName.label "Device Name">
|
||||
<!ENTITY changeSyncDeviceName.label "Change Device Name…">
|
||||
<!ENTITY changeSyncDeviceName.label.accesskey "h">
|
||||
<!ENTITY changeSyncDeviceName.accesskey "h">
|
||||
<!ENTITY cancelChangeSyncDeviceName.label "Cancel">
|
||||
<!ENTITY cancelChangeSyncDeviceName.label.accesskey "n">
|
||||
<!ENTITY cancelChangeSyncDeviceName.accesskey "n">
|
||||
<!ENTITY saveChangeSyncDeviceName.label "Save">
|
||||
<!ENTITY saveChangeSyncDeviceName.label.accesskey "v">
|
||||
<!ENTITY saveChangeSyncDeviceName.accesskey "v">
|
||||
<!ENTITY unlinkDevice.label "Unlink This Device">
|
||||
|
||||
<!-- Footer stuff -->
|
||||
|
@ -73,17 +73,16 @@ both, to better adapt this sentence to their language.
|
|||
|
||||
<!ENTITY notSignedIn.label "You are not signed in.">
|
||||
<!ENTITY signIn.label "Sign in">
|
||||
<!ENTITY signIn.label.accesskey "g">
|
||||
<!ENTITY signIn.accesskey "g">
|
||||
<!ENTITY profilePicture.tooltip "Change profile picture">
|
||||
<!ENTITY verifiedManage.label "Manage Account">
|
||||
<!ENTITY verifiedManage.label.accesskey "o">
|
||||
<!ENTITY verifiedManage.accesskey "o">
|
||||
<!ENTITY disconnect.label "Disconnect…">
|
||||
<!ENTITY disconnect.label.accesskey "D">
|
||||
<!ENTITY disconnect.accesskey "D">
|
||||
<!ENTITY verify.label "Verify Email">
|
||||
<!ENTITY verify.label.accesskey "V">
|
||||
<!ENTITY verify.accesskey "V">
|
||||
<!ENTITY forget.label "Forget this Email">
|
||||
<!ENTITY forget.label.accesskey "F">
|
||||
<!ENTITY rejectUnlinkFxaAccount.forget.label.accesskey "e">
|
||||
<!ENTITY forget.accesskey "F">
|
||||
|
||||
<!ENTITY welcome.description "Access your tabs, bookmarks, passwords and more wherever you use &brandShortName;.">
|
||||
<!ENTITY welcome.signIn.label "Sign In">
|
||||
|
|
|
@ -108,7 +108,7 @@ function loadRecordingFromFile(file) {
|
|||
// If the recording has no label, set it to be the
|
||||
// filename without its extension.
|
||||
if (!recordingData.label) {
|
||||
recordingData.label = file.leafName.replace(/\..+$/, "");
|
||||
recordingData.label = file.leafName.replace(/\.[^.]+$/, "");
|
||||
}
|
||||
|
||||
resolve(recordingData);
|
||||
|
|
|
@ -1078,8 +1078,7 @@ EventSource::DispatchAllMessageEvents()
|
|||
// create an event that uses the MessageEvent interface,
|
||||
// which does not bubble, is not cancelable, and has no default action
|
||||
|
||||
RefPtr<MessageEvent> event =
|
||||
NS_NewDOMMessageEvent(this, nullptr, nullptr);
|
||||
RefPtr<MessageEvent> event = new MessageEvent(this, nullptr, nullptr);
|
||||
|
||||
event->InitMessageEvent(nullptr, message->mEventName, false, false, jsData,
|
||||
mOrigin, message->mLastEventID, nullptr, nullptr);
|
||||
|
|
|
@ -2005,7 +2005,7 @@ WebSocket::CreateAndDispatchMessageEvent(const nsACString& aData,
|
|||
// create an event that uses the MessageEvent interface,
|
||||
// which does not bubble, is not cancelable, and has no default action
|
||||
|
||||
RefPtr<MessageEvent> event = NS_NewDOMMessageEvent(this, nullptr, nullptr);
|
||||
RefPtr<MessageEvent> event = new MessageEvent(this, nullptr, nullptr);
|
||||
|
||||
event->InitMessageEvent(nullptr, NS_LITERAL_STRING("message"), false, false,
|
||||
jsData, mImpl->mUTF16Origin, EmptyString(), nullptr,
|
||||
|
|
|
@ -131,6 +131,7 @@ NS_CP_ContentTypeName(uint32_t contentType)
|
|||
CASE_RETURN( TYPE_INTERNAL_SCRIPT_PRELOAD );
|
||||
CASE_RETURN( TYPE_INTERNAL_IMAGE );
|
||||
CASE_RETURN( TYPE_INTERNAL_IMAGE_PRELOAD );
|
||||
CASE_RETURN( TYPE_INTERNAL_IMAGE_FAVICON );
|
||||
CASE_RETURN( TYPE_INTERNAL_STYLESHEET );
|
||||
CASE_RETURN( TYPE_INTERNAL_STYLESHEET_PRELOAD );
|
||||
default:
|
||||
|
|
|
@ -8418,6 +8418,7 @@ nsContentUtils::InternalContentPolicyTypeToExternal(nsContentPolicyType aType)
|
|||
|
||||
case nsIContentPolicy::TYPE_INTERNAL_IMAGE:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON:
|
||||
return nsIContentPolicy::TYPE_IMAGE;
|
||||
|
||||
case nsIContentPolicy::TYPE_INTERNAL_STYLESHEET:
|
||||
|
|
|
@ -402,7 +402,7 @@ nsDOMDataChannel::DoOnMessageAvailable(const nsACString& aData,
|
|||
jsData.setString(jsString);
|
||||
}
|
||||
|
||||
RefPtr<MessageEvent> event = NS_NewDOMMessageEvent(this, nullptr, nullptr);
|
||||
RefPtr<MessageEvent> event = new MessageEvent(this, nullptr, nullptr);
|
||||
|
||||
event->InitMessageEvent(nullptr, NS_LITERAL_STRING("message"), false, false,
|
||||
jsData, mOrigin, EmptyString(), nullptr, nullptr);
|
||||
|
|
|
@ -11413,9 +11413,18 @@ nsDocument::RequestFullScreen(UniquePtr<FullscreenRequest>&& aRequest)
|
|||
return;
|
||||
}
|
||||
|
||||
// Per spec only HTML, <svg>, and <math> should be allowed, but
|
||||
// we also need to allow XUL elements right now.
|
||||
Element* elem = aRequest->GetElement();
|
||||
if (!elem->IsHTMLElement() && !elem->IsXULElement() &&
|
||||
!elem->IsSVGElement(nsGkAtoms::svg) &&
|
||||
!elem->IsMathMLElement(nsGkAtoms::math)) {
|
||||
DispatchFullscreenError("FullscreenDeniedNotHTMLSVGOrMathML");
|
||||
return;
|
||||
}
|
||||
|
||||
// We don't need to check element ready before this point, because
|
||||
// if we called ApplyFullscreen, it would check that for us.
|
||||
Element* elem = aRequest->GetElement();
|
||||
if (!FullscreenElementReadyCheck(elem, aRequest->mIsCallerChrome)) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -557,6 +557,7 @@ GK_ATOM(listing, "listing")
|
|||
GK_ATOM(listitem, "listitem")
|
||||
GK_ATOM(listrows, "listrows")
|
||||
GK_ATOM(load, "load")
|
||||
GK_ATOM(loadingprincipal, "loadingprincipal")
|
||||
GK_ATOM(localedir, "localedir")
|
||||
GK_ATOM(localName, "local-name")
|
||||
GK_ATOM(longdesc, "longdesc")
|
||||
|
|
|
@ -321,6 +321,14 @@ interface nsIContentPolicyBase : nsISupports
|
|||
*/
|
||||
const nsContentPolicyType TYPE_INTERNAL_STYLESHEET_PRELOAD = 40;
|
||||
|
||||
/**
|
||||
* Indicates an internal constant for favicon.
|
||||
*
|
||||
* This will be mapped to TYPE_IMAGE before being passed
|
||||
* to content policy implementations.
|
||||
*/
|
||||
const nsContentPolicyType TYPE_INTERNAL_IMAGE_FAVICON = 41;
|
||||
|
||||
/* When adding new content types, please update nsContentBlocker,
|
||||
* NS_CP_ContentTypeName, nsCSPContext, all nsIContentPolicy
|
||||
* implementations, the static_assert in dom/cache/DBSchema.cpp,
|
||||
|
|
|
@ -292,7 +292,8 @@ static_assert(nsIContentPolicy::TYPE_INVALID == 0 &&
|
|||
nsIContentPolicy::TYPE_INTERNAL_IMAGE == 37 &&
|
||||
nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD == 38 &&
|
||||
nsIContentPolicy::TYPE_INTERNAL_STYLESHEET == 39 &&
|
||||
nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD == 40,
|
||||
nsIContentPolicy::TYPE_INTERNAL_STYLESHEET_PRELOAD == 40 &&
|
||||
nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON == 41,
|
||||
"nsContentPolicyType values are as expected");
|
||||
|
||||
namespace {
|
||||
|
|
|
@ -995,7 +995,8 @@ EventDispatcher::CreateEvent(EventTarget* aOwner,
|
|||
}
|
||||
if (aEventType.LowerCaseEqualsLiteral("messageevent")) {
|
||||
LOG_EVENT_CREATION(MESSAGEEVENT);
|
||||
return NS_NewDOMMessageEvent(aOwner, aPresContext, nullptr);
|
||||
RefPtr<Event> event = new MessageEvent(aOwner, aPresContext, nullptr);
|
||||
return event.forget();
|
||||
}
|
||||
if (aEventType.LowerCaseEqualsLiteral("notifypaintevent")) {
|
||||
LOG_EVENT_CREATION(NOTIFYPAINTEVENT);
|
||||
|
|
|
@ -205,15 +205,3 @@ MessageEvent::SetSource(mozilla::dom::MessagePort* aPort)
|
|||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
already_AddRefed<MessageEvent>
|
||||
NS_NewDOMMessageEvent(EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
WidgetEvent* aEvent)
|
||||
{
|
||||
RefPtr<MessageEvent> it = new MessageEvent(aOwner, aPresContext, aEvent);
|
||||
return it.forget();
|
||||
}
|
||||
|
|
|
@ -97,9 +97,4 @@ private:
|
|||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
already_AddRefed<mozilla::dom::MessageEvent>
|
||||
NS_NewDOMMessageEvent(mozilla::dom::EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
mozilla::WidgetEvent* aEvent);
|
||||
|
||||
#endif // mozilla_dom_MessageEvent_h_
|
||||
|
|
|
@ -181,6 +181,7 @@ InternalRequest::MapContentPolicyTypeToRequestContext(nsContentPolicyType aConte
|
|||
break;
|
||||
case nsIContentPolicy::TYPE_INTERNAL_IMAGE:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD:
|
||||
case nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON:
|
||||
context = RequestContext::Image;
|
||||
break;
|
||||
case nsIContentPolicy::TYPE_INTERNAL_STYLESHEET:
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace dom {
|
|||
* frame | TYPE_INTERNAL_FRAME
|
||||
* hyperlink |
|
||||
* iframe | TYPE_INTERNAL_IFRAME
|
||||
* image | TYPE_INTERNAL_IMAGE, TYPE_INTERNAL_IMAGE_PRELOAD
|
||||
* image | TYPE_INTERNAL_IMAGE, TYPE_INTERNAL_IMAGE_PRELOAD, TYPE_INTERNAL_IMAGE_FAVICON
|
||||
* imageset | TYPE_IMAGESET
|
||||
* import | Not supported by Gecko
|
||||
* internal | TYPE_DOCUMENT, TYPE_XBL, TYPE_OTHER
|
||||
|
|
|
@ -211,7 +211,9 @@ const Decimal HTMLInputElement::kStepScaleFactorDate = Decimal(86400000);
|
|||
const Decimal HTMLInputElement::kStepScaleFactorNumberRange = Decimal(1);
|
||||
const Decimal HTMLInputElement::kStepScaleFactorTime = Decimal(1000);
|
||||
const Decimal HTMLInputElement::kStepScaleFactorMonth = Decimal(1);
|
||||
const Decimal HTMLInputElement::kStepScaleFactorWeek = Decimal(7 * 86400000);
|
||||
const Decimal HTMLInputElement::kDefaultStepBase = Decimal(0);
|
||||
const Decimal HTMLInputElement::kDefaultStepBaseWeek = Decimal(-259200000);
|
||||
const Decimal HTMLInputElement::kDefaultStep = Decimal(1);
|
||||
const Decimal HTMLInputElement::kDefaultStepTime = Decimal(60);
|
||||
const Decimal HTMLInputElement::kStepAny = Decimal(0);
|
||||
|
@ -2381,6 +2383,7 @@ HTMLInputElement::GetStepBase() const
|
|||
mType == NS_FORM_INPUT_DATE ||
|
||||
mType == NS_FORM_INPUT_TIME ||
|
||||
mType == NS_FORM_INPUT_MONTH ||
|
||||
mType == NS_FORM_INPUT_WEEK ||
|
||||
mType == NS_FORM_INPUT_RANGE,
|
||||
"Check that kDefaultStepBase is correct for this new type");
|
||||
|
||||
|
@ -2401,6 +2404,10 @@ HTMLInputElement::GetStepBase() const
|
|||
return stepBase;
|
||||
}
|
||||
|
||||
if (mType == NS_FORM_INPUT_WEEK) {
|
||||
return kDefaultStepBaseWeek;
|
||||
}
|
||||
|
||||
return kDefaultStepBase;
|
||||
}
|
||||
|
||||
|
@ -7353,7 +7360,8 @@ HTMLInputElement::GetStep() const
|
|||
}
|
||||
|
||||
// For input type=date, we round the step value to have a rounded day.
|
||||
if (mType == NS_FORM_INPUT_DATE || mType == NS_FORM_INPUT_MONTH) {
|
||||
if (mType == NS_FORM_INPUT_DATE || mType == NS_FORM_INPUT_MONTH ||
|
||||
mType == NS_FORM_INPUT_WEEK) {
|
||||
step = std::max(step.round(), Decimal(1));
|
||||
}
|
||||
|
||||
|
@ -8489,6 +8497,8 @@ HTMLInputElement::GetStepScaleFactor() const
|
|||
return kStepScaleFactorTime;
|
||||
case NS_FORM_INPUT_MONTH:
|
||||
return kStepScaleFactorMonth;
|
||||
case NS_FORM_INPUT_WEEK:
|
||||
return kStepScaleFactorWeek;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Unrecognized input type");
|
||||
return Decimal::nan();
|
||||
|
@ -8503,6 +8513,7 @@ HTMLInputElement::GetDefaultStep() const
|
|||
switch (mType) {
|
||||
case NS_FORM_INPUT_DATE:
|
||||
case NS_FORM_INPUT_MONTH:
|
||||
case NS_FORM_INPUT_WEEK:
|
||||
case NS_FORM_INPUT_NUMBER:
|
||||
case NS_FORM_INPUT_RANGE:
|
||||
return kDefaultStep;
|
||||
|
|
|
@ -1053,11 +1053,7 @@ protected:
|
|||
/**
|
||||
* Returns if the step attribute apply for the current type.
|
||||
*/
|
||||
bool DoesStepApply() const
|
||||
{
|
||||
// TODO: this is temporary until bug 888316 is fixed.
|
||||
return DoesMinMaxApply() && mType != NS_FORM_INPUT_WEEK;
|
||||
}
|
||||
bool DoesStepApply() const { return DoesMinMaxApply(); }
|
||||
|
||||
/**
|
||||
* Returns if stepDown and stepUp methods apply for the current type.
|
||||
|
@ -1507,9 +1503,13 @@ protected:
|
|||
static const Decimal kStepScaleFactorNumberRange;
|
||||
static const Decimal kStepScaleFactorTime;
|
||||
static const Decimal kStepScaleFactorMonth;
|
||||
static const Decimal kStepScaleFactorWeek;
|
||||
|
||||
// Default step base value when a type do not have specific one.
|
||||
static const Decimal kDefaultStepBase;
|
||||
// Default step base value when type=week does not not have a specific one,
|
||||
// which is −259200000, the start of week 1970-W01.
|
||||
static const Decimal kDefaultStepBaseWeek;
|
||||
|
||||
// Default step used when there is no specified step.
|
||||
static const Decimal kDefaultStep;
|
||||
|
|
|
@ -254,10 +254,62 @@ function error3(event) {
|
|||
}
|
||||
|
||||
function begin() {
|
||||
addFullscreenChangeContinuation("enter", enter1);
|
||||
fullScreenElement().requestFullscreen();
|
||||
testNamespaces(() => {
|
||||
addFullscreenChangeContinuation("enter", enter1);
|
||||
fullScreenElement().requestFullscreen();
|
||||
});
|
||||
}
|
||||
|
||||
function testNamespaces(followupTestFn) {
|
||||
let tests = [
|
||||
{allowed: false, name: "element", ns: "http://www.w3.org/XML/1998/namespace"},
|
||||
{allowed: false, name: "element", ns: "http://www.w3.org/1999/xlink"},
|
||||
{allowed: false, name: "element", ns: "http://www.w3.org/2000/svg"},
|
||||
{allowed: false, name: "element", ns: "http://www.w3.org/1998/Math/MathML"},
|
||||
{allowed: false, name: "mathml", ns: "unknown"},
|
||||
{allowed: false, name: "svg", ns: "unknown"},
|
||||
{allowed: true, name: "element", ns: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"},
|
||||
{allowed: true, name: "element", ns: "http://www.w3.org/1999/xhtml"},
|
||||
{allowed: true, name: "svg", ns: "http://www.w3.org/1999/xhtml"},
|
||||
{allowed: true, name: "math", ns: "http://www.w3.org/1999/xhtml"},
|
||||
{allowed: true, name: "svg", ns: "http://www.w3.org/2000/svg"},
|
||||
{allowed: true, name: "math", ns: "http://www.w3.org/1998/Math/MathML"},
|
||||
{allowed: true, name: "element"},
|
||||
];
|
||||
|
||||
function runNextNamespaceTest() {
|
||||
let test = tests.shift();
|
||||
if (!test) {
|
||||
followupTestFn();
|
||||
return;
|
||||
}
|
||||
|
||||
let elem = test.ns ? document.createElementNS(test.ns, test.name) :
|
||||
document.createElement(test.name);
|
||||
document.body.appendChild(elem);
|
||||
|
||||
if (test.allowed) {
|
||||
addFullscreenChangeContinuation("enter", () => {
|
||||
ok(document.fullscreen, "Document should be in fullscreen");
|
||||
is(document.fullscreenElement, elem,
|
||||
`Element named '${test.name}' in this namespace should be allowed: ${test.ns}`);
|
||||
addFullscreenChangeContinuation("exit", runNextNamespaceTest);
|
||||
document.body.removeChild(elem);
|
||||
});
|
||||
} else {
|
||||
addFullscreenErrorContinuation(() => {
|
||||
ok(!document.fullscreenElement,
|
||||
`Element named '${test.name}' in this namespace should not be allowed: ${test.ns}`);
|
||||
document.body.removeChild(elem);
|
||||
runNextNamespaceTest();
|
||||
});
|
||||
}
|
||||
|
||||
elem.requestFullscreen();
|
||||
}
|
||||
|
||||
runNextNamespaceTest();
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
<div id="full-screen-element"></div>
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=73503">
|
||||
Mozilla Bug 735031</a>
|
||||
|
||||
<svg width="100" height="100" viewbox="0 0 100 100">
|
||||
<rect id="svg-elem" x="10" y="10" width="50" height="50"
|
||||
<svg id="svg-elem" width="100" height="100" viewbox="0 0 100 100">
|
||||
<rect x="10" y="10" width="50" height="50"
|
||||
fill="black" stroke="blue" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
|
|
@ -30,8 +30,7 @@ var data = [
|
|||
{ type: 'datetime', apply: true, todo: true },
|
||||
{ type: 'date', apply: true },
|
||||
{ type: 'month', apply: true },
|
||||
// TODO: temporary set to false until bug 888316 is fixed.
|
||||
{ type: 'week', apply: false },
|
||||
{ type: 'week', apply: true },
|
||||
{ type: 'time', apply: true },
|
||||
{ type: 'datetime-local', apply: true, todo: true },
|
||||
{ type: 'number', apply: true },
|
||||
|
@ -840,7 +839,115 @@ for (var test of data) {
|
|||
|
||||
break;
|
||||
case 'week':
|
||||
// TODO: this is temporary until bug 888316 is fixed.
|
||||
// When step is invalid, every week is valid
|
||||
input.step = 0;
|
||||
input.value = '2016-W30';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = 'foo';
|
||||
input.value = '1970-W01';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = '-1';
|
||||
input.value = '1970-W01';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.removeAttribute('step');
|
||||
input.value = '1500-W01';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = 'any';
|
||||
input.value = '1966-W52';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = 'ANY';
|
||||
input.value = '2013-W10';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
// When min is set to a valid week, there is a step base.
|
||||
input.min = '2000-W01';
|
||||
input.step = '2';
|
||||
input.value = '2000-W03';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.value = '2000-W02';
|
||||
checkValidity(input, false, apply, { low: "2000-W01", high: "2000-W03" });
|
||||
|
||||
input.min = '2012-W52';
|
||||
input.value = '2013-W01';
|
||||
checkValidity(input, false, apply, { low: "2012-W52", high: "2013-W02" });
|
||||
|
||||
input.min = '2010-W01';
|
||||
input.step = '1.1';
|
||||
input.value = '2010-W02';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.min = '2010-W05';
|
||||
input.step = '1.9';
|
||||
input.value = '2010-W06';
|
||||
checkValidity(input, false, apply, { low: "2010-W05", high: "2010-W07" });
|
||||
|
||||
// Without any step attribute the week is valid
|
||||
input.removeAttribute('step');
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.min = '1950-W01';
|
||||
input.step = '53';
|
||||
input.value = '1951-W01';
|
||||
checkValidity(input, false, apply, { low: "1950-W01", high: "1951-W02" });
|
||||
|
||||
input.min = '1951-W01';
|
||||
input.step = '52';
|
||||
input.value = '1952-W01';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = '0.9';
|
||||
input.value = '1951-W02';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = '1.5';
|
||||
input.value = '1951-W04';
|
||||
checkValidity(input, false, apply, { low: "1951-W03", high: "1951-W05" });
|
||||
|
||||
input.value = '1951-W20';
|
||||
checkValidity(input, false, apply, { low: "1951-W19", high: "1951-W21" });
|
||||
|
||||
input.step = '300';
|
||||
input.min= '1968-W01';
|
||||
input.value = '1968-W05';
|
||||
checkValidity(input, false, apply, { low: "1968-W01", high: "1973-W40" });
|
||||
|
||||
input.value = '1971-W01';
|
||||
checkValidity(input, false, apply, { low: "1968-W01", high: "1973-W40" });
|
||||
|
||||
input.value = '1975-W01';
|
||||
checkValidity(input, false, apply, { low: "1973-W40", high: "1979-W27" });
|
||||
|
||||
input.value = '1985-W14';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = '2.1';
|
||||
input.min = '1991-W01';
|
||||
input.value = '1991-W01';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.value = '1991-W02';
|
||||
checkValidity(input, false, apply, { low: "1991-W01", high: "1991-W03" });
|
||||
|
||||
input.value = '1991-W03';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.step = '2.1';
|
||||
input.min = '1969-W52';
|
||||
input.value = '1969-W52';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
input.value = '1970-W01';
|
||||
checkValidity(input, false, apply, { low: "1969-W52", high: "1970-W02" });
|
||||
|
||||
input.value = '1970-W02';
|
||||
checkValidity(input, true, apply);
|
||||
|
||||
break;
|
||||
default:
|
||||
ok(false, "Implement the tests for <input type='" + test.type + " >");
|
||||
|
|
|
@ -51,13 +51,13 @@ function checkAvailability()
|
|||
["date", true],
|
||||
["time", true],
|
||||
["month", true],
|
||||
["week", true],
|
||||
["color", false],
|
||||
];
|
||||
|
||||
var todoList =
|
||||
[
|
||||
["datetime", true],
|
||||
["week", true],
|
||||
["datetime-local", true],
|
||||
];
|
||||
|
||||
|
@ -445,6 +445,70 @@ function checkStepDown()
|
|||
[ '2016-01', 'AnY', null, null, 1, null, true ],
|
||||
[ '2016-01', 'aNy', null, null, 1, null, true ],
|
||||
]},
|
||||
{ type: 'week', data: [
|
||||
// Regular case.
|
||||
[ '2016-W40', null, null, null, null, '2016-W39', false ],
|
||||
// Argument testing.
|
||||
[ '2016-W40', null, null, null, 1, '2016-W39', false ],
|
||||
[ '2016-W40', null, null, null, 5, '2016-W35', false ],
|
||||
[ '2016-W40', null, null, null, -1, '2016-W41', false ],
|
||||
[ '2016-W40', null, null, null, 0, '2016-W40', false ],
|
||||
// Week/Year wrapping.
|
||||
[ '2016-W01', null, null, null, 1, '2015-W53', false ],
|
||||
[ '1969-W02', null, null, null, 4, '1968-W50', false ],
|
||||
[ '1969-W01', null, null, null, -52, '1970-W01', false ],
|
||||
// Float values are rounded to integer (1.1 -> 1).
|
||||
[ '2016-W40', null, null, null, 1.1, '2016-W39', false ],
|
||||
[ '2016-W01', null, null, null, 1.9, '2015-W53', false ],
|
||||
// With step values.
|
||||
[ '2016-W03', '0.5', null, null, null, '2016-W02', false ],
|
||||
[ '2016-W03', '2', null, null, null, '2016-W01', false ],
|
||||
[ '2016-W03', '0.25', null, null, 4, '2015-W52', false ],
|
||||
[ '2016-W52', '1.1', '2016-W01', null, 1, '2016-W51', false ],
|
||||
[ '2016-W52', '1.1', '2016-W01', null, 2, '2016-W50', false ],
|
||||
[ '2016-W52', '1.1', '2016-W01', null, 10, '2016-W42', false ],
|
||||
[ '2016-W52', '1.1', '2016-W01', null, 52, '2016-W01', false ],
|
||||
[ '1968-W52', '1.1', '1968-W01', null, 8, '1968-W44', false ],
|
||||
// step = 0 isn't allowed (-> step = 1).
|
||||
[ '2016-W02', '0', null, null, null, '2016-W01', false ],
|
||||
// step < 0 isn't allowed (-> step = 1).
|
||||
[ '2016-W02', '-1', null, null, null, '2016-W01', false ],
|
||||
// step = NaN isn't allowed (-> step = 1).
|
||||
[ '2016-W02', 'foo', null, null, null, '2016-W01', false ],
|
||||
// Min values testing.
|
||||
[ '2016-W03', '1', 'foo', null, 2, '2016-W01', false ],
|
||||
[ '2016-W02', '1', '2016-01', null, null, '2016-W01', false ],
|
||||
[ '2016-W01', '1', '2016-W01', null, null, '2016-W01', false ],
|
||||
[ '2016-W01', '1', '2016-W01', null, 1, '2016-W01', false ],
|
||||
[ '2016-W05', '3', '2016-W01', null, null, '2016-W04', false ],
|
||||
[ '1969-W01', '5', '1969-W01', '1969-W02', null, '1969-W01', false ],
|
||||
// Max values testing.
|
||||
[ '2016-W02', '1', null, 'foo', null, '2016-W01', false ],
|
||||
[ '2016-W02', null, null, '2016-W05', null, '2016-W01', false ],
|
||||
[ '2016-W03', null, null, '2016-W03', null, '2016-W02', false ],
|
||||
[ '2016-W07', null, null, '2016-W04', 4, '2016-W03', false ],
|
||||
[ '2016-W07', '2', null, '2016-W04', 3, '2016-W01', false ],
|
||||
// Step mismatch.
|
||||
[ '2016-W04', '2', '2016-W01', null, null, '2016-W03', false ],
|
||||
[ '2016-W06', '2', '2016-W01', null, 2, '2016-W03', false ],
|
||||
[ '2016-W05', '2', '2016-W04', '2016-W08', null, '2016-W04', false ],
|
||||
[ '1970-W04', '2', null, null, null, '1970-W02', false ],
|
||||
[ '1970-W09', '3', null, null, null, '1970-W06', false ],
|
||||
// Clamping.
|
||||
[ '2016-W05', null, null, '2016-W01', null, '2016-W01', false ],
|
||||
[ '1970-W05', '2', '1970-W02', '1970-W05', null, '1970-W04', false ],
|
||||
[ '1970-W01', '5', '1970-W02', '1970-W09', 10, '1970-W01', false ],
|
||||
[ '1970-W07', '5', '1969-W52', '1970-W10', 2, '1969-W52', false ],
|
||||
[ '1970-W08', '3', '1970-W01', '1970-W07', 15, '1970-W01', false ],
|
||||
[ '1970-W10', '3', '1970-W01', '1970-W06', 2, '1970-W04', false ],
|
||||
// value = "" (NaN).
|
||||
[ '', null, null, null, null, '1970-W01', false ],
|
||||
// With step = 'any'.
|
||||
[ '2016-W01', 'any', null, null, 1, null, true ],
|
||||
[ '2016-W01', 'ANY', null, null, 1, null, true ],
|
||||
[ '2016-W01', 'AnY', null, null, 1, null, true ],
|
||||
[ '2016-W01', 'aNy', null, null, 1, null, true ],
|
||||
]},
|
||||
];
|
||||
|
||||
for (var test of testData) {
|
||||
|
@ -829,6 +893,71 @@ function checkStepUp()
|
|||
[ '2016-01', 'AnY', null, null, 1, null, true ],
|
||||
[ '2016-01', 'aNy', null, null, 1, null, true ],
|
||||
]},
|
||||
{ type: 'week', data: [
|
||||
// Regular case.
|
||||
[ '2016-W40', null, null, null, null, '2016-W41', false ],
|
||||
// Argument testing.
|
||||
[ '2016-W40', null, null, null, 1, '2016-W41', false ],
|
||||
[ '2016-W40', null, null, null, 20, '2017-W08', false ],
|
||||
[ '2016-W40', null, null, null, -1, '2016-W39', false ],
|
||||
[ '2016-W40', null, null, null, 0, '2016-W40', false ],
|
||||
// Week/Year wrapping.
|
||||
[ '2015-W53', null, null, null, 1, '2016-W01', false ],
|
||||
[ '1968-W52', null, null, null, 4, '1969-W04', false ],
|
||||
[ '1970-W01', null, null, null, -52, '1969-W01', false ],
|
||||
// Float values are rounded to integer (1.1 -> 1).
|
||||
[ '2016-W01', null, null, null, 1.1, '2016-W02', false ],
|
||||
[ '2016-W01', null, null, null, 1.9, '2016-W02', false ],
|
||||
// With step values.
|
||||
[ '2016-W01', '0.5', null, null, null, '2016-W02', false ],
|
||||
[ '2016-W01', '2', null, null, null, '2016-W03', false ],
|
||||
[ '2016-W01', '0.25', null, null, 4, '2016-W05', false ],
|
||||
[ '2016-W01', '1.1', '2016-01', null, 1, '2016-W02', false ],
|
||||
[ '2016-W01', '1.1', '2016-01', null, 2, '2016-W03', false ],
|
||||
[ '2016-W01', '1.1', '2016-01', null, 10, '2016-W11', false ],
|
||||
[ '2016-W01', '1.1', '2016-01', null, 20, '2016-W21', false ],
|
||||
// step = 0 isn't allowed (-> step = 1).
|
||||
[ '2016-W01', '0', null, null, null, '2016-W02', false ],
|
||||
// step < 0 isn't allowed (-> step = 1).
|
||||
[ '2016-W01', '-1', null, null, null, '2016-W02', false ],
|
||||
// step = NaN isn't allowed (-> step = 1).
|
||||
[ '2016-W01', 'foo', null, null, null, '2016-W02', false ],
|
||||
// Min values testing.
|
||||
[ '2016-W01', '1', 'foo', null, null, '2016-W02', false ],
|
||||
[ '2016-W01', null, '2015-W53', null, null, '2016-W02', false ],
|
||||
[ '2016-W01', null, '2016-W02', null, null, '2016-W02', false ],
|
||||
[ '2016-W01', null, '2016-W01', null, null, '2016-W02', false ],
|
||||
[ '2016-W01', null, '2016-W04', null, 4, '2016-W05', false ],
|
||||
[ '2016-W01', '2', '2016-W04', null, 3, '2016-W06', false ],
|
||||
// Max values testing.
|
||||
[ '2016-W01', '1', null, 'foo', 2, '2016-W03', false ],
|
||||
[ '2016-W01', '1', null, '2016-W02', 1, '2016-W02', false ],
|
||||
[ '2016-W02', null, null, '2016-W01', null, '2016-W02', false ],
|
||||
[ '2016-W02', null, null, '2016-W02', null, '2016-W02', false ],
|
||||
[ '1969-W02', '5', '1969-W01', '1969-W02', null, '1969-W02', false ],
|
||||
// Step mismatch.
|
||||
[ '2016-W02', '2', '2016-W01', null, null, '2016-W03', false ],
|
||||
[ '2016-W02', '2', '2016-W01', null, 2, '2016-W05', false ],
|
||||
[ '2016-W05', '2', '2016-W01', '2016-W06', null, '2016-W05', false ],
|
||||
[ '1970-W02', '2', null, null, null, '1970-W04', false ],
|
||||
[ '1970-W05', '3', null, null, null, '1970-W08', false ],
|
||||
[ '1970-W03', '3', null, null, null, '1970-W06', false ],
|
||||
[ '1970-W03', '3', '1970-W02', null, null, '1970-W05', false ],
|
||||
// Clamping.
|
||||
[ '2016-W01', null, '2016-W52', null, null, '2016-W52', false ],
|
||||
[ '1970-W02', '2', '1970-W01', '1970-W04', null, '1970-W03', false ],
|
||||
[ '1970-W01', '5', '1970-W02', '1970-W09', 10, '1970-W07', false ],
|
||||
[ '1969-W50', '5', '1969-W52', '1970-W06', 3, '1970-W05', false ],
|
||||
[ '1970-W01', '3', '1970-W02', '1971-W07', 15, '1970-W44', false ],
|
||||
[ '1970-W01', '3', '1970-W01', '1970-W06', 2, '1970-W04', false ],
|
||||
// value = "" (NaN).
|
||||
[ '', null, null, null, null, '1970-W02', false ],
|
||||
// With step = 'any'.
|
||||
[ '2016-W01', 'any', null, null, 1, null, true ],
|
||||
[ '2016-W01', 'ANY', null, null, 1, null, true ],
|
||||
[ '2016-W01', 'AnY', null, null, 1, null, true ],
|
||||
[ '2016-W01', 'aNy', null, null, 1, null, true ],
|
||||
]},
|
||||
];
|
||||
|
||||
for (var test of testData) {
|
||||
|
|
|
@ -71,6 +71,7 @@ FullscreenDeniedFocusedPlugin=Request for fullscreen was denied because a window
|
|||
FullscreenDeniedHidden=Request for fullscreen was denied because the document is no longer visible.
|
||||
FullscreenDeniedContainerNotAllowed=Request for fullscreen was denied because at least one of the document’s containing elements is not an iframe or does not have an “allowfullscreen” attribute.
|
||||
FullscreenDeniedNotInputDriven=Request for fullscreen was denied because Element.requestFullscreen() was not called from inside a short running user-generated event handler.
|
||||
FullscreenDeniedNotHTMLSVGOrMathML=Request for fullscreen was denied because requesting element is not <svg>, <math>, or an HTML element.
|
||||
FullscreenDeniedNotInDocument=Request for fullscreen was denied because requesting element is no longer in its document.
|
||||
FullscreenDeniedMovedDocument=Request for fullscreen was denied because requesting element has moved document.
|
||||
FullscreenDeniedLostWindow=Request for fullscreen was denied because we no longer have a window.
|
||||
|
|
|
@ -575,8 +575,7 @@ PresentationConnection::DispatchMessageEvent(JS::Handle<JS::Value> aData)
|
|||
return rv;
|
||||
}
|
||||
|
||||
RefPtr<MessageEvent> messageEvent =
|
||||
NS_NewDOMMessageEvent(this, nullptr, nullptr);
|
||||
RefPtr<MessageEvent> messageEvent = new MessageEvent(this, nullptr, nullptr);
|
||||
|
||||
messageEvent->InitMessageEvent(nullptr,
|
||||
NS_LITERAL_STRING("message"),
|
||||
|
|
|
@ -51,6 +51,7 @@ static bool IsImageLoadInEditorAppType(nsILoadInfo* aLoadInfo)
|
|||
nsContentPolicyType type = aLoadInfo->InternalContentPolicyType();
|
||||
if (type != nsIContentPolicy::TYPE_INTERNAL_IMAGE &&
|
||||
type != nsIContentPolicy::TYPE_INTERNAL_IMAGE_PRELOAD &&
|
||||
type != nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON &&
|
||||
type != nsIContentPolicy::TYPE_IMAGESET) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<html>
|
||||
|
||||
<head>
|
||||
<link rel='icon' href='favicon_bug1277803.ico'>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
Nothing to see here...
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,7 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
favicon_bug1277803.ico
|
||||
bug1277803.html
|
||||
|
||||
[test_bug1277803.xul]
|
||||
skip-if = os == 'android'
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 1.4 KiB |
|
@ -0,0 +1,99 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
|
||||
|
||||
<window title="Bug 1277803 test"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
width="600"
|
||||
height="600"
|
||||
onload="runTest();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
</body>
|
||||
|
||||
<script type="application/javascript"><![CDATA[
|
||||
SimpleTest.requestCompleteLog();
|
||||
let Ci = Components.interfaces;
|
||||
let Cc = Components.classes;
|
||||
let Cu = Components.utils;
|
||||
let makeURI = Cu.import("resource://gre/modules/BrowserUtils.jsm", {}).BrowserUtils.makeURI;
|
||||
|
||||
const BASE_URI = "http://mochi.test:8888/chrome/dom/security/test/general/";
|
||||
const FAVICON_URI = BASE_URI + "favicon_bug1277803.ico";
|
||||
const LOADING_URI = BASE_URI + "bug1277803.html";
|
||||
let testWindow; //will be used to trigger favicon load
|
||||
|
||||
let securityManager = Cc["@mozilla.org/scriptsecuritymanager;1"].
|
||||
getService(Ci.nsIScriptSecurityManager);
|
||||
let expectedPrincipal = securityManager.createCodebasePrincipal(makeURI(LOADING_URI), {});
|
||||
let systemPrincipal = Cc["@mozilla.org/systemprincipal;1"].createInstance();
|
||||
|
||||
// We expect 2 favicon loads, one from PlacesUIUtils.loadFavicon and one
|
||||
// from XUL:image loads.
|
||||
let requestXUL = false;
|
||||
let requestPlaces = false;
|
||||
|
||||
function runTest() {
|
||||
// Register our observer to intercept favicon requests.
|
||||
let os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
let observer = {
|
||||
observe: function(aSubject, aTopic, aData)
|
||||
{
|
||||
// Make sure this is a favicon request.
|
||||
let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
|
||||
if (FAVICON_URI != httpChannel.URI.spec) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure the topic is the one we set an observer for.
|
||||
is(aTopic, "http-on-modify-request", "Expected observer topic");
|
||||
|
||||
// Check for the correct loadingPrincipal, triggeringPrincipal.
|
||||
let triggeringPrincipal = httpChannel.loadInfo.triggeringPrincipal;
|
||||
let loadingPrincipal = httpChannel.loadInfo.loadingPrincipal;
|
||||
|
||||
if (loadingPrincipal.equals(systemPrincipal)) {
|
||||
// This is the favicon loading from XUL, which will have the system
|
||||
// principal as its loading principal and have a content principal
|
||||
// as its triggering principal.
|
||||
ok(triggeringPrincipal.equals(expectedPrincipal),
|
||||
"Correct triggeringPrincipal for favicon from XUL.");
|
||||
requestXUL = true;
|
||||
} else if (loadingPrincipal.equals(expectedPrincipal)) {
|
||||
// This is the favicon loading from Places, which will have a
|
||||
// content principal as its loading principal and triggering
|
||||
// principal.
|
||||
ok(triggeringPrincipal.equals(expectedPrincipal),
|
||||
"Correct triggeringPrincipal for favicon from Places.");
|
||||
requestPlaces = true;
|
||||
} else {
|
||||
ok(false, "An unexpected favicon request.")
|
||||
}
|
||||
|
||||
// Cleanup after ourselves...
|
||||
if (requestXUL && requestPlaces) {
|
||||
os.removeObserver(this, "http-on-modify-request");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
os.addObserver(observer, "http-on-modify-request", false);
|
||||
|
||||
// Now that the observer is set up, trigger a favicon load with navigation
|
||||
testWindow = window.open(LOADING_URI);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.registerCleanupFunction(function() {
|
||||
if (testWindow) {
|
||||
testWindow.close();
|
||||
}
|
||||
});
|
||||
]]></script>
|
||||
|
||||
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
|
||||
</window>
|
|
@ -22,6 +22,7 @@ MOCHITEST_MANIFESTS += [
|
|||
|
||||
MOCHITEST_CHROME_MANIFESTS += [
|
||||
'csp/chrome.ini',
|
||||
'general/chrome.ini',
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
Mozilla Bug 633602</a>
|
||||
<p id="display"></p>
|
||||
|
||||
<svg width="100" height="100" viewbox="0 0 100 100">
|
||||
<rect id="svg-elem" x="10" y="10" width="50" height="50"
|
||||
<svg id="svg-elem" width="100" height="100" viewbox="0 0 100 100">
|
||||
<rect x="10" y="10" width="50" height="50"
|
||||
fill="black" stroke="blue" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
|
|
@ -70,7 +70,7 @@ AssembleClientData(const nsAString& aOrigin, const nsAString& aTyp,
|
|||
}
|
||||
|
||||
if (NS_WARN_IF(!aClientData.Assign(NS_ConvertUTF16toUTF8(json)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -246,7 +246,12 @@ U2FRegisterTask::Run()
|
|||
}
|
||||
|
||||
MOZ_ASSERT(buffer);
|
||||
regData.Assign(buffer, bufferlen);
|
||||
if (NS_WARN_IF(!regData.Assign(buffer, bufferlen))) {
|
||||
free(buffer);
|
||||
ReturnError(ErrorCode::OTHER_ERROR);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
registerSuccess = true;
|
||||
break;
|
||||
|
@ -424,7 +429,12 @@ U2FSignTask::Run()
|
|||
}
|
||||
|
||||
MOZ_ASSERT(buffer);
|
||||
signatureData.Assign(buffer, bufferlen);
|
||||
if (NS_WARN_IF(!signatureData.Assign(buffer, bufferlen))) {
|
||||
free(buffer);
|
||||
ReturnError(ErrorCode::OTHER_ERROR);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
signSuccess = true;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
var worker = new Worker("url_worker.js");
|
||||
|
||||
worker.onmessage = function(event) {
|
||||
is(event.target, worker);
|
||||
is(event.target, worker, "Correct worker");
|
||||
|
||||
if (event.data.type == 'finish') {
|
||||
runTest();
|
||||
|
@ -37,7 +37,7 @@
|
|||
};
|
||||
|
||||
worker.onerror = function(event) {
|
||||
is(event.target, worker);
|
||||
is(event.target, worker, "Correct worker");
|
||||
ok(false, "Worker had an error: " + event.message);
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
|
|
@ -2668,7 +2668,6 @@ WorkerPrivateParent<Derived>::Thaw(nsPIDOMWindowInner* aWindow)
|
|||
// Execute queued runnables before waking up the worker, otherwise the worker
|
||||
// could post new messages before we run those that have been queued.
|
||||
if (!IsParentWindowPaused() && !mQueuedRunnables.IsEmpty()) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(IsDedicatedWorker());
|
||||
|
||||
nsTArray<nsCOMPtr<nsIRunnable>> runnables;
|
||||
|
@ -2720,7 +2719,6 @@ WorkerPrivateParent<Derived>::ParentWindowResumed()
|
|||
// Execute queued runnables before waking up, otherwise the worker could post
|
||||
// new messages before we run those that have been queued.
|
||||
if (!IsFrozen() && !mQueuedRunnables.IsEmpty()) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(IsDedicatedWorker());
|
||||
|
||||
nsTArray<nsCOMPtr<nsIRunnable>> runnables;
|
||||
|
|
|
@ -419,7 +419,7 @@ public:
|
|||
void
|
||||
QueueRunnable(nsIRunnable* aRunnable)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
AssertIsOnParentThread();
|
||||
mQueuedRunnables.AppendElement(aRunnable);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,14 +21,15 @@
|
|||
#include "mozilla/dom/VideoDecoderManagerParent.h"
|
||||
#include "mozilla/layers/CompositorThread.h"
|
||||
#include "mozilla/layers/ImageBridgeParent.h"
|
||||
#include "nsDebugImpl.h"
|
||||
#include "mozilla/layers/LayerTreeOwnerTracker.h"
|
||||
#include "ProcessUtils.h"
|
||||
#include "nsDebugImpl.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsThreadManager.h"
|
||||
#include "prenv.h"
|
||||
#include "ProcessUtils.h"
|
||||
#include "VRManager.h"
|
||||
#include "VRManagerParent.h"
|
||||
#include "VsyncBridgeParent.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
#if defined(XP_WIN)
|
||||
# include "DeviceManagerD3D9.h"
|
||||
# include "mozilla/gfx/DeviceManagerDx.h"
|
||||
|
@ -66,6 +67,13 @@ GPUParent::Init(base::ProcessId aParentPid,
|
|||
MessageLoop* aIOLoop,
|
||||
IPC::Channel* aChannel)
|
||||
{
|
||||
// Initialize the thread manager before starting IPC. Otherwise, messages
|
||||
// may be posted to the main thread and we won't be able to process them.
|
||||
if (NS_WARN_IF(NS_FAILED(nsThreadManager::get().Init()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now it's safe to start IPC.
|
||||
if (NS_WARN_IF(!Open(aChannel, aParentPid, aIOLoop))) {
|
||||
return false;
|
||||
}
|
||||
|
@ -161,7 +169,7 @@ GPUParent::RecvInit(nsTArray<GfxPrefSetting>&& prefs,
|
|||
bool
|
||||
GPUParent::RecvInitVsyncBridge(Endpoint<PVsyncBridgeParent>&& aVsyncEndpoint)
|
||||
{
|
||||
VsyncBridgeParent::Start(Move(aVsyncEndpoint));
|
||||
mVsyncBridge = VsyncBridgeParent::Start(Move(aVsyncEndpoint));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -317,6 +325,7 @@ GPUParent::ActorDestroy(ActorDestroyReason aWhy)
|
|||
|
||||
if (mVsyncBridge) {
|
||||
mVsyncBridge->Shutdown();
|
||||
mVsyncBridge = nullptr;
|
||||
}
|
||||
CompositorThreadHolder::Shutdown();
|
||||
#if defined(XP_WIN)
|
||||
|
@ -330,7 +339,6 @@ GPUParent::ActorDestroy(ActorDestroyReason aWhy)
|
|||
#ifdef MOZ_CRASHREPORTER
|
||||
CrashReporterClient::DestroySingleton();
|
||||
#endif
|
||||
NS_ShutdownXPCOM(nullptr);
|
||||
XRE_ShutdownChildProcess();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
#include "GPUProcessImpl.h"
|
||||
#include "mozilla/ipc/IOThreadChild.h"
|
||||
#include "nsXPCOM.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
@ -31,6 +32,7 @@ GPUProcessImpl::Init()
|
|||
void
|
||||
GPUProcessImpl::CleanUp()
|
||||
{
|
||||
NS_ShutdownXPCOM(nullptr);
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
|
|
|
@ -55,10 +55,16 @@ VsyncBridgeParent::Shutdown()
|
|||
{
|
||||
MessageLoop* ccloop = CompositorThreadHolder::Loop();
|
||||
if (MessageLoop::current() != ccloop) {
|
||||
ccloop->PostTask(NewRunnableMethod(this, &VsyncBridgeParent::Shutdown));
|
||||
ccloop->PostTask(NewRunnableMethod(this, &VsyncBridgeParent::ShutdownImpl));
|
||||
return;
|
||||
}
|
||||
|
||||
ShutdownImpl();
|
||||
}
|
||||
|
||||
void
|
||||
VsyncBridgeParent::ShutdownImpl()
|
||||
{
|
||||
if (mOpen) {
|
||||
Close();
|
||||
mOpen = false;
|
||||
|
|
|
@ -30,6 +30,7 @@ private:
|
|||
~VsyncBridgeParent();
|
||||
|
||||
void Open(Endpoint<PVsyncBridgeParent>&& aEndpoint);
|
||||
void ShutdownImpl();
|
||||
|
||||
private:
|
||||
bool mOpen;
|
||||
|
|
|
@ -71,6 +71,7 @@ IPDL_SOURCES = [
|
|||
LOCAL_INCLUDES += [
|
||||
'/dom/ipc',
|
||||
'/toolkit/crashreporter',
|
||||
'/xpcom/threads',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "mozilla/layers/PersistentBufferProvider.h"
|
||||
#include "ClientReadbackLayer.h" // for ClientReadbackLayer
|
||||
#include "nsAString.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsIWidgetListener.h"
|
||||
#include "nsTArray.h" // for AutoTArray
|
||||
#include "nsXULAppAPI.h" // for XRE_GetProcessType, etc
|
||||
|
@ -275,13 +276,11 @@ ClientLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback,
|
|||
void* aCallbackData,
|
||||
EndTransactionFlags)
|
||||
{
|
||||
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Rasterization);
|
||||
|
||||
PROFILER_LABEL("ClientLayerManager", "EndTransactionInternal",
|
||||
js::ProfileEntry::Category::GRAPHICS);
|
||||
|
||||
if (!mForwarder || !mForwarder->IPCOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef MOZ_LAYERS_HAVE_LOG
|
||||
MOZ_LAYERS_LOG((" ----- (beginning paint)"));
|
||||
Log();
|
||||
|
@ -356,6 +355,12 @@ ClientLayerManager::EndTransaction(DrawPaintedLayerCallback aCallback,
|
|||
void* aCallbackData,
|
||||
EndTransactionFlags aFlags)
|
||||
{
|
||||
if (!mForwarder->IPCOpen()) {
|
||||
mTransactionIdAllocator->RevokeTransactionId(mLatestTransactionId);
|
||||
mInTransaction = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mWidget) {
|
||||
mWidget->PrepareWindowEffects();
|
||||
}
|
||||
|
@ -381,9 +386,11 @@ ClientLayerManager::EndEmptyTransaction(EndTransactionFlags aFlags)
|
|||
{
|
||||
mInTransaction = false;
|
||||
|
||||
if (!mRoot) {
|
||||
if (!mRoot || !mForwarder->IPCOpen()) {
|
||||
mTransactionIdAllocator->RevokeTransactionId(mLatestTransactionId);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!EndTransactionInternal(nullptr, nullptr, aFlags)) {
|
||||
// Return without calling ForwardTransaction. This leaves the
|
||||
// ShadowLayerForwarder transaction open; the following
|
||||
|
|
|
@ -743,14 +743,28 @@ NewImageChannel(nsIChannel** aResult,
|
|||
nullptr, // loadGroup
|
||||
callbacks,
|
||||
aLoadFlags);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (aPolicyType == nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON) {
|
||||
// If this is a favicon loading, we will use the originAttributes from the
|
||||
// loadingPrincipal as the channel's originAttributes. This allows the favicon
|
||||
// loading from XUL will use the correct originAttributes.
|
||||
NeckoOriginAttributes neckoAttrs;
|
||||
neckoAttrs.InheritFromDocToNecko(BasePrincipal::Cast(aLoadingPrincipal)->OriginAttributesRef());
|
||||
|
||||
nsCOMPtr<nsILoadInfo> loadInfo = (*aResult)->GetLoadInfo();
|
||||
rv = loadInfo->SetOriginAttributes(neckoAttrs);
|
||||
}
|
||||
} else {
|
||||
// either we are loading something inside a document, in which case
|
||||
// we should always have a requestingNode, or we are loading something
|
||||
// outside a document, in which case the loadingPrincipal and
|
||||
// triggeringPrincipal should always be the systemPrincipal.
|
||||
// However, there are two exceptions: one is Notifications and the
|
||||
// other one is Favicons which create a channel in the parent prcoess
|
||||
// in which case we can't get a requestingNode.
|
||||
// However, there are exceptions: one is Notifications which create a
|
||||
// channel in the parent prcoess in which case we can't get a requestingNode.
|
||||
rv = NS_NewChannel(aResult,
|
||||
aURI,
|
||||
nsContentUtils::GetSystemPrincipal(),
|
||||
|
|
|
@ -250,9 +250,13 @@ UnixExceptionHandler(int signum, siginfo_t* info, void* context)
|
|||
if (sPrevSEGVHandler.sa_flags & SA_SIGINFO)
|
||||
sPrevSEGVHandler.sa_sigaction(signum, info, context);
|
||||
else if (sPrevSEGVHandler.sa_handler == SIG_DFL || sPrevSEGVHandler.sa_handler == SIG_IGN)
|
||||
raise(signum);
|
||||
sigaction(SIGSEGV, &sPrevSEGVHandler, nullptr);
|
||||
else
|
||||
sPrevSEGVHandler.sa_handler(signum);
|
||||
|
||||
// If we reach here, we're returning to let the default signal handler deal
|
||||
// with the exception. This is technically undefined behavior, but
|
||||
// everything seems to do it, and it removes us from the crash stack.
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -266,7 +270,7 @@ MemoryProtectionExceptionHandler::install()
|
|||
|
||||
// Install our new exception handler and save the previous one.
|
||||
struct sigaction faultHandler = {};
|
||||
faultHandler.sa_flags = SA_SIGINFO;
|
||||
faultHandler.sa_flags = SA_SIGINFO | SA_NODEFER;
|
||||
faultHandler.sa_sigaction = UnixExceptionHandler;
|
||||
sigemptyset(&faultHandler.sa_mask);
|
||||
sExceptionHandlerInstalled = !sigaction(SIGSEGV, &faultHandler, &sPrevSEGVHandler);
|
||||
|
|
|
@ -18,8 +18,20 @@ assertEq(f(0), 0);
|
|||
|
||||
setCachingEnabled(true);
|
||||
|
||||
// In order to allow following tests work on both big-endian and little-
|
||||
// endian architectures we need to define least significant byte (lsb) and
|
||||
// least significant word (lsw).
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) {i=i|0; i32[0] = i; return i8[0]|0}; return f');
|
||||
var f = asmLink(code, this, null, new ArrayBuffer(BUF_MIN));
|
||||
var lsb=0;
|
||||
var lsw=0
|
||||
if (f(0x12345678) == 0x12) {
|
||||
lsb=3;
|
||||
lsw=1;
|
||||
}
|
||||
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) {i=i|0; i32[0] = i; return i8[' + lsb + ']|0}; return f');
|
||||
var f = asmLink(code, this, null, new ArrayBuffer(BUF_MIN));
|
||||
assertEq(f(0),0);
|
||||
assertEq(f(0x7f),0x7f);
|
||||
assertEq(f(0xff),-1);
|
||||
|
@ -27,7 +39,7 @@ assertEq(f(0x100),0);
|
|||
|
||||
{
|
||||
var buf = new ArrayBuffer(BUF_MIN);
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + '/* not a clone */ function f(i) {i=i|0; i32[0] = i; return i8[0]|0}; return f');
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + '/* not a clone */ function f(i) {i=i|0; i32[0] = i; return i8[' + lsb + ']|0}; return f');
|
||||
var f = asmLink(code, this, null, buf);
|
||||
assertEq(f(0),0);
|
||||
assertEq(f(0x7f),0x7f);
|
||||
|
@ -40,21 +52,21 @@ assertEq(f(0x100),0);
|
|||
|
||||
setCachingEnabled(false);
|
||||
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) {i=i|0; i32[0] = i; return u8[0]|0}; return f');
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) {i=i|0; i32[0] = i; return u8[' + lsb + ']|0}; return f');
|
||||
var f = asmLink(code, this, null, new ArrayBuffer(BUF_MIN));
|
||||
assertEq(f(0),0);
|
||||
assertEq(f(0x7f),0x7f);
|
||||
assertEq(f(0xff),0xff);
|
||||
assertEq(f(0x100),0);
|
||||
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) {i=i|0; i32[0] = i; return i16[0]|0}; return f');
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) {i=i|0; i32[0] = i; return i16[' + lsw + ']|0}; return f');
|
||||
var f = asmLink(code, this, null, new ArrayBuffer(BUF_MIN));
|
||||
assertEq(f(0),0);
|
||||
assertEq(f(0x7fff),0x7fff);
|
||||
assertEq(f(0xffff),-1);
|
||||
assertEq(f(0x10000),0);
|
||||
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) {i=i|0; i32[0] = i; return u16[0]|0}; return f');
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) {i=i|0; i32[0] = i; return u16[' + lsw + ']|0}; return f');
|
||||
var f = asmLink(code, this, null, new ArrayBuffer(BUF_MIN));
|
||||
assertEq(f(0),0);
|
||||
assertEq(f(0x7fff),0x7fff);
|
||||
|
@ -75,14 +87,14 @@ assertEq(f(0x7fffffff),0x7fffffff);
|
|||
assertEq(f(0xffffffff),-1);
|
||||
assertEq(f(0x100000000),0);
|
||||
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) {i=i|0; i32[0] = i; return i8[0]|0}; return f');
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) {i=i|0; i32[0] = i; return i8[' + lsb + ']|0}; return f');
|
||||
var f = asmLink(code, this, null, new ArrayBuffer(BUF_MIN));
|
||||
assertEq(f(0),0);
|
||||
assertEq(f(0x7f),0x7f);
|
||||
assertEq(f(0xff),-1);
|
||||
assertEq(f(0x100),0);
|
||||
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) {i=i|0; i32[0] = i; return u8[0]|0}; return f');
|
||||
var code = asmCompile('glob', 'imp', 'b', USE_ASM + HEAP_IMPORTS + 'function f(i) {i=i|0; i32[0] = i; return u8[' + lsb + ']|0}; return f');
|
||||
var f = asmLink(code, this, null, new ArrayBuffer(BUF_MIN));
|
||||
assertEq(f(0),0);
|
||||
assertEq(f(0x7f),0x7f);
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
// getJitCompilerOptions will always return array with zeros when JIT is
|
||||
// disabled. Therefore we quit now.
|
||||
if (inJit() == 'Baseline is disabled.') {
|
||||
print("JIT is disabled.");
|
||||
quit();
|
||||
}
|
||||
|
||||
var wait = 100;
|
||||
|
||||
var method_A = function() {
|
||||
|
|
|
@ -14,6 +14,5 @@ var test = (function () {
|
|||
try {
|
||||
evalWithCache(test, {});
|
||||
} catch (x) {
|
||||
assertEq(x.message.includes("AsmJS"), true);
|
||||
assertEq(x.message.includes("XDR"), true);
|
||||
assertEq(x.message.includes("Asm.js is not supported by XDR"), true);
|
||||
}
|
||||
|
|
|
@ -55,7 +55,13 @@ class BufferPointer
|
|||
return (T*)p;
|
||||
}
|
||||
|
||||
T& operator*() const { return *get(); }
|
||||
void set(const T& value) {
|
||||
*get() = value;
|
||||
}
|
||||
|
||||
// Note: we return a copy instead of a reference, to avoid potential memory
|
||||
// safety hazards when the underlying buffer gets resized.
|
||||
const T operator*() const { return *get(); }
|
||||
T* operator->() const { return get(); }
|
||||
};
|
||||
|
||||
|
@ -111,7 +117,7 @@ struct BaselineStackBuilder
|
|||
js_free(buffer_);
|
||||
}
|
||||
|
||||
bool init() {
|
||||
MOZ_MUST_USE bool init() {
|
||||
MOZ_ASSERT(!buffer_);
|
||||
MOZ_ASSERT(bufferUsed_ == 0);
|
||||
buffer_ = reinterpret_cast<uint8_t*>(js_calloc(bufferTotal_));
|
||||
|
@ -136,7 +142,7 @@ struct BaselineStackBuilder
|
|||
return true;
|
||||
}
|
||||
|
||||
bool enlarge() {
|
||||
MOZ_MUST_USE bool enlarge() {
|
||||
MOZ_ASSERT(buffer_ != nullptr);
|
||||
if (bufferTotal_ & mozilla::tl::MulOverflowMask<2>::value)
|
||||
return false;
|
||||
|
@ -176,7 +182,7 @@ struct BaselineStackBuilder
|
|||
return framePushed_;
|
||||
}
|
||||
|
||||
bool subtract(size_t size, const char* info = nullptr) {
|
||||
MOZ_MUST_USE bool subtract(size_t size, const char* info = nullptr) {
|
||||
// enlarge the buffer if need be.
|
||||
while (size > bufferAvail_) {
|
||||
if (!enlarge())
|
||||
|
@ -197,7 +203,10 @@ struct BaselineStackBuilder
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
bool write(const T& t) {
|
||||
MOZ_MUST_USE bool write(const T& t) {
|
||||
MOZ_ASSERT(!(uintptr_t(&t) >= uintptr_t(header_->copyStackBottom) &&
|
||||
uintptr_t(&t) < uintptr_t(header_->copyStackTop)),
|
||||
"Should not reference memory that can be freed");
|
||||
if (!subtract(sizeof(T)))
|
||||
return false;
|
||||
memcpy(header_->copyStackBottom, &t, sizeof(T));
|
||||
|
@ -205,7 +214,7 @@ struct BaselineStackBuilder
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
bool writePtr(T* t, const char* info) {
|
||||
MOZ_MUST_USE bool writePtr(T* t, const char* info) {
|
||||
if (!write<T*>(t))
|
||||
return false;
|
||||
if (info)
|
||||
|
@ -215,7 +224,7 @@ struct BaselineStackBuilder
|
|||
return true;
|
||||
}
|
||||
|
||||
bool writeWord(size_t w, const char* info) {
|
||||
MOZ_MUST_USE bool writeWord(size_t w, const char* info) {
|
||||
if (!write<size_t>(w))
|
||||
return false;
|
||||
if (info) {
|
||||
|
@ -232,7 +241,7 @@ struct BaselineStackBuilder
|
|||
return true;
|
||||
}
|
||||
|
||||
bool writeValue(const Value& val, const char* info) {
|
||||
MOZ_MUST_USE bool writeValue(const Value& val, const char* info) {
|
||||
if (!write<Value>(val))
|
||||
return false;
|
||||
if (info) {
|
||||
|
@ -244,7 +253,7 @@ struct BaselineStackBuilder
|
|||
return true;
|
||||
}
|
||||
|
||||
bool maybeWritePadding(size_t alignment, size_t after, const char* info) {
|
||||
MOZ_MUST_USE bool maybeWritePadding(size_t alignment, size_t after, const char* info) {
|
||||
MOZ_ASSERT(framePushed_ % sizeof(Value) == 0);
|
||||
MOZ_ASSERT(after % sizeof(Value) == 0);
|
||||
size_t offset = ComputeByteAlignment(after, alignment);
|
||||
|
@ -430,7 +439,7 @@ class SnapshotIteratorForBailout : public SnapshotIterator
|
|||
|
||||
// Take previously computed result out of the activation, or compute the
|
||||
// results of all recover instructions contained in the snapshot.
|
||||
bool init(JSContext* cx) {
|
||||
MOZ_MUST_USE bool init(JSContext* cx) {
|
||||
|
||||
// Under a bailout, there is no need to invalidate the frame after
|
||||
// evaluating the recover instruction, as the invalidation is only
|
||||
|
@ -758,7 +767,7 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC,
|
|||
JitSpew(JitSpew_BaselineBailouts, " thisv=%016llx", *((uint64_t*) &thisv));
|
||||
|
||||
size_t thisvOffset = builder.framePushed() + JitFrameLayout::offsetOfThis();
|
||||
*builder.valuePointerAtStackOffset(thisvOffset) = thisv;
|
||||
builder.valuePointerAtStackOffset(thisvOffset).set(thisv);
|
||||
|
||||
MOZ_ASSERT(iter.numAllocations() >= CountArgSlots(script, fun));
|
||||
JitSpew(JitSpew_BaselineBailouts, " frame slots %u, nargs %u, nfixed %u",
|
||||
|
@ -781,7 +790,7 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC,
|
|||
(int) i, *((uint64_t*) &arg));
|
||||
if (callerPC) {
|
||||
size_t argOffset = builder.framePushed() + JitFrameLayout::offsetOfActualArg(i);
|
||||
*builder.valuePointerAtStackOffset(argOffset) = arg;
|
||||
builder.valuePointerAtStackOffset(argOffset).set(arg);
|
||||
} else {
|
||||
startFrameFormals[i].set(arg);
|
||||
}
|
||||
|
@ -1061,12 +1070,18 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC,
|
|||
// Push undefs onto the stack in anticipation of the popping of the
|
||||
// callee, thisv, and actual arguments passed from the caller's frame.
|
||||
if (isCall) {
|
||||
builder.writeValue(UndefinedValue(), "CallOp FillerCallee");
|
||||
builder.writeValue(UndefinedValue(), "CallOp FillerThis");
|
||||
for (uint32_t i = 0; i < numCallArgs; i++)
|
||||
builder.writeValue(UndefinedValue(), "CallOp FillerArg");
|
||||
if (pushedNewTarget)
|
||||
builder.writeValue(UndefinedValue(), "CallOp FillerNewTarget");
|
||||
if (!builder.writeValue(UndefinedValue(), "CallOp FillerCallee"))
|
||||
return false;
|
||||
if (!builder.writeValue(UndefinedValue(), "CallOp FillerThis"))
|
||||
return false;
|
||||
for (uint32_t i = 0; i < numCallArgs; i++) {
|
||||
if (!builder.writeValue(UndefinedValue(), "CallOp FillerArg"))
|
||||
return false;
|
||||
}
|
||||
if (pushedNewTarget) {
|
||||
if (!builder.writeValue(UndefinedValue(), "CallOp FillerNewTarget"))
|
||||
return false;
|
||||
}
|
||||
|
||||
frameSize += (numCallArgs + 2 + pushedNewTarget) * sizeof(Value);
|
||||
blFrame->setFrameSize(frameSize);
|
||||
|
@ -1276,7 +1291,8 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC,
|
|||
size_t calleeSlot = valueSlot - actualArgc - 1 - pushedNewTarget;
|
||||
|
||||
for (size_t i = valueSlot; i > calleeSlot; i--) {
|
||||
if (!builder.writeValue(*blFrame->valueSlot(i), "ArgVal"))
|
||||
Value v = *blFrame->valueSlot(i);
|
||||
if (!builder.writeValue(v, "ArgVal"))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1372,7 +1388,9 @@ InitFromBailout(JSContext* cx, HandleScript caller, jsbytecode* callerPC,
|
|||
if (pushedNewTarget) {
|
||||
size_t newTargetOffset = (builder.framePushed() - endOfBaselineStubArgs) +
|
||||
(actualArgc + 1) * sizeof(Value);
|
||||
builder.writeValue(*builder.valuePointerAtStackOffset(newTargetOffset), "CopiedNewTarget");
|
||||
Value newTargetValue = *builder.valuePointerAtStackOffset(newTargetOffset);
|
||||
if (!builder.writeValue(newTargetValue, "CopiedNewTarget"))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Push undefined for missing arguments.
|
||||
|
|
|
@ -162,7 +162,6 @@ MSG_DEF(JSMSG_USER_DEFINED_ERROR, 0, JSEXN_ERR, "JS_ReportError was called"
|
|||
|
||||
// Internal errors
|
||||
MSG_DEF(JSMSG_ALLOC_OVERFLOW, 0, JSEXN_INTERNALERR, "allocation size overflow")
|
||||
MSG_DEF(JSMSG_BAD_BUILD_ID, 0, JSEXN_INTERNALERR, "bad build ID for XDR script")
|
||||
MSG_DEF(JSMSG_BAD_BYTECODE, 1, JSEXN_INTERNALERR, "unimplemented JavaScript bytecode {0}")
|
||||
MSG_DEF(JSMSG_BUFFER_TOO_SMALL, 0, JSEXN_INTERNALERR, "buffer too small")
|
||||
MSG_DEF(JSMSG_BUILD_ID_NOT_AVAILABLE, 0, JSEXN_INTERNALERR, "build ID is not available")
|
||||
|
|
|
@ -68,7 +68,8 @@ BEGIN_TEST(testSharedImmutableStringsCache)
|
|||
for (auto i : mozilla::MakeRange(NUM_THREADS)) {
|
||||
auto cacheAndIndex = js_new<CacheAndIndex>(&cache, i);
|
||||
CHECK(cacheAndIndex);
|
||||
threads.infallibleEmplaceBack(getString, cacheAndIndex);
|
||||
threads.infallibleEmplaceBack();
|
||||
CHECK(threads.back().init(getString, cacheAndIndex));
|
||||
}
|
||||
|
||||
for (auto& thread : threads)
|
||||
|
|
|
@ -77,7 +77,8 @@ BEGIN_TEST(testExclusiveData)
|
|||
for (auto i : mozilla::MakeRange(NumThreads)) {
|
||||
auto counterAndBit = js_new<CounterAndBit>(i, counter);
|
||||
CHECK(counterAndBit);
|
||||
CHECK(threads.emplaceBack(setBitAndCheck, counterAndBit));
|
||||
CHECK(threads.emplaceBack());
|
||||
CHECK(threads.back().init(setBitAndCheck, counterAndBit));
|
||||
}
|
||||
|
||||
for (auto& thread : threads)
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
BEGIN_TEST(testThreadingThreadJoin)
|
||||
{
|
||||
bool flag = false;
|
||||
js::Thread thread([](bool* flagp){*flagp = true;}, &flag);
|
||||
js::Thread thread;
|
||||
CHECK(thread.init([](bool* flagp){*flagp = true;}, &flag));
|
||||
CHECK(thread.joinable());
|
||||
thread.join();
|
||||
CHECK(flag);
|
||||
|
@ -32,7 +33,8 @@ BEGIN_TEST(testThreadingThreadDetach)
|
|||
// We are going to detach this thread. Unlike join, we can't have it pointing at the stack
|
||||
// because it might do the write after we have returned and pushed a new frame.
|
||||
bool* flag = js_new<bool>(false);
|
||||
js::Thread thread([](bool* flag){*flag = true; js_delete(flag);}, mozilla::Move(flag));
|
||||
js::Thread thread;
|
||||
CHECK(thread.init([](bool* flag){*flag = true; js_delete(flag);}, mozilla::Move(flag)));
|
||||
CHECK(thread.joinable());
|
||||
thread.detach();
|
||||
CHECK(!thread.joinable());
|
||||
|
@ -43,7 +45,8 @@ END_TEST(testThreadingThreadDetach)
|
|||
|
||||
BEGIN_TEST(testThreadingThreadSetName)
|
||||
{
|
||||
js::Thread thread([](){js::ThisThread::SetName("JSAPI Test Thread");});
|
||||
js::Thread thread;
|
||||
CHECK(thread.init([](){js::ThisThread::SetName("JSAPI Test Thread");}));
|
||||
thread.detach();
|
||||
return true;
|
||||
}
|
||||
|
@ -53,7 +56,8 @@ BEGIN_TEST(testThreadingThreadId)
|
|||
{
|
||||
CHECK(js::Thread::Id() == js::Thread::Id());
|
||||
js::Thread::Id fromOther;
|
||||
js::Thread thread([](js::Thread::Id* idp){*idp = js::ThisThread::GetId();}, &fromOther);
|
||||
js::Thread thread;
|
||||
CHECK(thread.init([](js::Thread::Id* idp){*idp = js::ThisThread::GetId();}, &fromOther));
|
||||
js::Thread::Id fromMain = thread.get_id();
|
||||
thread.join();
|
||||
CHECK(fromOther == fromMain);
|
||||
|
@ -67,7 +71,8 @@ BEGIN_TEST(testThreadingThreadVectorMoveConstruct)
|
|||
mozilla::Atomic<int> count(0);
|
||||
mozilla::Vector<js::Thread, 0, js::SystemAllocPolicy> v;
|
||||
for (auto i : mozilla::MakeRange(N)) {
|
||||
CHECK(v.emplaceBack([](mozilla::Atomic<int>* countp){(*countp)++;}, &count));
|
||||
CHECK(v.emplaceBack());
|
||||
CHECK(v.back().init([](mozilla::Atomic<int>* countp){(*countp)++;}, &count));
|
||||
CHECK(v.length() == i + 1);
|
||||
}
|
||||
for (auto& th : v)
|
||||
|
@ -88,7 +93,8 @@ BEGIN_TEST(testThreadingThreadArgCopy)
|
|||
{
|
||||
for (size_t i = 0; i < 10000; ++i) {
|
||||
bool b = true;
|
||||
js::Thread thread([](bool bb){MOZ_RELEASE_ASSERT(bb);}, b);
|
||||
js::Thread thread;
|
||||
CHECK(thread.init([](bool bb){MOZ_RELEASE_ASSERT(bb);}, b));
|
||||
b = false;
|
||||
thread.join();
|
||||
}
|
||||
|
|
|
@ -26,13 +26,17 @@ FreezeThaw(JSContext* cx, JS::HandleScript script)
|
|||
|
||||
// freeze
|
||||
uint32_t nbytes;
|
||||
void* memory = JS_EncodeScript(cx, script, &nbytes);
|
||||
if (!memory)
|
||||
void* memory = nullptr;
|
||||
TranscodeResult rs = JS_EncodeScript(cx, script, &nbytes, &memory);
|
||||
if (rs != TranscodeResult_Ok)
|
||||
return nullptr;
|
||||
|
||||
// thaw
|
||||
JSScript* script2 = JS_DecodeScript(cx, memory, nbytes);
|
||||
JS::RootedScript script2(cx);
|
||||
rs = JS_DecodeScript(cx, memory, nbytes, &script2);
|
||||
js_free(memory);
|
||||
if (rs != TranscodeResult_Ok)
|
||||
return nullptr;
|
||||
return script2;
|
||||
}
|
||||
|
||||
|
|
|
@ -6592,44 +6592,50 @@ JS::detail::AssertArgumentsAreSane(JSContext* cx, HandleValue value)
|
|||
}
|
||||
#endif /* JS_DEBUG */
|
||||
|
||||
JS_PUBLIC_API(void*)
|
||||
JS_EncodeScript(JSContext* cx, HandleScript scriptArg, uint32_t* lengthp)
|
||||
JS_PUBLIC_API(TranscodeResult)
|
||||
JS_EncodeScript(JSContext* cx, HandleScript scriptArg,
|
||||
uint32_t* lengthp, void** buffer)
|
||||
{
|
||||
XDREncoder encoder(cx);
|
||||
RootedScript script(cx, scriptArg);
|
||||
if (!encoder.codeScript(&script))
|
||||
return nullptr;
|
||||
return encoder.forgetData(lengthp);
|
||||
*buffer = nullptr;
|
||||
if (encoder.codeScript(&script))
|
||||
*buffer = encoder.forgetData(lengthp);
|
||||
MOZ_ASSERT(bool(*buffer) == (encoder.resultCode() == TranscodeResult_Ok));
|
||||
return encoder.resultCode();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void*)
|
||||
JS_EncodeInterpretedFunction(JSContext* cx, HandleObject funobjArg, uint32_t* lengthp)
|
||||
JS_PUBLIC_API(TranscodeResult)
|
||||
JS_EncodeInterpretedFunction(JSContext* cx, HandleObject funobjArg,
|
||||
uint32_t* lengthp, void** buffer)
|
||||
{
|
||||
XDREncoder encoder(cx);
|
||||
RootedFunction funobj(cx, &funobjArg->as<JSFunction>());
|
||||
if (!encoder.codeFunction(&funobj))
|
||||
return nullptr;
|
||||
return encoder.forgetData(lengthp);
|
||||
*buffer = nullptr;
|
||||
if (encoder.codeFunction(&funobj))
|
||||
*buffer = encoder.forgetData(lengthp);
|
||||
MOZ_ASSERT(bool(*buffer) == (encoder.resultCode() == TranscodeResult_Ok));
|
||||
return encoder.resultCode();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSScript*)
|
||||
JS_DecodeScript(JSContext* cx, const void* data, uint32_t length)
|
||||
JS_PUBLIC_API(TranscodeResult)
|
||||
JS_DecodeScript(JSContext* cx, const void* data, uint32_t length,
|
||||
JS::MutableHandleScript scriptp)
|
||||
{
|
||||
XDRDecoder decoder(cx, data, length);
|
||||
RootedScript script(cx);
|
||||
if (!decoder.codeScript(&script))
|
||||
return nullptr;
|
||||
return script;
|
||||
decoder.codeScript(scriptp);
|
||||
MOZ_ASSERT(bool(scriptp) == (decoder.resultCode() == TranscodeResult_Ok));
|
||||
return decoder.resultCode();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSObject*)
|
||||
JS_DecodeInterpretedFunction(JSContext* cx, const void* data, uint32_t length)
|
||||
JS_PUBLIC_API(TranscodeResult)
|
||||
JS_DecodeInterpretedFunction(JSContext* cx, const void* data, uint32_t length,
|
||||
JS::MutableHandleFunction funp)
|
||||
{
|
||||
XDRDecoder decoder(cx, data, length);
|
||||
RootedFunction funobj(cx);
|
||||
if (!decoder.codeFunction(&funobj))
|
||||
return nullptr;
|
||||
return funobj;
|
||||
decoder.codeFunction(funp);
|
||||
MOZ_ASSERT(bool(funp) == (decoder.resultCode() == TranscodeResult_Ok));
|
||||
return decoder.resultCode();
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
|
|
|
@ -5836,17 +5836,38 @@ class MOZ_RAII AutoHideScriptedCaller
|
|||
* Encode/Decode interpreted scripts and functions to/from memory.
|
||||
*/
|
||||
|
||||
extern JS_PUBLIC_API(void*)
|
||||
JS_EncodeScript(JSContext* cx, JS::HandleScript script, uint32_t* lengthp);
|
||||
enum TranscodeResult
|
||||
{
|
||||
// Successful encoding / decoding.
|
||||
TranscodeResult_Ok = 0,
|
||||
|
||||
extern JS_PUBLIC_API(void*)
|
||||
JS_EncodeInterpretedFunction(JSContext* cx, JS::HandleObject funobj, uint32_t* lengthp);
|
||||
// A warning message, is set to the message out-param.
|
||||
TranscodeResult_Failure = 0x100,
|
||||
TranscodeResult_Failure_BadBuildId = TranscodeResult_Failure | 0x1,
|
||||
TranscodeResult_Failure_RunOnceNotSupported = TranscodeResult_Failure | 0x2,
|
||||
TranscodeResult_Failure_AsmJSNotSupported = TranscodeResult_Failure | 0x3,
|
||||
TranscodeResult_Failure_UnknownClassKind = TranscodeResult_Failure | 0x4,
|
||||
|
||||
extern JS_PUBLIC_API(JSScript*)
|
||||
JS_DecodeScript(JSContext* cx, const void* data, uint32_t length);
|
||||
// A error, the JSContext has a pending exception.
|
||||
TranscodeResult_Throw = 0x200
|
||||
};
|
||||
|
||||
extern JS_PUBLIC_API(TranscodeResult)
|
||||
JS_EncodeScript(JSContext* cx, JS::HandleScript script,
|
||||
uint32_t* lengthp, void** buffer);
|
||||
|
||||
extern JS_PUBLIC_API(TranscodeResult)
|
||||
JS_EncodeInterpretedFunction(JSContext* cx, JS::HandleObject funobj,
|
||||
uint32_t* lengthp, void** buffer);
|
||||
|
||||
extern JS_PUBLIC_API(TranscodeResult)
|
||||
JS_DecodeScript(JSContext* cx, const void* data, uint32_t length,
|
||||
JS::MutableHandleScript scriptp);
|
||||
|
||||
extern JS_PUBLIC_API(TranscodeResult)
|
||||
JS_DecodeInterpretedFunction(JSContext* cx, const void* data, uint32_t length,
|
||||
JS::MutableHandleFunction funp);
|
||||
|
||||
extern JS_PUBLIC_API(JSObject*)
|
||||
JS_DecodeInterpretedFunction(JSContext* cx, const void* data, uint32_t length);
|
||||
|
||||
namespace js {
|
||||
|
||||
|
|
|
@ -358,10 +358,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
|
|||
if (!comp->creationOptions().cloneSingletons() ||
|
||||
!comp->behaviors().getSingletonsAsTemplates())
|
||||
{
|
||||
JS_ReportErrorASCII(cx,
|
||||
"Can't serialize a run-once non-function script "
|
||||
"when we're not doing singleton cloning");
|
||||
return false;
|
||||
return xdr->fail(TranscodeResult_Failure_RunOnceNotSupported);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -795,8 +792,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
|
|||
funEnclosingScope = function->nonLazyScript()->enclosingScope();
|
||||
} else {
|
||||
MOZ_ASSERT(function->isAsmJSNative());
|
||||
JS_ReportErrorASCII(cx, "AsmJS modules are not yet supported in XDR serialization.");
|
||||
return false;
|
||||
return xdr->fail(TranscodeResult_Failure_AsmJSNotSupported);
|
||||
}
|
||||
|
||||
funEnclosingScopeIndex = FindScopeIndex(script, *funEnclosingScope);
|
||||
|
@ -831,7 +827,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
|
|||
|
||||
default: {
|
||||
MOZ_ASSERT(false, "Unknown class kind.");
|
||||
return false;
|
||||
return xdr->fail(TranscodeResult_Failure_UnknownClassKind);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1148,9 +1148,8 @@ CreateMappedArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
|
|||
if (!JS::ToUint32(cx, args[2], &size))
|
||||
return false;
|
||||
sizeGiven = true;
|
||||
if (offset > size) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE,
|
||||
"2");
|
||||
if (size == 0) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1168,7 +1167,7 @@ CreateMappedArrayBuffer(JSContext* cx, unsigned argc, Value* vp)
|
|||
JS_ReportErrorASCII(cx, "Unable to stat file");
|
||||
return false;
|
||||
}
|
||||
if (st.st_size < off_t(offset)) {
|
||||
if (off_t(offset) >= st.st_size) {
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_ARG_INDEX_OUT_OF_RANGE, "2");
|
||||
return false;
|
||||
|
@ -1511,6 +1510,42 @@ CacheEntry_setBytecode(JSContext* cx, HandleObject cache, uint8_t* buffer, uint3
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ConvertTranscodeResultToJSException(JSContext* cx, TranscodeResult rv)
|
||||
{
|
||||
switch (rv) {
|
||||
case TranscodeResult_Ok:
|
||||
return true;
|
||||
|
||||
default:
|
||||
MOZ_FALLTHROUGH;
|
||||
case TranscodeResult_Failure:
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
JS_ReportErrorASCII(cx, "generic warning");
|
||||
return false;
|
||||
case TranscodeResult_Failure_BadBuildId:
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
JS_ReportErrorASCII(cx, "the build-id does not match");
|
||||
return false;
|
||||
case TranscodeResult_Failure_RunOnceNotSupported:
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
JS_ReportErrorASCII(cx, "run-once script are not supported by XDR");
|
||||
return false;
|
||||
case TranscodeResult_Failure_AsmJSNotSupported:
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
JS_ReportErrorASCII(cx, "Asm.js is not supported by XDR");
|
||||
return false;
|
||||
case TranscodeResult_Failure_UnknownClassKind:
|
||||
MOZ_ASSERT(!cx->isExceptionPending());
|
||||
JS_ReportErrorASCII(cx, "Unknown class kind, go fix it.");
|
||||
return false;
|
||||
|
||||
case TranscodeResult_Throw:
|
||||
MOZ_ASSERT(cx->isExceptionPending());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
Evaluate(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
|
@ -1656,7 +1691,9 @@ Evaluate(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
|
||||
if (loadBytecode) {
|
||||
script = JS_DecodeScript(cx, loadBuffer, loadLength);
|
||||
TranscodeResult rv = JS_DecodeScript(cx, loadBuffer, loadLength, &script);
|
||||
if (!ConvertTranscodeResultToJSException(cx, rv))
|
||||
return false;
|
||||
} else {
|
||||
mozilla::Range<const char16_t> chars = codeChars.twoByteRange();
|
||||
(void) JS::Compile(cx, options, chars.start().get(), chars.length(), &script);
|
||||
|
@ -1705,8 +1742,9 @@ Evaluate(JSContext* cx, unsigned argc, Value* vp)
|
|||
}
|
||||
|
||||
if (saveBytecode) {
|
||||
saveBuffer = reinterpret_cast<uint8_t*>(JS_EncodeScript(cx, script, &saveLength));
|
||||
if (!saveBuffer)
|
||||
TranscodeResult rv = JS_EncodeScript(cx, script, &saveLength,
|
||||
reinterpret_cast<void**>(&saveBuffer.rwget()));
|
||||
if (!ConvertTranscodeResultToJSException(cx, rv))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -3533,7 +3571,10 @@ ScheduleWatchdog(JSContext* cx, double t)
|
|||
LockGuard<Mutex> guard(sc->watchdogLock);
|
||||
if (!sc->watchdogThread) {
|
||||
MOZ_ASSERT(!sc->watchdogTimeout);
|
||||
sc->watchdogThread.emplace(WatchdogMain, cx);
|
||||
sc->watchdogThread.emplace();
|
||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
||||
if (!sc->watchdogThread->init(WatchdogMain, cx))
|
||||
oomUnsafe.crash("watchdogThread.init");
|
||||
} else if (!sc->watchdogTimeout || timeout < sc->watchdogTimeout.value()) {
|
||||
sc->watchdogWakeup.notify_one();
|
||||
}
|
||||
|
|
|
@ -99,20 +99,12 @@ public:
|
|||
, options_(mozilla::Forward<O>(options))
|
||||
{ }
|
||||
|
||||
// Start a thread of execution at functor |f| with parameters |args|. Note
|
||||
// that the arguments must be either POD or rvalue references (mozilla::Move).
|
||||
// Attempting to pass a reference will result in the value being copied, which
|
||||
// may not be the intended behavior. See the comment below on
|
||||
// ThreadTrampoline::args for an explanation.
|
||||
template <typename F, typename... Args>
|
||||
explicit Thread(F&& f, Args&&... args) {
|
||||
MOZ_RELEASE_ASSERT(init(mozilla::Forward<F>(f),
|
||||
mozilla::Forward<Args>(args)...));
|
||||
}
|
||||
|
||||
// Start a thread of execution at functor |f| with parameters |args|. This
|
||||
// method will return false if thread creation fails. This Thread must not
|
||||
// already have been created.
|
||||
// already have been created. Note that the arguments must be either POD or
|
||||
// rvalue references (mozilla::Move). Attempting to pass a reference will
|
||||
// result in the value being copied, which may not be the intended behavior.
|
||||
// See the comment below on ThreadTrampoline::args for an explanation.
|
||||
template <typename F, typename... Args>
|
||||
MOZ_MUST_USE bool init(F&& f, Args&&... args) {
|
||||
MOZ_RELEASE_ASSERT(!joinable());
|
||||
|
|
|
@ -58,6 +58,16 @@ XDRBuffer::grow(size_t n)
|
|||
return true;
|
||||
}
|
||||
|
||||
template<XDRMode mode>
|
||||
void
|
||||
XDRState<mode>::postProcessContextErrors(JSContext* cx)
|
||||
{
|
||||
if (cx->isExceptionPending()) {
|
||||
MOZ_ASSERT(resultCode_ == TranscodeResult_Ok);
|
||||
resultCode_ = TranscodeResult_Throw;
|
||||
}
|
||||
}
|
||||
|
||||
template<XDRMode mode>
|
||||
bool
|
||||
XDRState<mode>::codeChars(const Latin1Char* chars, size_t nchars)
|
||||
|
@ -110,10 +120,8 @@ VersionCheck(XDRState<mode>* xdr)
|
|||
if (!xdr->codeUint32(&buildIdLength))
|
||||
return false;
|
||||
|
||||
if (mode == XDR_DECODE && buildIdLength != buildId.length()) {
|
||||
JS_ReportErrorNumberASCII(xdr->cx(), GetErrorMessage, nullptr, JSMSG_BAD_BUILD_ID);
|
||||
return false;
|
||||
}
|
||||
if (mode == XDR_DECODE && buildIdLength != buildId.length())
|
||||
return xdr->fail(TranscodeResult_Failure_BadBuildId);
|
||||
|
||||
if (mode == XDR_ENCODE) {
|
||||
if (!xdr->codeBytes(buildId.begin(), buildIdLength))
|
||||
|
@ -131,11 +139,9 @@ VersionCheck(XDRState<mode>* xdr)
|
|||
if (!xdr->codeBytes(decodedBuildId.begin(), buildIdLength))
|
||||
return false;
|
||||
|
||||
if (!PodEqual(decodedBuildId.begin(), buildId.begin(), buildIdLength)) {
|
||||
// We do not provide binary compatibility with older scripts.
|
||||
JS_ReportErrorNumberASCII(xdr->cx(), GetErrorMessage, nullptr, JSMSG_BAD_BUILD_ID);
|
||||
return false;
|
||||
}
|
||||
// We do not provide binary compatibility with older scripts.
|
||||
if (!PodEqual(decodedBuildId.begin(), buildId.begin(), buildIdLength))
|
||||
return xdr->fail(TranscodeResult_Failure_BadBuildId);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -143,18 +149,26 @@ VersionCheck(XDRState<mode>* xdr)
|
|||
|
||||
template<XDRMode mode>
|
||||
bool
|
||||
XDRState<mode>::codeFunction(MutableHandleFunction objp)
|
||||
XDRState<mode>::codeFunction(MutableHandleFunction funp)
|
||||
{
|
||||
if (mode == XDR_DECODE)
|
||||
objp.set(nullptr);
|
||||
funp.set(nullptr);
|
||||
else
|
||||
MOZ_ASSERT(objp->nonLazyScript()->enclosingScope()->is<GlobalScope>());
|
||||
MOZ_ASSERT(funp->nonLazyScript()->enclosingScope()->is<GlobalScope>());
|
||||
|
||||
if (!VersionCheck(this))
|
||||
if (!VersionCheck(this)) {
|
||||
postProcessContextErrors(cx());
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedScope scope(cx(), &cx()->global()->emptyGlobalScope());
|
||||
return XDRInterpretedFunction(this, scope, nullptr, objp);
|
||||
if (!XDRInterpretedFunction(this, scope, nullptr, funp)) {
|
||||
postProcessContextErrors(cx());
|
||||
funp.set(nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<XDRMode mode>
|
||||
|
@ -166,10 +180,18 @@ XDRState<mode>::codeScript(MutableHandleScript scriptp)
|
|||
else
|
||||
MOZ_ASSERT(!scriptp->enclosingScope());
|
||||
|
||||
if (!VersionCheck(this))
|
||||
if (!VersionCheck(this)) {
|
||||
postProcessContextErrors(cx());
|
||||
return false;
|
||||
}
|
||||
|
||||
return XDRScript(this, nullptr, nullptr, nullptr, scriptp);
|
||||
if (!XDRScript(this, nullptr, nullptr, nullptr, scriptp)) {
|
||||
postProcessContextErrors(cx());
|
||||
scriptp.set(nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<XDRMode mode>
|
||||
|
|
|
@ -79,16 +79,28 @@ template <XDRMode mode>
|
|||
class XDRState {
|
||||
public:
|
||||
XDRBuffer buf;
|
||||
TranscodeResult resultCode_;
|
||||
|
||||
protected:
|
||||
explicit XDRState(JSContext* cx)
|
||||
: buf(cx) { }
|
||||
: buf(cx), resultCode_(TranscodeResult_Ok) { }
|
||||
|
||||
public:
|
||||
JSContext* cx() const {
|
||||
return buf.cx();
|
||||
}
|
||||
|
||||
// Record logical failures of XDR.
|
||||
void postProcessContextErrors(JSContext* cx);
|
||||
TranscodeResult resultCode() const {
|
||||
return resultCode_;
|
||||
}
|
||||
bool fail(TranscodeResult code) {
|
||||
MOZ_ASSERT(resultCode_ == TranscodeResult_Ok);
|
||||
resultCode_ = code;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool codeUint8(uint8_t* n) {
|
||||
if (mode == XDR_ENCODE) {
|
||||
uint8_t* ptr = buf.write(sizeof *n);
|
||||
|
|
|
@ -728,16 +728,26 @@ mozJSComponentLoader::ObjectForLocation(ComponentLoaderInfo& aInfo,
|
|||
// The script wasn't in the cache , so compile it now.
|
||||
LOG(("Slow loading %s\n", nativePath.get()));
|
||||
|
||||
// Note - if mReuseLoaderGlobal is true, then we can't do lazy source,
|
||||
// because we compile things as functions (rather than script), and lazy
|
||||
// source isn't supported in that configuration. That's ok though,
|
||||
// because we only do mReuseLoaderGlobal on b2g, where we invoke
|
||||
// setDiscardSource(true) on the entire global.
|
||||
// Use lazy source if both of these conditions hold:
|
||||
//
|
||||
// (1) mReuseLoaderGlobal is false. If mReuseLoaderGlobal is true, we
|
||||
// can't do lazy source because we compile things as functions
|
||||
// (rather than script), and lazy source isn't supported in that
|
||||
// configuration. That's ok though, because we only do
|
||||
// mReuseLoaderGlobal on b2g, where we invoke setDiscardSource(true)
|
||||
// on the entire global.
|
||||
//
|
||||
// (2) We're using the startup cache. Non-lazy source + startup cache
|
||||
// regresses installer size (due to source code stored in XDR
|
||||
// encoded modules in omni.ja). Also, XDR decoding is relatively
|
||||
// fast. Content processes don't use the startup cache, so we want
|
||||
// them to use non-lazy source code to enable lazy parsing.
|
||||
// See bug 1303754.
|
||||
CompileOptions options(cx);
|
||||
options.setNoScriptRval(mReuseLoaderGlobal ? false : true)
|
||||
.setVersion(JSVERSION_LATEST)
|
||||
.setFileAndLine(nativePath.get(), 1)
|
||||
.setSourceIsLazy(!mReuseLoaderGlobal);
|
||||
.setSourceIsLazy(!mReuseLoaderGlobal && !!cache);
|
||||
|
||||
if (realFile) {
|
||||
#ifdef HAVE_PR_MEMMAP
|
||||
|
|
|
@ -29,31 +29,24 @@ ReadCachedScript(StartupCache* cache, nsACString& uri, JSContext* cx,
|
|||
if (NS_FAILED(rv))
|
||||
return rv; // don't warn since NOT_AVAILABLE is an ok error
|
||||
|
||||
scriptp.set(JS_DecodeScript(cx, buf.get(), len));
|
||||
if (!scriptp)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
return NS_OK;
|
||||
TranscodeResult code = JS_DecodeScript(cx, buf.get(), len, scriptp);
|
||||
if (code == TranscodeResult_Ok)
|
||||
return NS_OK;
|
||||
|
||||
if ((code & TranscodeResult_Failure) != 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
MOZ_ASSERT((code & TranscodeResult_Throw) != 0);
|
||||
JS_ClearPendingException(cx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ReadCachedFunction(StartupCache* cache, nsACString& uri, JSContext* cx,
|
||||
nsIPrincipal* systemPrincipal, JSFunction** functionp)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
/* This doesn't actually work ...
|
||||
nsAutoArrayPtr<char> buf;
|
||||
uint32_t len;
|
||||
nsresult rv = cache->GetBuffer(PromiseFlatCString(uri).get(),
|
||||
getter_Transfers(buf), &len);
|
||||
if (NS_FAILED(rv))
|
||||
return rv; // don't warn since NOT_AVAILABLE is an ok error
|
||||
|
||||
JSObject* obj = JS_DecodeInterpretedFunction(cx, buf, len, nsJSPrincipals::get(systemPrincipal), nullptr);
|
||||
if (!obj)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
JSFunction* function = JS_ValueToFunction(cx, OBJECT_TO_JSVAL(obj));
|
||||
*functionp = function;
|
||||
return NS_OK;*/
|
||||
// This doesn't actually work ...
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -63,14 +56,17 @@ WriteCachedScript(StartupCache* cache, nsACString& uri, JSContext* cx,
|
|||
MOZ_ASSERT(JS_GetScriptPrincipals(script) == nsJSPrincipals::get(systemPrincipal));
|
||||
|
||||
uint32_t size;
|
||||
void* data = JS_EncodeScript(cx, script, &size);
|
||||
if (!data) {
|
||||
// JS_EncodeScript may have set a pending exception.
|
||||
void* data = nullptr;
|
||||
TranscodeResult code = JS_EncodeScript(cx, script, &size, &data);
|
||||
if (code != TranscodeResult_Ok) {
|
||||
if ((code & TranscodeResult_Failure) != 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
MOZ_ASSERT((code & TranscodeResult_Throw) != 0);
|
||||
JS_ClearPendingException(cx);
|
||||
return NS_ERROR_FAILURE;
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(size);
|
||||
MOZ_ASSERT(size && data);
|
||||
nsresult rv = cache->PutBuffer(PromiseFlatCString(uri).get(), static_cast<char*>(data), size);
|
||||
js_free(data);
|
||||
return rv;
|
||||
|
@ -80,19 +76,6 @@ nsresult
|
|||
WriteCachedFunction(StartupCache* cache, nsACString& uri, JSContext* cx,
|
||||
nsIPrincipal* systemPrincipal, JSFunction* function)
|
||||
{
|
||||
return NS_ERROR_FAILURE;
|
||||
/* This doesn't actually work ...
|
||||
uint32_t size;
|
||||
void* data =
|
||||
JS_EncodeInterpretedFunction(cx, JS_GetFunctionObject(function), &size);
|
||||
if (!data) {
|
||||
// JS_EncodeInterpretedFunction may have set a pending exception.
|
||||
JS_ClearPendingException(cx);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(size);
|
||||
nsresult rv = cache->PutBuffer(PromiseFlatCString(uri).get(), static_cast<char*>(data), size);
|
||||
js_free(data);
|
||||
return rv;*/
|
||||
// This doesn't actually work ...
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
|
|
@ -1091,17 +1091,24 @@ WriteScriptOrFunction(nsIObjectOutputStream* stream, JSContext* cx,
|
|||
|
||||
|
||||
uint32_t size;
|
||||
void* data;
|
||||
void* data = nullptr;
|
||||
TranscodeResult code;
|
||||
{
|
||||
if (functionObj)
|
||||
data = JS_EncodeInterpretedFunction(cx, functionObj, &size);
|
||||
code = JS_EncodeInterpretedFunction(cx, functionObj, &size, &data);
|
||||
else
|
||||
data = JS_EncodeScript(cx, script, &size);
|
||||
code = JS_EncodeScript(cx, script, &size, &data);
|
||||
}
|
||||
|
||||
if (!data)
|
||||
if (code != TranscodeResult_Ok) {
|
||||
if ((code & TranscodeResult_Failure) != 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
MOZ_ASSERT((code & TranscodeResult_Throw) != 0);
|
||||
JS_ClearPendingException(cx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
MOZ_ASSERT(size);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(size && data);
|
||||
rv = stream->Write32(size);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = stream->WriteBytes(static_cast<char*>(data), size);
|
||||
|
@ -1139,18 +1146,25 @@ ReadScriptOrFunction(nsIObjectInputStream* stream, JSContext* cx,
|
|||
return rv;
|
||||
|
||||
{
|
||||
TranscodeResult code;
|
||||
if (scriptp) {
|
||||
JSScript* script = JS_DecodeScript(cx, data, size);
|
||||
if (!script)
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
else
|
||||
*scriptp = script;
|
||||
Rooted<JSScript*> script(cx);
|
||||
code = JS_DecodeScript(cx, data, size, &script);
|
||||
if (code == TranscodeResult_Ok)
|
||||
*scriptp = script.get();
|
||||
} else {
|
||||
JSObject* funobj = JS_DecodeInterpretedFunction(cx, data, size);
|
||||
if (!funobj)
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
else
|
||||
*functionObjp = funobj;
|
||||
Rooted<JSFunction*> funobj(cx);
|
||||
code = JS_DecodeInterpretedFunction(cx, data, size, &funobj);
|
||||
if (code == TranscodeResult_Ok)
|
||||
*functionObjp = JS_GetFunctionObject(funobj.get());
|
||||
}
|
||||
|
||||
if (code != TranscodeResult_Ok) {
|
||||
if ((code & TranscodeResult_Failure) != 0)
|
||||
return NS_ERROR_FAILURE;
|
||||
MOZ_ASSERT((code & TranscodeResult_Throw) != 0);
|
||||
JS_ClearPendingException(cx);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,8 +61,10 @@
|
|||
#include "mozilla/OperatorNewExtensions.h"
|
||||
#include "mozilla/PendingAnimationTracker.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "ActiveLayerTracker.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsPrintfCString.h"
|
||||
|
@ -1811,9 +1813,14 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
|
|||
|
||||
ContainerLayerParameters containerParameters
|
||||
(presShell->GetResolution(), presShell->GetResolution());
|
||||
RefPtr<ContainerLayer> root = layerBuilder->
|
||||
BuildContainerLayerFor(aBuilder, layerManager, frame, nullptr, this,
|
||||
containerParameters, nullptr);
|
||||
|
||||
RefPtr<ContainerLayer> root;
|
||||
{
|
||||
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Layerization);
|
||||
root = layerBuilder->
|
||||
BuildContainerLayerFor(aBuilder, layerManager, frame, nullptr, this,
|
||||
containerParameters, nullptr);
|
||||
}
|
||||
|
||||
nsIDocument* document = presShell->GetDocument();
|
||||
|
||||
|
@ -7105,3 +7112,106 @@ nsDisplayFilter::PrintEffects(nsACString& aTo)
|
|||
aTo += ")";
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
uint32_t PaintTelemetry::sPaintLevel = 0;
|
||||
uint32_t PaintTelemetry::sMetricLevel = 0;
|
||||
EnumeratedArray<PaintTelemetry::Metric,
|
||||
PaintTelemetry::Metric::COUNT,
|
||||
double> PaintTelemetry::sMetrics;
|
||||
|
||||
PaintTelemetry::AutoRecordPaint::AutoRecordPaint()
|
||||
{
|
||||
// Don't record nested paints.
|
||||
if (sPaintLevel++ > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset metrics for a new paint.
|
||||
for (auto& metric : sMetrics) {
|
||||
metric = 0.0;
|
||||
}
|
||||
mStart = TimeStamp::Now();
|
||||
}
|
||||
|
||||
PaintTelemetry::AutoRecordPaint::~AutoRecordPaint()
|
||||
{
|
||||
MOZ_ASSERT(sPaintLevel != 0);
|
||||
if (--sPaintLevel > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we're in multi-process mode, don't include paint times for the parent
|
||||
// process.
|
||||
if (gfxVars::BrowserTabsRemoteAutostart() && XRE_IsParentProcess()) {
|
||||
return;
|
||||
}
|
||||
|
||||
double totalMs = (TimeStamp::Now() - mStart).ToMilliseconds();
|
||||
|
||||
// Record the total time.
|
||||
Telemetry::Accumulate(Telemetry::CONTENT_PAINT_TIME, static_cast<uint32_t>(totalMs));
|
||||
|
||||
// If the total time was >= 16ms, then it's likely we missed a frame due to
|
||||
// painting. In this case we'll gather some detailed metrics below.
|
||||
if (totalMs <= 16.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto record = [=](const char* aKey, double aDurationMs) -> void {
|
||||
MOZ_ASSERT(aDurationMs <= totalMs);
|
||||
|
||||
uint32_t amount = static_cast<int32_t>((aDurationMs / totalMs) * 100.0);
|
||||
|
||||
nsDependentCString key(aKey);
|
||||
Telemetry::Accumulate(Telemetry::CONTENT_LARGE_PAINT_PHASE_WEIGHT, key, amount);
|
||||
};
|
||||
|
||||
double dlMs = sMetrics[Metric::DisplayList];
|
||||
double flbMs = sMetrics[Metric::Layerization];
|
||||
double rMs = sMetrics[Metric::Rasterization];
|
||||
|
||||
// Record all permutations since aggregation makes it difficult to
|
||||
// correlate. For example we can't derive "flb+r" from "dl" because we
|
||||
// don't know the total time associated with a bucket entry. So we just
|
||||
// play it safe and include everything. We can however derive "other" time
|
||||
// from the final permutation.
|
||||
record("dl", dlMs);
|
||||
record("flb", flbMs);
|
||||
record("r", rMs);
|
||||
record("dl,flb", dlMs + flbMs);
|
||||
record("dl,r", dlMs + rMs);
|
||||
record("flb,r", flbMs + rMs);
|
||||
record("dl,flb,r", dlMs + flbMs + rMs);
|
||||
}
|
||||
|
||||
PaintTelemetry::AutoRecord::AutoRecord(Metric aMetric)
|
||||
: mMetric(aMetric)
|
||||
{
|
||||
// Don't double-record anything nested.
|
||||
if (sMetricLevel++ > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't record inside nested paints, or outside of paints.
|
||||
if (sPaintLevel != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
mStart = TimeStamp::Now();
|
||||
}
|
||||
|
||||
PaintTelemetry::AutoRecord::~AutoRecord()
|
||||
{
|
||||
MOZ_ASSERT(sMetricLevel != 0);
|
||||
|
||||
sMetricLevel--;
|
||||
if (mStart.IsNull()) {
|
||||
return;
|
||||
}
|
||||
|
||||
sMetrics[mMetric] += (TimeStamp::Now() - mStart).ToMilliseconds();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -28,8 +28,10 @@
|
|||
#include "DisplayListClipState.h"
|
||||
#include "LayerState.h"
|
||||
#include "FrameMetrics.h"
|
||||
#include "mozilla/EnumeratedArray.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/gfx/UserData.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
@ -4471,4 +4473,43 @@ public:
|
|||
mutable mozilla::Maybe<bool> mIsFrameSelected;
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class PaintTelemetry
|
||||
{
|
||||
public:
|
||||
enum class Metric {
|
||||
DisplayList,
|
||||
Layerization,
|
||||
Rasterization,
|
||||
COUNT,
|
||||
};
|
||||
|
||||
class AutoRecord
|
||||
{
|
||||
public:
|
||||
explicit AutoRecord(Metric aMetric);
|
||||
~AutoRecord();
|
||||
private:
|
||||
Metric mMetric;
|
||||
mozilla::TimeStamp mStart;
|
||||
};
|
||||
|
||||
class AutoRecordPaint
|
||||
{
|
||||
public:
|
||||
AutoRecordPaint();
|
||||
~AutoRecordPaint();
|
||||
private:
|
||||
mozilla::TimeStamp mStart;
|
||||
};
|
||||
|
||||
private:
|
||||
static uint32_t sPaintLevel;
|
||||
static uint32_t sMetricLevel;
|
||||
static mozilla::EnumeratedArray<Metric, Metric::COUNT, double> sMetrics;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /*NSDISPLAYLIST_H_*/
|
||||
|
|
|
@ -3522,6 +3522,8 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
|
|||
PROFILER_LABEL("nsLayoutUtils", "PaintFrame::BuildDisplayList",
|
||||
js::ProfileEntry::Category::GRAPHICS);
|
||||
|
||||
|
||||
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::DisplayList);
|
||||
aFrame->BuildDisplayListForStackingContext(&builder, dirtyRect, &list);
|
||||
}
|
||||
|
||||
|
@ -3634,8 +3636,8 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
|
|||
}
|
||||
|
||||
TimeStamp paintStart = TimeStamp::Now();
|
||||
RefPtr<LayerManager> layerManager =
|
||||
list.PaintRoot(&builder, aRenderingContext, flags);
|
||||
RefPtr<LayerManager> layerManager
|
||||
= list.PaintRoot(&builder, aRenderingContext, flags);
|
||||
Telemetry::AccumulateTimeDelta(Telemetry::PAINT_RASTERIZE_TIME,
|
||||
paintStart);
|
||||
|
||||
|
|
|
@ -987,7 +987,7 @@ nsPresContext::DetachShell()
|
|||
mRestyleManager->Disconnect();
|
||||
mRestyleManager = nullptr;
|
||||
}
|
||||
if (mRefreshDriver && mRefreshDriver->PresContext() == this) {
|
||||
if (mRefreshDriver && mRefreshDriver->GetPresContext() == this) {
|
||||
mRefreshDriver->Disconnect();
|
||||
// Can't null out the refresh driver here.
|
||||
}
|
||||
|
|
|
@ -134,7 +134,8 @@ class nsRootPresContext;
|
|||
// An interface for presentation contexts. Presentation contexts are
|
||||
// objects that provide an outer context for a presentation shell.
|
||||
|
||||
class nsPresContext : public nsIObserver {
|
||||
class nsPresContext : public nsIObserver,
|
||||
public mozilla::SupportsWeakPtr<nsPresContext> {
|
||||
public:
|
||||
typedef mozilla::FramePropertyTable FramePropertyTable;
|
||||
typedef mozilla::LangGroupFontPrefs LangGroupFontPrefs;
|
||||
|
@ -145,6 +146,7 @@ public:
|
|||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(nsPresContext)
|
||||
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsPresContext)
|
||||
|
||||
enum nsPresContextType {
|
||||
eContext_Galley, // unpaginated screen presentation
|
||||
|
|
|
@ -1295,7 +1295,7 @@ PresShell::Destroy()
|
|||
mHiddenInvalidationObserverRefreshDriver->RemovePresShellToInvalidateIfHidden(this);
|
||||
}
|
||||
|
||||
if (rd->PresContext() == GetPresContext()) {
|
||||
if (rd->GetPresContext() == GetPresContext()) {
|
||||
rd->RevokeViewManagerFlush();
|
||||
}
|
||||
|
||||
|
@ -8997,7 +8997,7 @@ PresShell::Freeze()
|
|||
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
if (presContext &&
|
||||
presContext->RefreshDriver()->PresContext() == presContext) {
|
||||
presContext->RefreshDriver()->GetPresContext() == presContext) {
|
||||
presContext->RefreshDriver()->Freeze();
|
||||
}
|
||||
|
||||
|
@ -9055,7 +9055,7 @@ PresShell::Thaw()
|
|||
{
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
if (presContext &&
|
||||
presContext->RefreshDriver()->PresContext() == presContext) {
|
||||
presContext->RefreshDriver()->GetPresContext() == presContext) {
|
||||
presContext->RefreshDriver()->Thaw();
|
||||
}
|
||||
|
||||
|
@ -10911,7 +10911,7 @@ PresShell::SetIsActive(bool aIsActive)
|
|||
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
if (presContext &&
|
||||
presContext->RefreshDriver()->PresContext() == presContext) {
|
||||
presContext->RefreshDriver()->GetPresContext() == presContext) {
|
||||
presContext->RefreshDriver()->SetThrottled(!mIsActive);
|
||||
}
|
||||
|
||||
|
@ -11142,7 +11142,7 @@ nsIPresShell::FontSizeInflationEnabled()
|
|||
void
|
||||
PresShell::PausePainting()
|
||||
{
|
||||
if (GetPresContext()->RefreshDriver()->PresContext() != GetPresContext())
|
||||
if (GetPresContext()->RefreshDriver()->GetPresContext() != GetPresContext())
|
||||
return;
|
||||
|
||||
mPaintingIsFrozen = true;
|
||||
|
@ -11152,7 +11152,7 @@ PresShell::PausePainting()
|
|||
void
|
||||
PresShell::ResumePainting()
|
||||
{
|
||||
if (GetPresContext()->RefreshDriver()->PresContext() != GetPresContext())
|
||||
if (GetPresContext()->RefreshDriver()->GetPresContext() != GetPresContext())
|
||||
return;
|
||||
|
||||
mPaintingIsFrozen = false;
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#include "mozilla/TimelineConsumers.h"
|
||||
#include "nsAnimationManager.h"
|
||||
#include "nsIDOMEvent.h"
|
||||
#include "nsDisplayList.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::widget;
|
||||
|
@ -172,7 +173,8 @@ public:
|
|||
NS_ASSERTION(mRootRefreshDrivers.Contains(aDriver), "RemoveRefreshDriver for a refresh driver that's not in the root refresh list!");
|
||||
mRootRefreshDrivers.RemoveElement(aDriver);
|
||||
} else {
|
||||
nsPresContext* rootContext = aDriver->PresContext()->GetRootPresContext();
|
||||
nsPresContext* pc = aDriver->GetPresContext();
|
||||
nsPresContext* rootContext = pc ? pc->GetRootPresContext() : nullptr;
|
||||
// During PresContext shutdown, we can't accurately detect
|
||||
// if a root refresh driver exists or not. Therefore, we have to
|
||||
// search and find out which list this driver exists in.
|
||||
|
@ -226,7 +228,8 @@ protected:
|
|||
|
||||
bool IsRootRefreshDriver(nsRefreshDriver* aDriver)
|
||||
{
|
||||
nsPresContext* rootContext = aDriver->PresContext()->GetRootPresContext();
|
||||
nsPresContext* pc = aDriver->GetPresContext();
|
||||
nsPresContext* rootContext = pc ? pc->GetRootPresContext() : nullptr;
|
||||
if (!rootContext) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1908,7 +1911,10 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
|||
|
||||
mViewManagerFlushIsPending = false;
|
||||
RefPtr<nsViewManager> vm = mPresContext->GetPresShell()->GetViewManager();
|
||||
vm->ProcessPendingUpdates();
|
||||
{
|
||||
PaintTelemetry::AutoRecordPaint record;
|
||||
vm->ProcessPendingUpdates();
|
||||
}
|
||||
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
|
||||
|
@ -2096,7 +2102,8 @@ nsRefreshDriver::IsWaitingForPaint(mozilla::TimeStamp aTime)
|
|||
|
||||
// Try find the 'root' refresh driver for the current window and check
|
||||
// if that is waiting for a paint.
|
||||
nsPresContext *rootContext = PresContext()->GetRootPresContext();
|
||||
nsPresContext* pc = GetPresContext();
|
||||
nsPresContext* rootContext = pc ? pc->GetRootPresContext() : nullptr;
|
||||
if (rootContext) {
|
||||
nsRefreshDriver *rootRefresh = rootContext->RefreshDriver();
|
||||
if (rootRefresh && rootRefresh != this) {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Vector.h"
|
||||
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "mozFlushType.h"
|
||||
#include "nsTObserverArray.h"
|
||||
#include "nsTArray.h"
|
||||
|
@ -273,7 +273,7 @@ public:
|
|||
/**
|
||||
* Return the prescontext we were initialized with
|
||||
*/
|
||||
nsPresContext* PresContext() const { return mPresContext; }
|
||||
nsPresContext* GetPresContext() const { return mPresContext; }
|
||||
|
||||
/**
|
||||
* PBackgroundChild actor is created asynchronously in content process.
|
||||
|
@ -381,8 +381,8 @@ private:
|
|||
ProfilerBacktrace* mReflowCause;
|
||||
ProfilerBacktrace* mStyleCause;
|
||||
|
||||
nsPresContext *mPresContext; // weak; pres context passed in constructor
|
||||
// and unset in Disconnect
|
||||
// nsPresContext passed in constructor and unset in Disconnect.
|
||||
mozilla::WeakPtr<nsPresContext> mPresContext;
|
||||
|
||||
RefPtr<nsRefreshDriver> mRootRefresh;
|
||||
|
||||
|
|
|
@ -426,10 +426,13 @@ public:
|
|||
SetInitialChildList(ChildListID aListID,
|
||||
nsFrameList& aChildList) override
|
||||
{
|
||||
NS_ASSERTION(aListID == kPrincipalList, "unexpected frame list");
|
||||
MOZ_ASSERT(aListID == kPrincipalList || aListID == kBackdropList,
|
||||
"unexpected frame list");
|
||||
nsBlockFrame::SetInitialChildList(aListID, aChildList);
|
||||
// re-resolve our subtree to set any mathml-expected data
|
||||
nsMathMLContainerFrame::RebuildAutomaticDataForChildren(this);
|
||||
if (aListID == kPrincipalList) {
|
||||
// re-resolve our subtree to set any mathml-expected data
|
||||
nsMathMLContainerFrame::RebuildAutomaticDataForChildren(this);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void
|
||||
|
|
|
@ -1154,5 +1154,10 @@ function SendUpdateCanvasForEvent(event, contentRootElement)
|
|||
#if REFTEST_B2G
|
||||
OnInitialLoad();
|
||||
#else
|
||||
addEventListener("load", OnInitialLoad, true);
|
||||
if (content.document.readyState == "complete") {
|
||||
// load event has already fired for content, get started
|
||||
OnInitialLoad();
|
||||
} else {
|
||||
addEventListener("load", OnInitialLoad, true);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -107,7 +107,6 @@ user_pref("browser.tabs.remote.autostart.2", false);
|
|||
user_pref("startup.homepage_welcome_url", "");
|
||||
user_pref("startup.homepage_welcome_url.additional", "");
|
||||
user_pref("startup.homepage_override_url", "");
|
||||
user_pref("browser.usedOnWindows10.introURL", "");
|
||||
|
||||
user_pref("media.gmp-manager.url.override", "http://localhost/dummy-gmp-manager.xml");
|
||||
user_pref("media.gmp-manager.updateEnabled", false);
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "nsIContent.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsSerializationHelper.h"
|
||||
|
||||
#include "mozilla/BasicEvents.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
|
@ -226,6 +227,29 @@ nsImageBoxFrame::UpdateImage()
|
|||
if (mUseSrcAttr) {
|
||||
nsIDocument* doc = mContent->GetComposedDoc();
|
||||
if (doc) {
|
||||
// Use the serialized loadingPrincipal from the image element. Fall back
|
||||
// to mContent's principal (SystemPrincipal) if not available.
|
||||
nsContentPolicyType contentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE;
|
||||
nsCOMPtr<nsIPrincipal> loadingPrincipal = mContent->NodePrincipal();
|
||||
nsAutoString imageLoadingPrincipal;
|
||||
mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::loadingprincipal,
|
||||
imageLoadingPrincipal);
|
||||
if (!imageLoadingPrincipal.IsEmpty()) {
|
||||
nsCOMPtr<nsISupports> serializedPrincipal;
|
||||
NS_DeserializeObject(NS_ConvertUTF16toUTF8(imageLoadingPrincipal),
|
||||
getter_AddRefs(serializedPrincipal));
|
||||
loadingPrincipal = do_QueryInterface(serializedPrincipal);
|
||||
|
||||
if (loadingPrincipal) {
|
||||
// Set the content policy type to TYPE_INTERNAL_IMAGE_FAVICON for
|
||||
// indicating it's a favicon loading.
|
||||
contentPolicyType = nsIContentPolicy::TYPE_INTERNAL_IMAGE_FAVICON;
|
||||
} else {
|
||||
// Fallback if the deserialization is failed.
|
||||
loadingPrincipal = mContent->NodePrincipal();
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> baseURI = mContent->GetBaseURI();
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri),
|
||||
|
@ -233,10 +257,11 @@ nsImageBoxFrame::UpdateImage()
|
|||
doc,
|
||||
baseURI);
|
||||
if (uri) {
|
||||
nsresult rv = nsContentUtils::LoadImage(uri, mContent, doc, mContent->NodePrincipal(),
|
||||
nsresult rv = nsContentUtils::LoadImage(uri, mContent, doc, loadingPrincipal,
|
||||
doc->GetDocumentURI(), doc->GetReferrerPolicy(),
|
||||
mListener, mLoadFlags,
|
||||
EmptyString(), getter_AddRefs(mImageRequest));
|
||||
EmptyString(), getter_AddRefs(mImageRequest),
|
||||
contentPolicyType);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && mImageRequest) {
|
||||
nsLayoutUtils::RegisterImageRequestIfAnimated(presContext,
|
||||
|
|
|
@ -408,8 +408,13 @@ nsMenuFrame::HandleEvent(nsPresContext* aPresContext,
|
|||
// On mac, open menulist on either up/down arrow or space (w/o Cmd pressed)
|
||||
if (!IsOpen() && ((keyEvent->mCharCode == ' ' && !keyEvent->IsMeta()) ||
|
||||
(keyCode == NS_VK_UP || keyCode == NS_VK_DOWN))) {
|
||||
*aEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||
OpenMenu(false);
|
||||
|
||||
// When pressing space, don't open the menu if performing an incremental search.
|
||||
if (keyEvent->mCharCode != ' ' ||
|
||||
!nsMenuPopupFrame::IsWithinIncrementalTime(keyEvent->mTime)) {
|
||||
*aEventStatus = nsEventStatus_eConsumeNoDefault;
|
||||
OpenMenu(false);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// On other platforms, toggle menulist on unmodified F4 or Alt arrow
|
||||
|
|
|
@ -61,6 +61,8 @@ using mozilla::dom::PopupBoxObject;
|
|||
|
||||
int8_t nsMenuPopupFrame::sDefaultLevelIsTop = -1;
|
||||
|
||||
DOMTimeStamp nsMenuPopupFrame::sLastKeyTime = 0;
|
||||
|
||||
// XXX, kyle.yuan@sun.com, there are 4 definitions for the same purpose:
|
||||
// nsMenuPopupFrame.h, nsListControlFrame.cpp, listbox.xml, tree.xml
|
||||
// need to find a good place to put them together.
|
||||
|
@ -534,6 +536,11 @@ nsMenuPopupFrame::LayoutPopup(nsBoxLayoutState& aState, nsIFrame* aParentMenu,
|
|||
if (mIsOpenChanged) {
|
||||
mIsOpenChanged = false;
|
||||
|
||||
// Make sure the current selection in a menulist is visible.
|
||||
if (IsMenuList() && mCurrentMenu) {
|
||||
EnsureMenuItemIsVisible(mCurrentMenu);
|
||||
}
|
||||
|
||||
#ifndef MOZ_WIDGET_GTK
|
||||
// If the animate attribute is set to open, check for a transition and wait
|
||||
// for it to finish before firing the popupshown event.
|
||||
|
@ -2002,7 +2009,6 @@ nsMenuPopupFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent, bool& doAction
|
|||
bool isMenu = parentContent &&
|
||||
!parentContent->NodeInfo()->Equals(nsGkAtoms::menulist, kNameSpaceID_XUL);
|
||||
|
||||
static DOMTimeStamp lastKeyTime = 0;
|
||||
DOMTimeStamp keyTime;
|
||||
aKeyEvent->AsEvent()->GetTimeStamp(&keyTime);
|
||||
|
||||
|
@ -2027,12 +2033,11 @@ nsMenuPopupFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent, bool& doAction
|
|||
if (isMenu) {
|
||||
// Menu supports only first-letter navigation
|
||||
mIncrementalString = uniChar;
|
||||
} else if (sTimeoutOfIncrementalSearch &&
|
||||
keyTime - lastKeyTime > sTimeoutOfIncrementalSearch) {
|
||||
} else if (IsWithinIncrementalTime(keyTime)) {
|
||||
mIncrementalString.Append(uniChar);
|
||||
} else {
|
||||
// Interval too long, treat as new typing
|
||||
mIncrementalString = uniChar;
|
||||
} else {
|
||||
mIncrementalString.Append(uniChar);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2047,7 +2052,7 @@ nsMenuPopupFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent, bool& doAction
|
|||
stringLength = 1;
|
||||
}
|
||||
|
||||
lastKeyTime = keyTime;
|
||||
sLastKeyTime = keyTime;
|
||||
|
||||
// NOTE: If you crashed here due to a bogus |immediateParent| it is
|
||||
// possible that the menu whose shortcut is being looked up has
|
||||
|
|
|
@ -332,6 +332,9 @@ public:
|
|||
nsMenuFrame* FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent, bool& doAction);
|
||||
|
||||
void ClearIncrementalString() { mIncrementalString.Truncate(); }
|
||||
static bool IsWithinIncrementalTime(DOMTimeStamp time) {
|
||||
return !sTimeoutOfIncrementalSearch || time - sLastKeyTime <= sTimeoutOfIncrementalSearch;
|
||||
}
|
||||
|
||||
virtual nsIAtom* GetType() const override { return nsGkAtoms::menuPopupFrame; }
|
||||
|
||||
|
@ -616,6 +619,8 @@ protected:
|
|||
|
||||
static int8_t sDefaultLevelIsTop;
|
||||
|
||||
static DOMTimeStamp sLastKeyTime;
|
||||
|
||||
// If 0, never timed out. Otherwise, the value is in milliseconds.
|
||||
static uint32_t sTimeoutOfIncrementalSearch;
|
||||
}; // class nsMenuPopupFrame
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче