зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound. CLOSED TREE
This commit is contained in:
Коммит
26aadf7f93
|
@ -411,7 +411,7 @@ pref("permissions.default.geo", 0);
|
|||
pref("permissions.default.desktop-notification", 0);
|
||||
pref("permissions.default.shortcuts", 0);
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
#ifdef EARLY_BETA_OR_EARLIER
|
||||
pref("permissions.desktop-notification.postPrompt.enabled", true);
|
||||
#else
|
||||
pref("permissions.desktop-notification.postPrompt.enabled", false);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
[DEFAULT]
|
||||
|
||||
[browser_principalSerialization_version1.js]
|
||||
[browser_principalSerialization_csp.js]
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/*
|
||||
* Within Bug 965637 we move the CSP away from the Principal. Serialized Principals however
|
||||
* might still have CSPs serialized within them. This tests ensures that we do not
|
||||
* encounter a memory corruption when deserializing. It's fine that the deserialized
|
||||
* CSP is null, but the Principal itself should deserialize correctly.
|
||||
*/
|
||||
|
||||
add_task(async function test_deserialize_principal_with_csp() {
|
||||
/*
|
||||
This test should be resilient to changes in principal serialization, if these are failing then it's likely the code will break session storage.
|
||||
To recreate this for another version, copy the function into the browser console, browse some pages and printHistory.
|
||||
|
||||
Generated with:
|
||||
function printHistory() {
|
||||
let tests = [];
|
||||
let entries = SessionStore.getSessionHistory(gBrowser.selectedTab).entries.map((entry) => { return entry.triggeringPrincipal_base64 });
|
||||
entries.push(E10SUtils.serializePrincipal(gBrowser.selectedTab.linkedBrowser._contentPrincipal));
|
||||
for (let entry of entries) {
|
||||
console.log(entry);
|
||||
let testData = {};
|
||||
testData.input = entry;
|
||||
let principal = E10SUtils.deserializePrincipal(testData.input);
|
||||
testData.output = {};
|
||||
if (principal.URI === null) {
|
||||
testData.output.URI = false;
|
||||
} else {
|
||||
testData.output.URISpec = principal.URI.spec;
|
||||
}
|
||||
testData.output.originAttributes = principal.originAttributes;
|
||||
testData.output.cspJSON = principal.cspJSON;
|
||||
|
||||
tests.push(testData);
|
||||
}
|
||||
return tests;
|
||||
}
|
||||
printHistory(); // Copy this into: serializedPrincipalsFromFirefox
|
||||
*/
|
||||
|
||||
let serializedPrincipalsFromFirefox = [
|
||||
{
|
||||
"input": "ZT4OTT7kRfqycpfCC8AeuAAAAAAAAAAAwAAAAAAAAEYB3pRy0IA0EdOTmQAQS6D9QJIHOlRteE8wkTq4cYEyCMYAAAAC/////wAAAbsBAAAAHmh0dHBzOi8vd3d3Lm1vemlsbGEub3JnL2VuLVVTLwAAAAAAAAAFAAAACAAAAA8AAAAA/////wAAAAD/////AAAACAAAAA8AAAAXAAAABwAAABcAAAAHAAAAFwAAAAcAAAAeAAAAAAAAAAD/////AAAAAP////8AAAAA/////wAAAAD/////AQAAAAAAAAAAAAAAAQnZ7Rrl1EAEv+Anzrkj2ayzxMCuvV5MrYfgjSENuz+fAd6UctCANBHTk5kAEEug/UCSBzpUbXhPMJE6uHGBMgjGAAAAAv////8AAAG7AQAAAB5odHRwczovL3d3dy5tb3ppbGxhLm9yZy9lbi1VUy8AAAAAAAAABQAAAAgAAAAPAAAAAP////8AAAAA/////wAAAAgAAAAPAAAAFwAAAAcAAAAXAAAABwAAABcAAAAHAAAAHgAAAAAAAAAA/////wAAAAD/////AAAAAP////8AAAAA/////wEAAAAAAAAAAAABAAAFtgBzAGMAcgBpAHAAdAAtAHMAcgBjACAAJwBzAGUAbABmACcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBuAGUAdAAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AYwBvAG0AIAAnAHUAbgBzAGEAZgBlAC0AaQBuAGwAaQBuAGUAJwAgACcAdQBuAHMAYQBmAGUALQBlAHYAYQBsACcAIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQB0AGEAZwBtAGEAbgBhAGcAZQByAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQAtAGEAbgBhAGwAeQB0AGkAYwBzAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdABhAGcAbQBhAG4AYQBnAGUAcgAuAGcAbwBvAGcAbABlAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgB5AG8AdQB0AHUAYgBlAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AcwAuAHkAdABpAG0AZwAuAGMAbwBtADsAIABpAG0AZwAtAHMAcgBjACAAJwBzAGUAbABmACcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBuAGUAdAAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AYwBvAG0AIABkAGEAdABhADoAIABoAHQAdABwAHMAOgAvAC8AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUAdABhAGcAbQBhAG4AYQBnAGUAcgAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUALQBhAG4AYQBsAHkAdABpAGMAcwAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAGEAZABzAGUAcgB2AGkAYwBlAC4AZwBvAG8AZwBsAGUALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwBhAGQAcwBlAHIAdgBpAGMAZQAuAGcAbwBvAGcAbABlAC4AZABlACAAaAB0AHQAcABzADoALwAvAGEAZABzAGUAcgB2AGkAYwBlAC4AZwBvAG8AZwBsAGUALgBkAGsAIABoAHQAdABwAHMAOgAvAC8AYwByAGUAYQB0AGkAdgBlAGMAbwBtAG0AbwBuAHMALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwBhAGQALgBkAG8AdQBiAGwAZQBjAGwAaQBjAGsALgBuAGUAdAA7ACAAZABlAGYAYQB1AGwAdAAtAHMAcgBjACAAJwBzAGUAbABmACcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBuAGUAdAAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AYwBvAG0AOwAgAGYAcgBhAG0AZQAtAHMAcgBjACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUAdABhAGcAbQBhAG4AYQBnAGUAcgAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUALQBhAG4AYQBsAHkAdABpAGMAcwAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AeQBvAHUAdAB1AGIAZQAtAG4AbwBjAG8AbwBrAGkAZQAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHQAcgBhAGMAawBlAHIAdABlAHMAdAAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AcwB1AHIAdgBlAHkAZwBpAHoAbQBvAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AYQBjAGMAbwB1AG4AdABzAC4AZgBpAHIAZQBmAG8AeAAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAGEAYwBjAG8AdQBuAHQAcwAuAGYAaQByAGUAZgBvAHgALgBjAG8AbQAuAGMAbgAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAHkAbwB1AHQAdQBiAGUALgBjAG8AbQA7ACAAcwB0AHkAbABlAC0AcwByAGMAIAAnAHMAZQBsAGYAJwAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG4AZQB0ACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AbwByAGcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBjAG8AbQAgACcAdQBuAHMAYQBmAGUALQBpAG4AbABpAG4AZQAnADsAIABjAG8AbgBuAGUAYwB0AC0AcwByAGMAIAAnAHMAZQBsAGYAJwAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG4AZQB0ACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AbwByAGcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAHQAYQBnAG0AYQBuAGEAZwBlAHIALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAC0AYQBuAGEAbAB5AHQAaQBjAHMALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwBhAGMAYwBvAHUAbgB0AHMALgBmAGkAcgBlAGYAbwB4AC4AYwBvAG0ALwAgAGgAdAB0AHAAcwA6AC8ALwBhAGMAYwBvAHUAbgB0AHMALgBmAGkAcgBlAGYAbwB4AC4AYwBvAG0ALgBjAG4ALwA7ACAAYwBoAGkAbABkAC0AcwByAGMAIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQB0AGEAZwBtAGEAbgBhAGcAZQByAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQAtAGEAbgBhAGwAeQB0AGkAYwBzAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgB5AG8AdQB0AHUAYgBlAC0AbgBvAGMAbwBvAGsAaQBlAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdAByAGEAYwBrAGUAcgB0AGUAcwB0AC4AbwByAGcAIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBzAHUAcgB2AGUAeQBnAGkAegBtAG8ALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwBhAGMAYwBvAHUAbgB0AHMALgBmAGkAcgBlAGYAbwB4AC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AYQBjAGMAbwB1AG4AdABzAC4AZgBpAHIAZQBmAG8AeAAuAGMAbwBtAC4AYwBuACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AeQBvAHUAdAB1AGIAZQAuAGMAbwBtAAA=",
|
||||
"output": {
|
||||
"cspJSON": "{\"csp-policies\":[{\"child-src\":[\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://www.youtube-nocookie.com\",\"https://trackertest.org\",\"https://www.surveygizmo.com\",\"https://accounts.firefox.com\",\"https://accounts.firefox.com.cn\",\"https://www.youtube.com\"],\"connect-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://accounts.firefox.com/\",\"https://accounts.firefox.com.cn/\"],\"default-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\"],\"frame-src\":[\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://www.youtube-nocookie.com\",\"https://trackertest.org\",\"https://www.surveygizmo.com\",\"https://accounts.firefox.com\",\"https://accounts.firefox.com.cn\",\"https://www.youtube.com\"],\"img-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"data:\",\"https://mozilla.org\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://adservice.google.com\",\"https://adservice.google.de\",\"https://adservice.google.dk\",\"https://creativecommons.org\",\"https://ad.doubleclick.net\"],\"report-only\":false,\"script-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"'unsafe-inline'\",\"'unsafe-eval'\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://tagmanager.google.com\",\"https://www.youtube.com\",\"https://s.ytimg.com\"],\"style-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"'unsafe-inline'\"]}]}",
|
||||
"URISpec": "https://www.mozilla.org/en-US/",
|
||||
"originAttributes": {
|
||||
"firstPartyDomain": "",
|
||||
"inIsolatedMozBrowser": false,
|
||||
"privateBrowsingId": 0,
|
||||
"userContextId": 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"input": "ZT4OTT7kRfqycpfCC8AeuAAAAAAAAAAAwAAAAAAAAEYB3pRy0IA0EdOTmQAQS6D9QJIHOlRteE8wkTq4cYEyCMYAAAAC/////wAAAbsBAAAAL2h0dHBzOi8vd3d3Lm1vemlsbGEub3JnL2VuLVVTL2ZpcmVmb3gvYWNjb3VudHMvAAAAAAAAAAUAAAAIAAAADwAAAAj/////AAAACP////8AAAAIAAAADwAAABcAAAAYAAAAFwAAABgAAAAXAAAAGAAAAC8AAAAAAAAAL/////8AAAAA/////wAAABf/////AAAAF/////8BAAAAAAAAAAAAAAABCdntGuXUQAS/4CfOuSPZrLPEwK69Xkyth+CNIQ27P58B3pRy0IA0EdOTmQAQS6D9QJIHOlRteE8wkTq4cYEyCMYAAAAC/////wAAAbsBAAAAL2h0dHBzOi8vd3d3Lm1vemlsbGEub3JnL2VuLVVTL2ZpcmVmb3gvYWNjb3VudHMvAAAAAAAAAAUAAAAIAAAADwAAAAj/////AAAACP////8AAAAIAAAADwAAABcAAAAYAAAAFwAAABgAAAAXAAAAGAAAAC8AAAAAAAAAL/////8AAAAA/////wAAABf/////AAAAF/////8BAAAAAAAAAAAAAQAABbYAcwBjAHIAaQBwAHQALQBzAHIAYwAgACcAcwBlAGwAZgAnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AbgBlAHQAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAGMAbwBtACAAJwB1AG4AcwBhAGYAZQAtAGkAbgBsAGkAbgBlACcAIAAnAHUAbgBzAGEAZgBlAC0AZQB2AGEAbAAnACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUAdABhAGcAbQBhAG4AYQBnAGUAcgAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUALQBhAG4AYQBsAHkAdABpAGMAcwAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHQAYQBnAG0AYQBuAGEAZwBlAHIALgBnAG8AbwBnAGwAZQAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AeQBvAHUAdAB1AGIAZQAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHMALgB5AHQAaQBtAGcALgBjAG8AbQA7ACAAaQBtAGcALQBzAHIAYwAgACcAcwBlAGwAZgAnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AbgBlAHQAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAGMAbwBtACAAZABhAHQAYQA6ACAAaAB0AHQAcABzADoALwAvAG0AbwB6AGkAbABsAGEALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAHQAYQBnAG0AYQBuAGEAZwBlAHIALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAC0AYQBuAGEAbAB5AHQAaQBjAHMALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwBhAGQAcwBlAHIAdgBpAGMAZQAuAGcAbwBvAGcAbABlAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AYQBkAHMAZQByAHYAaQBjAGUALgBnAG8AbwBnAGwAZQAuAGQAZQAgAGgAdAB0AHAAcwA6AC8ALwBhAGQAcwBlAHIAdgBpAGMAZQAuAGcAbwBvAGcAbABlAC4AZABrACAAaAB0AHQAcABzADoALwAvAGMAcgBlAGEAdABpAHYAZQBjAG8AbQBtAG8AbgBzAC4AbwByAGcAIABoAHQAdABwAHMAOgAvAC8AYQBkAC4AZABvAHUAYgBsAGUAYwBsAGkAYwBrAC4AbgBlAHQAOwAgAGQAZQBmAGEAdQBsAHQALQBzAHIAYwAgACcAcwBlAGwAZgAnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AbgBlAHQAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAGMAbwBtADsAIABmAHIAYQBtAGUALQBzAHIAYwAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAHQAYQBnAG0AYQBuAGEAZwBlAHIALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAC0AYQBuAGEAbAB5AHQAaQBjAHMALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAHkAbwB1AHQAdQBiAGUALQBuAG8AYwBvAG8AawBpAGUALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB0AHIAYQBjAGsAZQByAHQAZQBzAHQALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAHMAdQByAHYAZQB5AGcAaQB6AG0AbwAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAGEAYwBjAG8AdQBuAHQAcwAuAGYAaQByAGUAZgBvAHgALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwBhAGMAYwBvAHUAbgB0AHMALgBmAGkAcgBlAGYAbwB4AC4AYwBvAG0ALgBjAG4AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgB5AG8AdQB0AHUAYgBlAC4AYwBvAG0AOwAgAHMAdAB5AGwAZQAtAHMAcgBjACAAJwBzAGUAbABmACcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBuAGUAdAAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AYwBvAG0AIAAnAHUAbgBzAGEAZgBlAC0AaQBuAGwAaQBuAGUAJwA7ACAAYwBvAG4AbgBlAGMAdAAtAHMAcgBjACAAJwBzAGUAbABmACcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBuAGUAdAAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQB0AGEAZwBtAGEAbgBhAGcAZQByAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQAtAGEAbgBhAGwAeQB0AGkAYwBzAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AYQBjAGMAbwB1AG4AdABzAC4AZgBpAHIAZQBmAG8AeAAuAGMAbwBtAC8AIABoAHQAdABwAHMAOgAvAC8AYQBjAGMAbwB1AG4AdABzAC4AZgBpAHIAZQBmAG8AeAAuAGMAbwBtAC4AYwBuAC8AOwAgAGMAaABpAGwAZAAtAHMAcgBjACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUAdABhAGcAbQBhAG4AYQBnAGUAcgAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUALQBhAG4AYQBsAHkAdABpAGMAcwAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AeQBvAHUAdAB1AGIAZQAtAG4AbwBjAG8AbwBrAGkAZQAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHQAcgBhAGMAawBlAHIAdABlAHMAdAAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AcwB1AHIAdgBlAHkAZwBpAHoAbQBvAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AYQBjAGMAbwB1AG4AdABzAC4AZgBpAHIAZQBmAG8AeAAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAGEAYwBjAG8AdQBuAHQAcwAuAGYAaQByAGUAZgBvAHgALgBjAG8AbQAuAGMAbgAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAHkAbwB1AHQAdQBiAGUALgBjAG8AbQAA",
|
||||
"output": {
|
||||
"URISpec": "https://www.mozilla.org/en-US/firefox/accounts/",
|
||||
"originAttributes": {
|
||||
"firstPartyDomain": "",
|
||||
"inIsolatedMozBrowser": false,
|
||||
"privateBrowsingId": 0,
|
||||
"userContextId": 0,
|
||||
},
|
||||
"cspJSON": "{\"csp-policies\":[{\"child-src\":[\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://www.youtube-nocookie.com\",\"https://trackertest.org\",\"https://www.surveygizmo.com\",\"https://accounts.firefox.com\",\"https://accounts.firefox.com.cn\",\"https://www.youtube.com\"],\"connect-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://accounts.firefox.com/\",\"https://accounts.firefox.com.cn/\"],\"default-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\"],\"frame-src\":[\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://www.youtube-nocookie.com\",\"https://trackertest.org\",\"https://www.surveygizmo.com\",\"https://accounts.firefox.com\",\"https://accounts.firefox.com.cn\",\"https://www.youtube.com\"],\"img-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"data:\",\"https://mozilla.org\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://adservice.google.com\",\"https://adservice.google.de\",\"https://adservice.google.dk\",\"https://creativecommons.org\",\"https://ad.doubleclick.net\"],\"report-only\":false,\"script-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"'unsafe-inline'\",\"'unsafe-eval'\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://tagmanager.google.com\",\"https://www.youtube.com\",\"https://s.ytimg.com\"],\"style-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"'unsafe-inline'\"]}]}",
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
for (let test of serializedPrincipalsFromFirefox) {
|
||||
let principal = E10SUtils.deserializePrincipal(test.input);
|
||||
is(principal.cspJSON, test.output.cspJSON, "should have CSP");
|
||||
|
||||
for (let key in principal.originAttributes) {
|
||||
is(principal.originAttributes[key], test.output.originAttributes[key], `Ensure value of ${key} is ${test.output.originAttributes[key]}`);
|
||||
}
|
||||
|
||||
if ("URI" in test.output && test.output.URI === false) {
|
||||
is(principal.URI, null, "Should have not have a URI for system");
|
||||
} else {
|
||||
is(principal.URI.spec, test.output.URISpec, `Should have spec ${test.output.URISpec}`);
|
||||
}
|
||||
}
|
||||
});
|
|
@ -121,32 +121,6 @@ add_task(async function test_realHistoryCheck() {
|
|||
"cspJSON": "{}",
|
||||
},
|
||||
},
|
||||
{
|
||||
"input": "ZT4OTT7kRfqycpfCC8AeuAAAAAAAAAAAwAAAAAAAAEYB3pRy0IA0EdOTmQAQS6D9QJIHOlRteE8wkTq4cYEyCMYAAAAC/////wAAAbsBAAAAHmh0dHBzOi8vd3d3Lm1vemlsbGEub3JnL2VuLVVTLwAAAAAAAAAFAAAACAAAAA8AAAAA/////wAAAAD/////AAAACAAAAA8AAAAXAAAABwAAABcAAAAHAAAAFwAAAAcAAAAeAAAAAAAAAAD/////AAAAAP////8AAAAA/////wAAAAD/////AQAAAAAAAAAAAAAAAQnZ7Rrl1EAEv+Anzrkj2ayzxMCuvV5MrYfgjSENuz+fAd6UctCANBHTk5kAEEug/UCSBzpUbXhPMJE6uHGBMgjGAAAAAv////8AAAG7AQAAAB5odHRwczovL3d3dy5tb3ppbGxhLm9yZy9lbi1VUy8AAAAAAAAABQAAAAgAAAAPAAAAAP////8AAAAA/////wAAAAgAAAAPAAAAFwAAAAcAAAAXAAAABwAAABcAAAAHAAAAHgAAAAAAAAAA/////wAAAAD/////AAAAAP////8AAAAA/////wEAAAAAAAAAAAABAAAFtgBzAGMAcgBpAHAAdAAtAHMAcgBjACAAJwBzAGUAbABmACcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBuAGUAdAAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AYwBvAG0AIAAnAHUAbgBzAGEAZgBlAC0AaQBuAGwAaQBuAGUAJwAgACcAdQBuAHMAYQBmAGUALQBlAHYAYQBsACcAIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQB0AGEAZwBtAGEAbgBhAGcAZQByAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQAtAGEAbgBhAGwAeQB0AGkAYwBzAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdABhAGcAbQBhAG4AYQBnAGUAcgAuAGcAbwBvAGcAbABlAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgB5AG8AdQB0AHUAYgBlAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AcwAuAHkAdABpAG0AZwAuAGMAbwBtADsAIABpAG0AZwAtAHMAcgBjACAAJwBzAGUAbABmACcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBuAGUAdAAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AYwBvAG0AIABkAGEAdABhADoAIABoAHQAdABwAHMAOgAvAC8AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUAdABhAGcAbQBhAG4AYQBnAGUAcgAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUALQBhAG4AYQBsAHkAdABpAGMAcwAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAGEAZABzAGUAcgB2AGkAYwBlAC4AZwBvAG8AZwBsAGUALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwBhAGQAcwBlAHIAdgBpAGMAZQAuAGcAbwBvAGcAbABlAC4AZABlACAAaAB0AHQAcABzADoALwAvAGEAZABzAGUAcgB2AGkAYwBlAC4AZwBvAG8AZwBsAGUALgBkAGsAIABoAHQAdABwAHMAOgAvAC8AYwByAGUAYQB0AGkAdgBlAGMAbwBtAG0AbwBuAHMALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwBhAGQALgBkAG8AdQBiAGwAZQBjAGwAaQBjAGsALgBuAGUAdAA7ACAAZABlAGYAYQB1AGwAdAAtAHMAcgBjACAAJwBzAGUAbABmACcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBuAGUAdAAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AYwBvAG0AOwAgAGYAcgBhAG0AZQAtAHMAcgBjACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUAdABhAGcAbQBhAG4AYQBnAGUAcgAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUALQBhAG4AYQBsAHkAdABpAGMAcwAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AeQBvAHUAdAB1AGIAZQAtAG4AbwBjAG8AbwBrAGkAZQAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHQAcgBhAGMAawBlAHIAdABlAHMAdAAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AcwB1AHIAdgBlAHkAZwBpAHoAbQBvAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AYQBjAGMAbwB1AG4AdABzAC4AZgBpAHIAZQBmAG8AeAAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAGEAYwBjAG8AdQBuAHQAcwAuAGYAaQByAGUAZgBvAHgALgBjAG8AbQAuAGMAbgAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAHkAbwB1AHQAdQBiAGUALgBjAG8AbQA7ACAAcwB0AHkAbABlAC0AcwByAGMAIAAnAHMAZQBsAGYAJwAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG4AZQB0ACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AbwByAGcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBjAG8AbQAgACcAdQBuAHMAYQBmAGUALQBpAG4AbABpAG4AZQAnADsAIABjAG8AbgBuAGUAYwB0AC0AcwByAGMAIAAnAHMAZQBsAGYAJwAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG4AZQB0ACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AbwByAGcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAHQAYQBnAG0AYQBuAGEAZwBlAHIALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAC0AYQBuAGEAbAB5AHQAaQBjAHMALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwBhAGMAYwBvAHUAbgB0AHMALgBmAGkAcgBlAGYAbwB4AC4AYwBvAG0ALwAgAGgAdAB0AHAAcwA6AC8ALwBhAGMAYwBvAHUAbgB0AHMALgBmAGkAcgBlAGYAbwB4AC4AYwBvAG0ALgBjAG4ALwA7ACAAYwBoAGkAbABkAC0AcwByAGMAIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQB0AGEAZwBtAGEAbgBhAGcAZQByAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQAtAGEAbgBhAGwAeQB0AGkAYwBzAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgB5AG8AdQB0AHUAYgBlAC0AbgBvAGMAbwBvAGsAaQBlAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdAByAGEAYwBrAGUAcgB0AGUAcwB0AC4AbwByAGcAIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBzAHUAcgB2AGUAeQBnAGkAegBtAG8ALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwBhAGMAYwBvAHUAbgB0AHMALgBmAGkAcgBlAGYAbwB4AC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AYQBjAGMAbwB1AG4AdABzAC4AZgBpAHIAZQBmAG8AeAAuAGMAbwBtAC4AYwBuACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AeQBvAHUAdAB1AGIAZQAuAGMAbwBtAAA=",
|
||||
"output": {
|
||||
"cspJSON": "{\"csp-policies\":[{\"child-src\":[\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://www.youtube-nocookie.com\",\"https://trackertest.org\",\"https://www.surveygizmo.com\",\"https://accounts.firefox.com\",\"https://accounts.firefox.com.cn\",\"https://www.youtube.com\"],\"connect-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://accounts.firefox.com/\",\"https://accounts.firefox.com.cn/\"],\"default-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\"],\"frame-src\":[\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://www.youtube-nocookie.com\",\"https://trackertest.org\",\"https://www.surveygizmo.com\",\"https://accounts.firefox.com\",\"https://accounts.firefox.com.cn\",\"https://www.youtube.com\"],\"img-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"data:\",\"https://mozilla.org\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://adservice.google.com\",\"https://adservice.google.de\",\"https://adservice.google.dk\",\"https://creativecommons.org\",\"https://ad.doubleclick.net\"],\"report-only\":false,\"script-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"'unsafe-inline'\",\"'unsafe-eval'\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://tagmanager.google.com\",\"https://www.youtube.com\",\"https://s.ytimg.com\"],\"style-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"'unsafe-inline'\"]}]}",
|
||||
"URISpec": "https://www.mozilla.org/en-US/",
|
||||
"originAttributes": {
|
||||
"firstPartyDomain": "",
|
||||
"inIsolatedMozBrowser": false,
|
||||
"privateBrowsingId": 0,
|
||||
"userContextId": 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"input": "ZT4OTT7kRfqycpfCC8AeuAAAAAAAAAAAwAAAAAAAAEYB3pRy0IA0EdOTmQAQS6D9QJIHOlRteE8wkTq4cYEyCMYAAAAC/////wAAAbsBAAAAL2h0dHBzOi8vd3d3Lm1vemlsbGEub3JnL2VuLVVTL2ZpcmVmb3gvYWNjb3VudHMvAAAAAAAAAAUAAAAIAAAADwAAAAj/////AAAACP////8AAAAIAAAADwAAABcAAAAYAAAAFwAAABgAAAAXAAAAGAAAAC8AAAAAAAAAL/////8AAAAA/////wAAABf/////AAAAF/////8BAAAAAAAAAAAAAAABCdntGuXUQAS/4CfOuSPZrLPEwK69Xkyth+CNIQ27P58B3pRy0IA0EdOTmQAQS6D9QJIHOlRteE8wkTq4cYEyCMYAAAAC/////wAAAbsBAAAAL2h0dHBzOi8vd3d3Lm1vemlsbGEub3JnL2VuLVVTL2ZpcmVmb3gvYWNjb3VudHMvAAAAAAAAAAUAAAAIAAAADwAAAAj/////AAAACP////8AAAAIAAAADwAAABcAAAAYAAAAFwAAABgAAAAXAAAAGAAAAC8AAAAAAAAAL/////8AAAAA/////wAAABf/////AAAAF/////8BAAAAAAAAAAAAAQAABbYAcwBjAHIAaQBwAHQALQBzAHIAYwAgACcAcwBlAGwAZgAnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AbgBlAHQAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAGMAbwBtACAAJwB1AG4AcwBhAGYAZQAtAGkAbgBsAGkAbgBlACcAIAAnAHUAbgBzAGEAZgBlAC0AZQB2AGEAbAAnACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUAdABhAGcAbQBhAG4AYQBnAGUAcgAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUALQBhAG4AYQBsAHkAdABpAGMAcwAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHQAYQBnAG0AYQBuAGEAZwBlAHIALgBnAG8AbwBnAGwAZQAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AeQBvAHUAdAB1AGIAZQAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHMALgB5AHQAaQBtAGcALgBjAG8AbQA7ACAAaQBtAGcALQBzAHIAYwAgACcAcwBlAGwAZgAnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AbgBlAHQAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAGMAbwBtACAAZABhAHQAYQA6ACAAaAB0AHQAcABzADoALwAvAG0AbwB6AGkAbABsAGEALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAHQAYQBnAG0AYQBuAGEAZwBlAHIALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAC0AYQBuAGEAbAB5AHQAaQBjAHMALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwBhAGQAcwBlAHIAdgBpAGMAZQAuAGcAbwBvAGcAbABlAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AYQBkAHMAZQByAHYAaQBjAGUALgBnAG8AbwBnAGwAZQAuAGQAZQAgAGgAdAB0AHAAcwA6AC8ALwBhAGQAcwBlAHIAdgBpAGMAZQAuAGcAbwBvAGcAbABlAC4AZABrACAAaAB0AHQAcABzADoALwAvAGMAcgBlAGEAdABpAHYAZQBjAG8AbQBtAG8AbgBzAC4AbwByAGcAIABoAHQAdABwAHMAOgAvAC8AYQBkAC4AZABvAHUAYgBsAGUAYwBsAGkAYwBrAC4AbgBlAHQAOwAgAGQAZQBmAGEAdQBsAHQALQBzAHIAYwAgACcAcwBlAGwAZgAnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AbgBlAHQAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAGMAbwBtADsAIABmAHIAYQBtAGUALQBzAHIAYwAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAHQAYQBnAG0AYQBuAGEAZwBlAHIALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAGcAbwBvAGcAbABlAC0AYQBuAGEAbAB5AHQAaQBjAHMALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAHkAbwB1AHQAdQBiAGUALQBuAG8AYwBvAG8AawBpAGUALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwB0AHIAYQBjAGsAZQByAHQAZQBzAHQALgBvAHIAZwAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAHMAdQByAHYAZQB5AGcAaQB6AG0AbwAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAGEAYwBjAG8AdQBuAHQAcwAuAGYAaQByAGUAZgBvAHgALgBjAG8AbQAgAGgAdAB0AHAAcwA6AC8ALwBhAGMAYwBvAHUAbgB0AHMALgBmAGkAcgBlAGYAbwB4AC4AYwBvAG0ALgBjAG4AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgB5AG8AdQB0AHUAYgBlAC4AYwBvAG0AOwAgAHMAdAB5AGwAZQAtAHMAcgBjACAAJwBzAGUAbABmACcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBuAGUAdAAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AYwBvAG0AIAAnAHUAbgBzAGEAZgBlAC0AaQBuAGwAaQBuAGUAJwA7ACAAYwBvAG4AbgBlAGMAdAAtAHMAcgBjACAAJwBzAGUAbABmACcAIABoAHQAdABwAHMAOgAvAC8AKgAuAG0AbwB6AGkAbABsAGEALgBuAGUAdAAgAGgAdAB0AHAAcwA6AC8ALwAqAC4AbQBvAHoAaQBsAGwAYQAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvACoALgBtAG8AegBpAGwAbABhAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQB0AGEAZwBtAGEAbgBhAGcAZQByAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AdwB3AHcALgBnAG8AbwBnAGwAZQAtAGEAbgBhAGwAeQB0AGkAYwBzAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AYQBjAGMAbwB1AG4AdABzAC4AZgBpAHIAZQBmAG8AeAAuAGMAbwBtAC8AIABoAHQAdABwAHMAOgAvAC8AYQBjAGMAbwB1AG4AdABzAC4AZgBpAHIAZQBmAG8AeAAuAGMAbwBtAC4AYwBuAC8AOwAgAGMAaABpAGwAZAAtAHMAcgBjACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUAdABhAGcAbQBhAG4AYQBnAGUAcgAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AZwBvAG8AZwBsAGUALQBhAG4AYQBsAHkAdABpAGMAcwAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AeQBvAHUAdAB1AGIAZQAtAG4AbwBjAG8AbwBrAGkAZQAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAHQAcgBhAGMAawBlAHIAdABlAHMAdAAuAG8AcgBnACAAaAB0AHQAcABzADoALwAvAHcAdwB3AC4AcwB1AHIAdgBlAHkAZwBpAHoAbQBvAC4AYwBvAG0AIABoAHQAdABwAHMAOgAvAC8AYQBjAGMAbwB1AG4AdABzAC4AZgBpAHIAZQBmAG8AeAAuAGMAbwBtACAAaAB0AHQAcABzADoALwAvAGEAYwBjAG8AdQBuAHQAcwAuAGYAaQByAGUAZgBvAHgALgBjAG8AbQAuAGMAbgAgAGgAdAB0AHAAcwA6AC8ALwB3AHcAdwAuAHkAbwB1AHQAdQBiAGUALgBjAG8AbQAA",
|
||||
"output": {
|
||||
"URISpec": "https://www.mozilla.org/en-US/firefox/accounts/",
|
||||
"originAttributes": {
|
||||
"firstPartyDomain": "",
|
||||
"inIsolatedMozBrowser": false,
|
||||
"privateBrowsingId": 0,
|
||||
"userContextId": 0,
|
||||
},
|
||||
"cspJSON": "{\"csp-policies\":[{\"child-src\":[\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://www.youtube-nocookie.com\",\"https://trackertest.org\",\"https://www.surveygizmo.com\",\"https://accounts.firefox.com\",\"https://accounts.firefox.com.cn\",\"https://www.youtube.com\"],\"connect-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://accounts.firefox.com/\",\"https://accounts.firefox.com.cn/\"],\"default-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\"],\"frame-src\":[\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://www.youtube-nocookie.com\",\"https://trackertest.org\",\"https://www.surveygizmo.com\",\"https://accounts.firefox.com\",\"https://accounts.firefox.com.cn\",\"https://www.youtube.com\"],\"img-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"data:\",\"https://mozilla.org\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://adservice.google.com\",\"https://adservice.google.de\",\"https://adservice.google.dk\",\"https://creativecommons.org\",\"https://ad.doubleclick.net\"],\"report-only\":false,\"script-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"'unsafe-inline'\",\"'unsafe-eval'\",\"https://www.googletagmanager.com\",\"https://www.google-analytics.com\",\"https://tagmanager.google.com\",\"https://www.youtube.com\",\"https://s.ytimg.com\"],\"style-src\":[\"'self'\",\"https://*.mozilla.net\",\"https://*.mozilla.org\",\"https://*.mozilla.com\",\"'unsafe-inline'\"]}]}",
|
||||
},
|
||||
},
|
||||
{
|
||||
"input": "ZT4OTT7kRfqycpfCC8AeuAAAAAAAAAAAwAAAAAAAAEYB3pRy0IA0EdOTmQAQS6D9QJIHOlRteE8wkTq4cYEyCMYAAAAC/////wAAAbsBAAAAe2h0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTLz91dG1fc291cmNlPXd3dy5tb3ppbGxhLm9yZyZ1dG1fbWVkaXVtPXJlZmVycmFsJnV0bV9jYW1wYWlnbj1uYXYmdXRtX2NvbnRlbnQ9ZGV2ZWxvcGVycwAAAAAAAAAFAAAACAAAABUAAAAA/////wAAAAD/////AAAACAAAABUAAAAdAAAAXgAAAB0AAAAHAAAAHQAAAAcAAAAkAAAAAAAAAAD/////AAAAAP////8AAAAlAAAAVgAAAAD/////AQAAAAAAAAAAAAAAAA==",
|
||||
"output": {
|
||||
|
|
|
@ -0,0 +1,419 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* This test records I/O syscalls done on the main thread during startup.
|
||||
*
|
||||
* To run this test similar to try server, you need to run:
|
||||
* ./mach package
|
||||
* ./mach test --appname=dist <path to test>
|
||||
*
|
||||
* If you made changes that cause this test to fail, it's likely because you
|
||||
* are touching more files or directories during startup.
|
||||
* Most code has no reason to use main thread I/O.
|
||||
* If for some reason accessing the file system on the main thread is currently
|
||||
* unavoidable, consider defering the I/O as long as you can, ideally after
|
||||
* the end of startup.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/* Set this to true only for debugging purpose; it makes the output noisy. */
|
||||
const kDumpAllStacks = false;
|
||||
|
||||
// Shortcuts for conditions.
|
||||
const LINUX = AppConstants.platform == "linux";
|
||||
const WIN = AppConstants.platform == "win";
|
||||
const MAC = AppConstants.platform == "macosx";
|
||||
|
||||
/* Paths in the whitelist can:
|
||||
* - be a full path, eg. "/etc/mime.types"
|
||||
* - have a prefix which will be resolved using Services.dirsvc
|
||||
* eg. "GreD:omni.ja"
|
||||
* It's possible to have only a prefix, in thise case the directory will
|
||||
* still be resolved, eg. "UAppData:"
|
||||
* - use * at the begining and/or end as a wildcard
|
||||
* The folder separator is '/' even for Windows paths, where it'll be
|
||||
* automatically converted to '\'.
|
||||
*
|
||||
* Specifying 'ignoreIfUnused: true' will make the test ignore unused entries;
|
||||
* without this the test is strict and will fail if a whitelist entry isn't used.
|
||||
*
|
||||
* Each entry specifies the maximum number of times an operation is expected to
|
||||
* occur.
|
||||
* The operations currently reported by the I/O interposer are:
|
||||
* create/open: only supported on Windows currently. The test currently
|
||||
* ignores these markers to have a shorter initial whitelist.
|
||||
* Adding Unix support is bug 1533779.
|
||||
* stat: supported on all platforms when checking the last modified date or
|
||||
* file size. Supported only on Windows when checking if a file exists;
|
||||
* fixing this inconsistency is bug 1536109.
|
||||
* read: supported on all platforms, but unix platforms will only report read
|
||||
* calls going through NSPR.
|
||||
* write: supported on all platforms, but Linux will only report write calls
|
||||
* going through NSPR.
|
||||
* close: supported only on Unix, and only for close calls going through NSPR.
|
||||
* Adding Windows support is bug 1524574.
|
||||
* fsync: supported only on Windows.
|
||||
*
|
||||
* If an entry specifies more than one operation, if at least one of them is
|
||||
* encountered, the test won't report a failure for the entry. This helps when
|
||||
* whitelisting cases where the reported operations aren't the same on all
|
||||
* platforms due to the I/O interposer inconsistencies across platforms
|
||||
* documented above.
|
||||
*/
|
||||
const processes = {
|
||||
"Web Content": [
|
||||
{
|
||||
path: "GreD:omni.ja",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1376994
|
||||
path: "XCurProcD:omni.ja",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1543761
|
||||
path: "GreD:chrome.manifest",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1376994, bug 1543761
|
||||
path: "XCurProcD:chrome.manifest",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // Exists call in ScopedXREEmbed::SetAppDir
|
||||
path: "XCurProcD:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1357205
|
||||
path: "XREAppFeat:webcompat@mozilla.org.xpi",
|
||||
condition: !WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1357205
|
||||
path: "XREAppFeat:formautofill@mozilla.org.xpi",
|
||||
condition: !WIN,
|
||||
stat: 1,
|
||||
},
|
||||
],
|
||||
"Privileged Content": [
|
||||
{
|
||||
path: "GreD:omni.ja",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1376994
|
||||
path: "XCurProcD:omni.ja",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1543761
|
||||
path: "GreD:chrome.manifest",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1376994, bug 1543761
|
||||
path: "XCurProcD:chrome.manifest",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // Exists call in ScopedXREEmbed::SetAppDir
|
||||
path: "XCurProcD:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1357205
|
||||
path: "XREAppFeat:webcompat@mozilla.org.xpi",
|
||||
condition: !WIN,
|
||||
stat: 1,
|
||||
},
|
||||
],
|
||||
"WebExtensions": [
|
||||
{
|
||||
path: "GreD:omni.ja",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1376994
|
||||
path: "XCurProcD:omni.ja",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1543761
|
||||
path: "GreD:chrome.manifest",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1376994, bug 1543761
|
||||
path: "XCurProcD:chrome.manifest",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // Exists call in ScopedXREEmbed::SetAppDir
|
||||
path: "XCurProcD:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1357205
|
||||
path: "XREAppFeat:webcompat@mozilla.org.xpi",
|
||||
condition: !WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1357205
|
||||
path: "XREAppFeat:formautofill@mozilla.org.xpi",
|
||||
condition: !WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1357205
|
||||
path: "XREAppFeat:screenshots@mozilla.org.xpi",
|
||||
condition: !WIN,
|
||||
close: 1,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
function expandWhitelistPath(path) {
|
||||
if (path.includes(":")) {
|
||||
let [prefix, suffix] = path.split(":");
|
||||
let [key, property] = prefix.split(".");
|
||||
let dir = Services.dirsvc.get(key, Ci.nsIFile);
|
||||
if (property) {
|
||||
dir = dir[property];
|
||||
}
|
||||
|
||||
// Resolve symLinks.
|
||||
let dirPath = dir.path;
|
||||
while (dir && !dir.isSymlink()) {
|
||||
dir = dir.parent;
|
||||
}
|
||||
if (dir) {
|
||||
dirPath = dirPath.replace(dir.path, dir.target);
|
||||
}
|
||||
|
||||
path = dirPath;
|
||||
|
||||
if (suffix) {
|
||||
path += "/" + suffix;
|
||||
}
|
||||
}
|
||||
if (AppConstants.platform == "win") {
|
||||
path = path.replace(/\//g, "\\");
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
function getStackFromProfile(profile, stack) {
|
||||
const stackPrefixCol = profile.stackTable.schema.prefix;
|
||||
const stackFrameCol = profile.stackTable.schema.frame;
|
||||
const frameLocationCol = profile.frameTable.schema.location;
|
||||
|
||||
let result = [];
|
||||
while (stack) {
|
||||
let sp = profile.stackTable.data[stack];
|
||||
let frame = profile.frameTable.data[sp[stackFrameCol]];
|
||||
stack = sp[stackPrefixCol];
|
||||
frame = profile.stringTable[frame[frameLocationCol]];
|
||||
if (frame != "js::RunScript" && !frame.startsWith("next (self-hosted:")) {
|
||||
result.push(frame);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function getIOMarkersFromProfile(profile) {
|
||||
const nameCol = profile.markers.schema.name;
|
||||
const dataCol = profile.markers.schema.data;
|
||||
|
||||
let markers = [];
|
||||
for (let m of profile.markers.data) {
|
||||
let markerName = profile.stringTable[m[nameCol]];
|
||||
|
||||
if (markerName != "FileIO")
|
||||
continue;
|
||||
|
||||
let markerData = m[dataCol];
|
||||
if (markerData.source == "sqlite-mainthread") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let samples = markerData.stack.samples;
|
||||
let stack = samples.data[0][samples.schema.stack];
|
||||
markers.push({operation: markerData.operation,
|
||||
filename: markerData.filename,
|
||||
source: markerData.source,
|
||||
stackId: stack});
|
||||
}
|
||||
|
||||
return markers;
|
||||
}
|
||||
|
||||
function pathMatches(path, filename) {
|
||||
path = path.toLowerCase();
|
||||
return path == filename || // Full match
|
||||
// Wildcard on both sides of the path
|
||||
(path.startsWith("*") && path.endsWith("*") &&
|
||||
filename.includes(path.slice(1, -1))) ||
|
||||
// Wildcard suffix
|
||||
(path.endsWith("*") && filename.startsWith(path.slice(0, -1))) ||
|
||||
// Wildcard prefix
|
||||
(path.startsWith("*") && filename.endsWith(path.slice(1)));
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
if (!AppConstants.NIGHTLY_BUILD && !AppConstants.MOZ_DEV_EDITION && !AppConstants.DEBUG) {
|
||||
ok(!("@mozilla.org/test/startuprecorder;1" in Cc),
|
||||
"the startup recorder component shouldn't exist in this non-nightly/non-devedition/" +
|
||||
"non-debug build.");
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
let omniJa = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
|
||||
omniJa.append("omni.ja");
|
||||
if (!omniJa.exists()) {
|
||||
ok(false, "This test requires a packaged build, " +
|
||||
"run 'mach package' and then use --appname=dist");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"].getService().wrappedJSObject;
|
||||
await startupRecorder.done;
|
||||
|
||||
for (let process in processes) {
|
||||
processes[process] =
|
||||
processes[process].filter(entry => !("condition" in entry) || entry.condition);
|
||||
processes[process].forEach(entry => {
|
||||
entry.path = expandWhitelistPath(entry.path, entry.canonicalize);
|
||||
});
|
||||
}
|
||||
|
||||
let tmpPath = expandWhitelistPath(MAC ? "TmpD:" : "/dev/shm").toLowerCase();
|
||||
let shouldPass = true;
|
||||
for (let procName in processes) {
|
||||
let whitelist = processes[procName];
|
||||
info(`whitelisted paths for ${procName} process:\n` +
|
||||
whitelist.map(e => {
|
||||
let operations = Object.keys(e).filter(k => !["path", "condition"].includes(k))
|
||||
.map(k => `${k}: ${e[k]}`);
|
||||
return ` ${e.path} - ${operations.join(", ")}`;
|
||||
}).join("\n"));
|
||||
|
||||
let profile;
|
||||
for (let process of startupRecorder.data.profile.processes) {
|
||||
if (process.threads[0].processName == procName) {
|
||||
profile = process.threads[0];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (procName == "Privileged Content" && !profile) {
|
||||
// The Privileged Content is started from an idle task that may not have
|
||||
// been executed yet at the time we captured the startup profile in
|
||||
// startupRecorder.
|
||||
todo(false, `profile for ${procName} process not found`);
|
||||
} else {
|
||||
ok(profile, `Found profile for ${procName} process`);
|
||||
}
|
||||
if (!profile) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let markers = getIOMarkersFromProfile(profile);
|
||||
for (let marker of markers) {
|
||||
if (marker.operation == "create/open") {
|
||||
// TODO: handle these I/O markers once they are supported on
|
||||
// non-Windows platforms.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert to lower case before comparing because the OS X test slaves
|
||||
// have the 'Firefox' folder in 'Library/Application Support' created
|
||||
// as 'firefox' for some reason.
|
||||
let filename = marker.filename.toLowerCase();
|
||||
|
||||
if (!filename) {
|
||||
// We are still missing the filename on some mainthreadio markers,
|
||||
// these markers are currently useless for the purpose of this test.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!WIN) {
|
||||
if (filename == "/dev/urandom") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore I/O due to IPC. This doesn't really touch the disk.
|
||||
if (filename.startsWith(tmpPath + "/org.chromium.")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let expected = false;
|
||||
for (let entry of whitelist) {
|
||||
if (pathMatches(entry.path, filename)) {
|
||||
entry[marker.operation] = (entry[marker.operation] || 0) - 1;
|
||||
entry._used = true;
|
||||
expected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!expected) {
|
||||
record(false,
|
||||
`unexpected ${marker.operation} on ${marker.filename} in ${procName} process`,
|
||||
undefined,
|
||||
" " + getStackFromProfile(profile, marker.stackId).join("\n "));
|
||||
shouldPass = false;
|
||||
}
|
||||
info(`(${marker.source}) ${marker.operation} - ${marker.filename}`);
|
||||
if (kDumpAllStacks) {
|
||||
info(getStackFromProfile(profile, marker.stackId).map(f => " " + f)
|
||||
.join("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
for (let entry of whitelist) {
|
||||
for (let op in entry) {
|
||||
if (["path", "condition", "ignoreIfUnused", "_used"].includes(op)) {
|
||||
continue;
|
||||
}
|
||||
let message = `${op} on ${entry.path} `;
|
||||
if (entry[op] == 0) {
|
||||
message += "as many times as expected";
|
||||
} else if (entry[op] > 0) {
|
||||
message += `allowed ${entry[op]} more times`;
|
||||
} else {
|
||||
message += `${entry[op] * -1} more times than expected`;
|
||||
}
|
||||
ok(entry[op] >= 0, `${message} in ${procName} process`);
|
||||
}
|
||||
if (!("_used" in entry) && !entry.ignoreIfUnused) {
|
||||
ok(false, `unused whitelist entry ${procName}: ${entry.path}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldPass) {
|
||||
ok(shouldPass, "No unexpected main thread I/O during startup");
|
||||
} else {
|
||||
const filename = "child-startup-mainthreadio-profile.json";
|
||||
let path = Cc["@mozilla.org/process/environment;1"]
|
||||
.getService(Ci.nsIEnvironment)
|
||||
.get("MOZ_UPLOAD_DIR");
|
||||
let encoder = new TextEncoder();
|
||||
let profilePath = OS.Path.join(path, filename);
|
||||
await OS.File.writeAtomic(profilePath,
|
||||
encoder.encode(JSON.stringify(startupRecorder.data.profile)));
|
||||
ok(false,
|
||||
"Found some unexpected main thread I/O during child process startup; " +
|
||||
"profile uploaded in " + filename);
|
||||
}
|
||||
});
|
|
@ -0,0 +1,933 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* This test records I/O syscalls done on the main thread during startup.
|
||||
*
|
||||
* To run this test similar to try server, you need to run:
|
||||
* ./mach package
|
||||
* ./mach test --appname=dist <path to test>
|
||||
*
|
||||
* If you made changes that cause this test to fail, it's likely because you
|
||||
* are touching more files or directories during startup.
|
||||
* Most code has no reason to use main thread I/O.
|
||||
* If for some reason accessing the file system on the main thread is currently
|
||||
* unavoidable, consider defering the I/O as long as you can, ideally after
|
||||
* the end of startup.
|
||||
* If your code isn't strictly required to show the first browser window,
|
||||
* it shouldn't be loaded before we are done with first paint.
|
||||
* Finally, if your code isn't really needed during startup, it should not be
|
||||
* loaded before we have started handling user events.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
const { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
|
||||
|
||||
/* Set this to true only for debugging purpose; it makes the output noisy. */
|
||||
const kDumpAllStacks = false;
|
||||
|
||||
// Shortcuts for conditions.
|
||||
const LINUX = AppConstants.platform == "linux";
|
||||
const WIN = AppConstants.platform == "win";
|
||||
const MAC = AppConstants.platform == "macosx";
|
||||
|
||||
/* Paths in the whitelist can:
|
||||
* - be a full path, eg. "/etc/mime.types"
|
||||
* - have a prefix which will be resolved using Services.dirsvc
|
||||
* eg. "GreD:omni.ja"
|
||||
* It's possible to have only a prefix, in thise case the directory will
|
||||
* still be resolved, eg. "UAppData:"
|
||||
* - use * at the begining and/or end as a wildcard
|
||||
* - For Windows specific entries that require resolving the path to its
|
||||
* canonical form, ie. the old DOS 8.3 format, use canonicalize: true.
|
||||
* This is needed for stat calls to non-existent files.
|
||||
* The folder separator is '/' even for Windows paths, where it'll be
|
||||
* automatically converted to '\'.
|
||||
*
|
||||
* Specifying 'ignoreIfUnused: true' will make the test ignore unused entries;
|
||||
* without this the test is strict and will fail if a whitelist entry isn't used.
|
||||
*
|
||||
* Each entry specifies the maximum number of times an operation is expected to
|
||||
* occur.
|
||||
* The operations currently reported by the I/O interposer are:
|
||||
* create/open: only supported on Windows currently. The test currently
|
||||
* ignores these markers to have a shorter initial whitelist.
|
||||
* Adding Unix support is bug 1533779.
|
||||
* stat: supported on all platforms when checking the last modified date or
|
||||
* file size. Supported only on Windows when checking if a file exists;
|
||||
* fixing this inconsistency is bug 1536109.
|
||||
* read: supported on all platforms, but unix platforms will only report read
|
||||
* calls going through NSPR.
|
||||
* write: supported on all platforms, but Linux will only report write calls
|
||||
* going through NSPR.
|
||||
* close: supported only on Unix, and only for close calls going through NSPR.
|
||||
* Adding Windows support is bug 1524574.
|
||||
* fsync: supported only on Windows.
|
||||
*
|
||||
* If an entry specifies more than one operation, if at least one of them is
|
||||
* encountered, the test won't report a failure for the entry. This helps when
|
||||
* whitelisting cases where the reported operations aren't the same on all
|
||||
* platforms due to the I/O interposer inconsistencies across platforms
|
||||
* documented above.
|
||||
*/
|
||||
const startupPhases = {
|
||||
// Anything done before or during app-startup must have a compelling reason
|
||||
// to run before we have even selected the user profile.
|
||||
"before profile selection": [
|
||||
{ // bug 1541226
|
||||
path: "UAppData:",
|
||||
condition: WIN,
|
||||
stat: 3,
|
||||
},
|
||||
{ // bug 1541200
|
||||
path: "UAppData:Crash Reports/InstallTime20*",
|
||||
condition: AppConstants.MOZ_CRASHREPORTER,
|
||||
stat: 1, // only caught on Windows.
|
||||
read: 1,
|
||||
write: 2,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1541200
|
||||
path: "UAppData:Crash Reports/LastCrash",
|
||||
condition: WIN && AppConstants.MOZ_CRASHREPORTER,
|
||||
stat: 1, // only caught on Windows.
|
||||
read: 1,
|
||||
},
|
||||
{ // bug 1541200
|
||||
path: "UAppData:Crash Reports/LastCrash",
|
||||
condition: !WIN && AppConstants.MOZ_CRASHREPORTER,
|
||||
ignoreIfUnused: true, // only if we ever crashed on this machine
|
||||
read: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1541226
|
||||
path: "DefProfLRt.parent:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // At least the read seems unavoidable for a regular startup.
|
||||
path: "UAppData:profiles.ini",
|
||||
condition: MAC,
|
||||
stat: 1,
|
||||
read: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1546931
|
||||
path: "UAppData:installs.ini",
|
||||
condition: WIN || MAC,
|
||||
ignoreIfUnused: true, // only if a real profile exists on the system.
|
||||
read: 1,
|
||||
stat: 2,
|
||||
close: 1,
|
||||
},
|
||||
{ // At least the read seems unavoidable for a regular startup.
|
||||
path: "UAppData:profiles.ini",
|
||||
condition: WIN,
|
||||
ignoreIfUnused: true, // only if a real profile exists on the system.
|
||||
read: 1,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541226, bug 1363586, bug 1541593
|
||||
path: "ProfD:",
|
||||
condition: WIN,
|
||||
stat: 3,
|
||||
},
|
||||
{
|
||||
path: "ProfLD:.startup-incomplete",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1541491 to stop using this file, bug 1541494 to write correctly.
|
||||
path: "ProfLD:compatibility.ini",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
write: 18,
|
||||
close: 1,
|
||||
},
|
||||
{
|
||||
path: "GreD:omni.ja",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1376994
|
||||
path: "XCurProcD:omni.ja",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
},
|
||||
{
|
||||
path: "ProfD:parent.lock",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541603
|
||||
path: "ProfD:minidumps",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1543746
|
||||
path: "XCurProcD:defaults/preferences",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1544034
|
||||
path: "ProfLDS:startupCache/scriptCache-child-current.bin",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1544034
|
||||
path: "ProfLDS:startupCache/scriptCache-child.bin",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1544034
|
||||
path: "ProfLDS:startupCache/scriptCache-current.bin",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1544034
|
||||
path: "ProfLDS:startupCache/scriptCache.bin",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1544037
|
||||
path: "ProfLDS:startupCache/startupCache." +
|
||||
(Services.appinfo.is64Bit ? 8 : 4) + ".little",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541601
|
||||
path: "PrfDef:channel-prefs.js",
|
||||
stat: 1,
|
||||
read: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1543761
|
||||
path: "GreD:chrome.manifest",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1376994, bug 1543761
|
||||
path: "XCurProcD:chrome.manifest",
|
||||
condition: !WIN, // Visible on Windows with an open marker
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // At least the read seems unavoidable
|
||||
path: "PrefD:prefs.js",
|
||||
stat: 1,
|
||||
read: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1543752
|
||||
path: "PrefD:user.js",
|
||||
stat: 1,
|
||||
read: 1,
|
||||
close: 1,
|
||||
},
|
||||
{
|
||||
path: "*ld.so.conf*",
|
||||
condition: LINUX,
|
||||
ignoreIfUnused: true,
|
||||
read: 22,
|
||||
close: 11,
|
||||
},
|
||||
{ // bug 1546838
|
||||
path: "ProfD:xulstore/data.mdb",
|
||||
condition: WIN,
|
||||
write: 1,
|
||||
fsync: 1,
|
||||
},
|
||||
],
|
||||
|
||||
"before opening first browser window": [
|
||||
{ // bug 1541226
|
||||
path: "ProfD:",
|
||||
condition: WIN,
|
||||
stat: 2,
|
||||
},
|
||||
{
|
||||
path: "XCurProcD:blocklist.xml",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1534745
|
||||
path: "ProfD:cookies.sqlite-journal",
|
||||
condition: !LINUX,
|
||||
stat: 3,
|
||||
write: 4,
|
||||
},
|
||||
{ // bug 1534745
|
||||
path: "ProfD:cookies.sqlite",
|
||||
condition: !LINUX,
|
||||
stat: 2,
|
||||
read: 2,
|
||||
write: 1,
|
||||
},
|
||||
{ // bug 1534745
|
||||
path: "ProfD:cookies.sqlite-wal",
|
||||
condition: WIN,
|
||||
stat: 2,
|
||||
},
|
||||
{ // bug 975996
|
||||
path: "ProfD:permissions.sqlite",
|
||||
condition: WIN || MAC,
|
||||
fsync: 7,
|
||||
read: 2,
|
||||
stat: 1,
|
||||
write: 10,
|
||||
},
|
||||
{ // bug 975996
|
||||
path: "ProfD:permissions.sqlite-journal",
|
||||
condition: WIN || MAC,
|
||||
fsync: 7,
|
||||
stat: 26,
|
||||
write: 38,
|
||||
},
|
||||
{ // bug 975996
|
||||
path: "ProfD:permissions.sqlite-wal",
|
||||
condition: WIN,
|
||||
stat: 20,
|
||||
},
|
||||
{ // Seems done by OS X and outside of our control.
|
||||
path: "*.savedState/restorecount.plist",
|
||||
condition: MAC,
|
||||
ignoreIfUnused: true,
|
||||
write: 1,
|
||||
},
|
||||
{
|
||||
path: "*ld.so.conf*",
|
||||
condition: LINUX,
|
||||
ignoreIfUnused: true,
|
||||
read: 22,
|
||||
close: 11,
|
||||
},
|
||||
{ // bug 1545167
|
||||
path: "/etc/mime.types",
|
||||
condition: LINUX,
|
||||
read: 3,
|
||||
close: 3,
|
||||
},
|
||||
{
|
||||
path: "UChrm:userChrome.css",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541233
|
||||
path: "UChrm:userContent.css",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541246
|
||||
path: "XREUSysExt:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541246
|
||||
path: "XRESysExtDev:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541246
|
||||
path: "ProfD:extensions",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541246
|
||||
path: "XCurProcD:extensions",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1541246
|
||||
path: "UAppData:",
|
||||
ignoreIfUnused: true, // sometimes before opening first browser window,
|
||||
// sometimes before first paint
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1546838
|
||||
path: "ProfD:xulstore/data.mdb",
|
||||
condition: WIN,
|
||||
read: 1,
|
||||
},
|
||||
],
|
||||
|
||||
// We reach this phase right after showing the first browser window.
|
||||
// This means that any I/O at this point delayed first paint.
|
||||
"before first paint": [
|
||||
{ // bug 1541226
|
||||
path: "ProfD:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545119
|
||||
path: "OldUpdRootD:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1446012
|
||||
path: "UpdRootD:updates/0/update.status",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "ProfD:pluginreg.dat",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "ProfD:pluginreg.dat.tmp",
|
||||
stat: 1,
|
||||
write: 64,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "ProfD:plugins",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "APlugns:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "UserPlugins.parent:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "UserPlugins:",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "ProfD:plugins/nptest.dll",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "ProfD:plugins/npsecondtest.dll",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "ProfD:plugins/npthirdtest.dll",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1545123
|
||||
path: "ProfD:plugins/npswftest.dll",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{
|
||||
path: "XREAppFeat:formautofill@mozilla.org.xpi",
|
||||
condition: !WIN,
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1545167
|
||||
path: "/etc/mime.types",
|
||||
condition: LINUX,
|
||||
read: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // We only hit this for new profiles.
|
||||
path: "XREAppDist:distribution.ini",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{
|
||||
path: "*WindowsApps/microsoft.windowscommunicationsapps*",
|
||||
condition: WIN,
|
||||
ignoreIfUnused: true,
|
||||
stat: 3,
|
||||
},
|
||||
{ // bug 1545139
|
||||
path: "*Fonts/StaticCache.dat",
|
||||
condition: WIN,
|
||||
ignoreIfUnused: true, // Only on Win7
|
||||
read: 1,
|
||||
},
|
||||
{ // bug 1541246
|
||||
path: "UAppData:",
|
||||
ignoreIfUnused: true, // sometimes before opening first browser window,
|
||||
// sometimes before first paint
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // Not in packaged builds; useful for artifact builds.
|
||||
path: "GreD:ScalarArtifactDefinitions.json",
|
||||
condition: WIN && !AppConstants.MOZILLA_OFFICIAL,
|
||||
stat: 1,
|
||||
},
|
||||
{ // Not in packaged builds; useful for artifact builds.
|
||||
path: "GreD:EventArtifactDefinitions.json",
|
||||
condition: WIN && !AppConstants.MOZILLA_OFFICIAL,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1546838
|
||||
path: "ProfD:xulstore/data.mdb",
|
||||
condition: MAC,
|
||||
write: 3,
|
||||
},
|
||||
{ // bug 1543090
|
||||
path: "GreD:omni.ja",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1543090
|
||||
path: "XCurProcD:omni.ja",
|
||||
condition: WIN,
|
||||
stat: 2,
|
||||
},
|
||||
],
|
||||
|
||||
// We are at this phase once we are ready to handle user events.
|
||||
// Any IO at this phase or before gets in the way of the user
|
||||
// interacting with the first browser window.
|
||||
"before handling user events": [
|
||||
{
|
||||
path: "GreD:update.test",
|
||||
ignoreIfUnused: true,
|
||||
condition: LINUX,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:cert9.db",
|
||||
condition: WIN,
|
||||
read: 2,
|
||||
stat: 2,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:cert9.db",
|
||||
condition: WIN,
|
||||
ignoreIfUnused: true, // if canonicalize(ProfD) == ProfD, we'll use the previous entry.
|
||||
canonicalize: true,
|
||||
stat: 2,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:cert9.db-journal",
|
||||
condition: WIN,
|
||||
canonicalize: true,
|
||||
stat: 2,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:cert9.db-wal",
|
||||
condition: WIN,
|
||||
canonicalize: true,
|
||||
stat: 2,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:pkcs11.txt",
|
||||
condition: WIN,
|
||||
read: 2,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:key4.db",
|
||||
condition: WIN,
|
||||
read: 2,
|
||||
stat: 2,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:key4.db",
|
||||
condition: WIN,
|
||||
ignoreIfUnused: true, // if canonicalize(ProfD) == ProfD, we'll use the previous entry.
|
||||
canonicalize: true,
|
||||
stat: 2,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:key4.db-journal",
|
||||
condition: WIN,
|
||||
canonicalize: true,
|
||||
stat: 5,
|
||||
},
|
||||
{ // bug 1370516 - NSS should be initialized off main thread.
|
||||
path: "ProfD:key4.db-wal",
|
||||
condition: WIN,
|
||||
canonicalize: true,
|
||||
stat: 5,
|
||||
},
|
||||
{
|
||||
path: "XREAppFeat:webcompat-reporter@mozilla.org.xpi",
|
||||
condition: !WIN,
|
||||
ignoreIfUnused: true,
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1003968
|
||||
path: "XREAppDist:searchplugins",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{
|
||||
path: "XCurProcD:extensions",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1543090
|
||||
path: "GreD:omni.ja",
|
||||
condition: WIN,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1543090
|
||||
path: "XCurProcD:omni.ja",
|
||||
condition: WIN,
|
||||
stat: 2,
|
||||
},
|
||||
],
|
||||
|
||||
// Things that are expected to be completely out of the startup path
|
||||
// and loaded lazily when used for the first time by the user should
|
||||
// be blacklisted here.
|
||||
"before becoming idle": [
|
||||
{
|
||||
path: "XREAppFeat:screenshots@mozilla.org.xpi",
|
||||
ignoreIfUnused: true,
|
||||
close: 1,
|
||||
},
|
||||
{
|
||||
path: "XREAppFeat:webcompat-reporter@mozilla.org.xpi",
|
||||
ignoreIfUnused: true,
|
||||
stat: 1,
|
||||
close: 1,
|
||||
},
|
||||
{ // bug 1391590
|
||||
path: "ProfD:places.sqlite-journal",
|
||||
ignoreIfUnused: true,
|
||||
fsync: 1,
|
||||
stat: 4,
|
||||
write: 2,
|
||||
},
|
||||
{ // bug 1391590
|
||||
path: "ProfD:places.sqlite-wal",
|
||||
ignoreIfUnused: true,
|
||||
stat: 4,
|
||||
fsync: 3,
|
||||
write: 148,
|
||||
},
|
||||
{ // bug 1391590
|
||||
path: "ProfD:places.sqlite-shm",
|
||||
condition: WIN,
|
||||
ignoreIfUnused: true,
|
||||
stat: 1,
|
||||
},
|
||||
{ // bug 1391590
|
||||
path: "ProfD:places.sqlite",
|
||||
ignoreIfUnused: true,
|
||||
fsync: 2,
|
||||
read: 1,
|
||||
stat: 3,
|
||||
write: 1310,
|
||||
},
|
||||
{ // bug 1391590
|
||||
path: "ProfD:favicons.sqlite-journal",
|
||||
ignoreIfUnused: true,
|
||||
fsync: 2,
|
||||
stat: 7,
|
||||
write: 7,
|
||||
},
|
||||
{ // bug 1391590
|
||||
path: "ProfD:favicons.sqlite-wal",
|
||||
ignoreIfUnused: true,
|
||||
fsync: 2,
|
||||
stat: 7,
|
||||
write: 15,
|
||||
},
|
||||
{ // bug 1391590
|
||||
path: "ProfD:favicons.sqlite-shm",
|
||||
condition: WIN,
|
||||
ignoreIfUnused: true,
|
||||
stat: 2,
|
||||
},
|
||||
{ // bug 1391590
|
||||
path: "ProfD:favicons.sqlite",
|
||||
ignoreIfUnused: true,
|
||||
fsync: 3,
|
||||
read: 4,
|
||||
stat: 4,
|
||||
write: 1300,
|
||||
},
|
||||
{
|
||||
path: "ProfD:key4.db-journal",
|
||||
condition: WIN,
|
||||
canonicalize: true,
|
||||
stat: 2,
|
||||
},
|
||||
{
|
||||
path: "ProfD:key4.db-wal",
|
||||
condition: WIN,
|
||||
canonicalize: true,
|
||||
stat: 2,
|
||||
},
|
||||
{
|
||||
path: "ProfD:",
|
||||
condition: WIN,
|
||||
ignoreIfUnused: true,
|
||||
stat: 3,
|
||||
},
|
||||
{ // bug 1543090
|
||||
path: "XCurProcD:omni.ja",
|
||||
condition: WIN,
|
||||
stat: 7,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
for (let name of ["d3d11layers", "d3d9video", "glcontext", "d3d11video", "wmfvpxvideo"]) {
|
||||
startupPhases["before first paint"].push({
|
||||
path: `ProfD:${name}.guard`,
|
||||
ignoreIfUnused: true,
|
||||
stat: 1,
|
||||
});
|
||||
}
|
||||
|
||||
function expandWhitelistPath(path, canonicalize = false) {
|
||||
if (path.includes(":")) {
|
||||
let [prefix, suffix] = path.split(":");
|
||||
let [key, property] = prefix.split(".");
|
||||
let dir = Services.dirsvc.get(key, Ci.nsIFile);
|
||||
if (property) {
|
||||
dir = dir[property];
|
||||
}
|
||||
|
||||
if (canonicalize) {
|
||||
path = dir.QueryInterface(Ci.nsILocalFileWin).canonicalPath;
|
||||
} else {
|
||||
// Resolve symLinks.
|
||||
let dirPath = dir.path;
|
||||
while (dir && !dir.isSymlink()) {
|
||||
dir = dir.parent;
|
||||
}
|
||||
if (dir) {
|
||||
dirPath = dirPath.replace(dir.path, dir.target);
|
||||
}
|
||||
|
||||
path = dirPath;
|
||||
}
|
||||
|
||||
if (suffix) {
|
||||
path += "/" + suffix;
|
||||
}
|
||||
}
|
||||
if (AppConstants.platform == "win") {
|
||||
path = path.replace(/\//g, "\\");
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
function getStackFromProfile(profile, stack) {
|
||||
const stackPrefixCol = profile.stackTable.schema.prefix;
|
||||
const stackFrameCol = profile.stackTable.schema.frame;
|
||||
const frameLocationCol = profile.frameTable.schema.location;
|
||||
|
||||
let result = [];
|
||||
while (stack) {
|
||||
let sp = profile.stackTable.data[stack];
|
||||
let frame = profile.frameTable.data[sp[stackFrameCol]];
|
||||
stack = sp[stackPrefixCol];
|
||||
frame = profile.stringTable[frame[frameLocationCol]];
|
||||
if (frame != "js::RunScript" && !frame.startsWith("next (self-hosted:")) {
|
||||
result.push(frame);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function pathMatches(path, filename) {
|
||||
path = path.toLowerCase();
|
||||
return path == filename || // Full match
|
||||
// Wildcard on both sides of the path
|
||||
(path.startsWith("*") && path.endsWith("*") &&
|
||||
filename.includes(path.slice(1, -1))) ||
|
||||
// Wildcard suffix
|
||||
(path.endsWith("*") && filename.startsWith(path.slice(0, -1))) ||
|
||||
// Wildcard prefix
|
||||
(path.startsWith("*") && filename.endsWith(path.slice(1)));
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
if (!AppConstants.NIGHTLY_BUILD && !AppConstants.MOZ_DEV_EDITION && !AppConstants.DEBUG) {
|
||||
ok(!("@mozilla.org/test/startuprecorder;1" in Cc),
|
||||
"the startup recorder component shouldn't exist in this non-nightly/non-devedition/" +
|
||||
"non-debug build.");
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
let omniJa = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
|
||||
omniJa.append("omni.ja");
|
||||
if (!omniJa.exists()) {
|
||||
ok(false, "This test requires a packaged build, " +
|
||||
"run 'mach package' and then use --appname=dist");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let startupRecorder = Cc["@mozilla.org/test/startuprecorder;1"].getService().wrappedJSObject;
|
||||
await startupRecorder.done;
|
||||
|
||||
// Add system add-ons to the whitelist dynamically.
|
||||
// They should go in the omni.ja file (bug 1357205).
|
||||
{
|
||||
let addons = await AddonManager.getAddonsByTypes(["extension"]);
|
||||
for (let addon of addons) {
|
||||
if (addon.isSystem) {
|
||||
startupPhases["before opening first browser window"].push({
|
||||
path: `XREAppFeat:${addon.id}.xpi`,
|
||||
stat: 3,
|
||||
close: 2,
|
||||
});
|
||||
startupPhases["before handling user events"].push({
|
||||
path: `XREAppFeat:${addon.id}.xpi`,
|
||||
condition: WIN,
|
||||
stat: 2,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for main thread I/O markers in the startup profile.
|
||||
let profile = startupRecorder.data.profile.threads[0];
|
||||
|
||||
let phases = {};
|
||||
{
|
||||
const nameCol = profile.markers.schema.name;
|
||||
const dataCol = profile.markers.schema.data;
|
||||
|
||||
let markersForCurrentPhase = [];
|
||||
|
||||
for (let m of profile.markers.data) {
|
||||
let markerName = profile.stringTable[m[nameCol]];
|
||||
if (markerName.startsWith("startupRecorder:")) {
|
||||
phases[markerName.split("startupRecorder:")[1]] = markersForCurrentPhase;
|
||||
markersForCurrentPhase = [];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (markerName != "FileIO")
|
||||
continue;
|
||||
|
||||
let markerData = m[dataCol];
|
||||
if (markerData.source == "sqlite-mainthread") {
|
||||
continue;
|
||||
}
|
||||
|
||||
let samples = markerData.stack.samples;
|
||||
let stack = samples.data[0][samples.schema.stack];
|
||||
markersForCurrentPhase.push({operation: markerData.operation,
|
||||
filename: markerData.filename,
|
||||
source: markerData.source,
|
||||
stackId: stack});
|
||||
}
|
||||
}
|
||||
|
||||
for (let phase in startupPhases) {
|
||||
startupPhases[phase] =
|
||||
startupPhases[phase].filter(entry => !("condition" in entry) || entry.condition);
|
||||
startupPhases[phase].forEach(entry => {
|
||||
entry.path = expandWhitelistPath(entry.path, entry.canonicalize);
|
||||
});
|
||||
}
|
||||
|
||||
let tmpPath = expandWhitelistPath(MAC ? "TmpD:" : "/dev/shm").toLowerCase();
|
||||
let shouldPass = true;
|
||||
for (let phase in phases) {
|
||||
let whitelist = startupPhases[phase];
|
||||
info(`whitelisted paths ${phase}:\n` +
|
||||
whitelist.map(e => {
|
||||
let operations = Object.keys(e).filter(k => k != "path")
|
||||
.map(k => `${k}: ${e[k]}`);
|
||||
return ` ${e.path} - ${operations.join(", ")}`;
|
||||
}).join("\n"));
|
||||
|
||||
let markers = phases[phase];
|
||||
for (let marker of markers) {
|
||||
if (marker.operation == "create/open") {
|
||||
// TODO: handle these I/O markers once they are supported on
|
||||
// non-Windows platforms.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert to lower case before comparing because the OS X test slaves
|
||||
// have the 'Firefox' folder in 'Library/Application Support' created
|
||||
// as 'firefox' for some reason.
|
||||
let filename = marker.filename.toLowerCase();
|
||||
|
||||
if (!filename) {
|
||||
// We are still missing the filename on some mainthreadio markers,
|
||||
// these markers are currently useless for the purpose of this test.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!WIN) {
|
||||
if (filename == "/dev/urandom") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore I/O due to IPC. This doesn't really touch the disk.
|
||||
if (filename.startsWith(tmpPath + "/org.chromium.")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let expected = false;
|
||||
for (let entry of whitelist) {
|
||||
if (pathMatches(entry.path, filename)) {
|
||||
entry[marker.operation] = (entry[marker.operation] || 0) - 1;
|
||||
entry._used = true;
|
||||
expected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!expected) {
|
||||
record(false,
|
||||
`unexpected ${marker.operation} on ${marker.filename} ${phase}`,
|
||||
undefined,
|
||||
" " + getStackFromProfile(profile, marker.stackId).join("\n "));
|
||||
shouldPass = false;
|
||||
}
|
||||
info(`(${marker.source}) ${marker.operation} - ${marker.filename}`);
|
||||
if (kDumpAllStacks) {
|
||||
info(getStackFromProfile(profile, marker.stackId).map(f => " " + f)
|
||||
.join("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
for (let entry of whitelist) {
|
||||
for (let op in entry) {
|
||||
if (["path", "condition", "canonicalize", "ignoreIfUnused", "_used"].includes(op)) {
|
||||
continue;
|
||||
}
|
||||
let message = `${op} on ${entry.path} `;
|
||||
if (entry[op] == 0) {
|
||||
message += "as many times as expected";
|
||||
} else if (entry[op] > 0) {
|
||||
message += `allowed ${entry[op]} more times`;
|
||||
} else {
|
||||
message += `${entry[op] * -1} more times than expected`;
|
||||
}
|
||||
ok(entry[op] >= 0, `${message} ${phase}`);
|
||||
}
|
||||
if (!("_used" in entry) && !entry.ignoreIfUnused) {
|
||||
ok(false, `unused whitelist entry ${phase}: ${entry.path}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldPass) {
|
||||
ok(shouldPass, "No unexpected main thread I/O during startup");
|
||||
} else {
|
||||
const filename = "startup-mainthreadio-profile.json";
|
||||
let path = Cc["@mozilla.org/process/environment;1"]
|
||||
.getService(Ci.nsIEnvironment)
|
||||
.get("MOZ_UPLOAD_DIR");
|
||||
let encoder = new TextEncoder();
|
||||
let profilePath = OS.Path.join(path, filename);
|
||||
await OS.File.writeAtomic(profilePath,
|
||||
encoder.encode(JSON.stringify(startupRecorder.data.profile)));
|
||||
ok(false,
|
||||
"Found some unexpected main thread I/O during startup; profile uploaded in " +
|
||||
filename);
|
||||
}
|
||||
});
|
|
@ -0,0 +1,20 @@
|
|||
[DEFAULT]
|
||||
# Currently disabled on debug due to debug-only failures, see bug 1549723.
|
||||
skip-if = debug
|
||||
# to avoid overhead when running the browser normally, startupRecorder.js will
|
||||
# do almost nothing unless browser.startup.record is true.
|
||||
# gfx.canvas.willReadFrequently.enable is just an optimization, but needs to be
|
||||
# set during early startup to have an impact as a canvas will be used by
|
||||
# startupRecorder.js
|
||||
prefs =
|
||||
# Skip migration work in BG__migrateUI for browser_startup.js since it isn't
|
||||
# representative of common startup, and triggers Places I/O.
|
||||
browser.migration.version=9999999
|
||||
browser.startup.record=true
|
||||
gfx.canvas.willReadFrequently.enable=true
|
||||
environment =
|
||||
MOZ_PROFILER_STARTUP=1
|
||||
MOZ_PROFILER_STARTUP_FEATURES=js,mainthreadio
|
||||
MOZ_PROFILER_STARTUP_ENTRIES=10000000
|
||||
[../browser_startup_mainthreadio.js]
|
||||
[../browser_startup_content_mainthreadio.js]
|
|
@ -28,6 +28,7 @@ support-files =
|
|||
[browser_trackingUI_open_preferences.js]
|
||||
[browser_trackingUI_pbmode_exceptions.js]
|
||||
[browser_trackingUI_report_breakage.js]
|
||||
skip-if = os == 'linux' && (debug || asan) # Bug 1546797
|
||||
[browser_trackingUI_state.js]
|
||||
skip-if = serviceworker_e10s # see https://bugzilla.mozilla.org/show_bug.cgi?id=1511303#c1
|
||||
[browser_trackingUI_state_all_disabled.js]
|
||||
|
|
|
@ -34,6 +34,7 @@ BROWSER_CHROME_MANIFESTS += [
|
|||
'content/test/pageinfo/browser.ini',
|
||||
'content/test/performance/browser.ini',
|
||||
'content/test/performance/hidpi/browser.ini',
|
||||
'content/test/performance/io/browser.ini',
|
||||
'content/test/performance/legacyurlbar/browser.ini',
|
||||
'content/test/performance/lowdpi/browser.ini',
|
||||
'content/test/permissions/browser.ini',
|
||||
|
|
|
@ -130,6 +130,20 @@
|
|||
</popupnotificationcontent>
|
||||
</popupnotification>
|
||||
|
||||
<popupnotification id="appMenu-update-unsupported-notification"
|
||||
popupid="update-unsupported"
|
||||
data-lazy-l10n-id="appmenu-update-unsupported"
|
||||
data-l10n-attrs="buttonlabel, buttonaccesskey, secondarybuttonlabel, secondarybuttonaccesskey"
|
||||
closebuttonhidden="true"
|
||||
dropmarkerhidden="true"
|
||||
checkboxhidden="true"
|
||||
buttonhighlight="true"
|
||||
hidden="true">
|
||||
<popupnotificationcontent id="update-unsupported-notification-content" orient="vertical">
|
||||
<description id="update-unsupported-description" data-lazy-l10n-id="appmenu-update-unsupported-message"></description>
|
||||
</popupnotificationcontent>
|
||||
</popupnotification>
|
||||
|
||||
<popupnotification id="appMenu-update-restart-notification"
|
||||
popupid="update-restart"
|
||||
data-lazy-l10n-id="appmenu-update-restart"
|
||||
|
@ -217,6 +231,7 @@
|
|||
<toolbarbutton class="panel-banner-item"
|
||||
label-update-available="&updateAvailable.panelUI.label;"
|
||||
label-update-manual="&updateManual.panelUI.label;"
|
||||
label-update-unsupported="&updateUnsupported.panelUI.label;"
|
||||
label-update-restart="&updateRestart.panelUI.label2;"
|
||||
oncommand="PanelUI._onBannerItemSelected(event)"
|
||||
wrap="true"
|
||||
|
|
|
@ -466,6 +466,12 @@ add_task(async function testPolicyCategorization() {
|
|||
|
||||
// Cleanup after this particular test.
|
||||
if (Services.policies.status != Ci.nsIEnterprisePolicies.INACTIVE) {
|
||||
await EnterprisePolicyTesting.setupPolicyEngineWithJson({
|
||||
policies: {"Cookies": {
|
||||
"Locked": false,
|
||||
},
|
||||
},
|
||||
});
|
||||
await EnterprisePolicyTesting.setupPolicyEngineWithJson("");
|
||||
}
|
||||
is(Services.policies.status, Ci.nsIEnterprisePolicies.INACTIVE, "Engine is inactive at the end of the test");
|
||||
|
|
|
@ -11,9 +11,7 @@
|
|||
*/
|
||||
|
||||
const TEST_PATH = "http://example.net/browser/browser/components/resistfingerprinting/test/browser/";
|
||||
|
||||
const DEFAULT_ROUNDED_WIDTH_STEP = 200;
|
||||
const DEFAULT_ROUNDED_HEIGHT_STEP = 100;
|
||||
const { RFPHelper } = ChromeUtils.import("resource://gre/modules/RFPHelper.jsm");
|
||||
|
||||
// A set of test cases which defines the width and the height of the outer window.
|
||||
const TEST_CASES = [
|
||||
|
@ -50,10 +48,9 @@ function handleOSFuzziness(aContent, aTarget) {
|
|||
|
||||
function checkForDefaultSetting(
|
||||
aContentWidth, aContentHeight, aRealWidth, aRealHeight) {
|
||||
// The default behavior for rounding is to round window with 200x100 stepping.
|
||||
// So, we can get the rounded size by subtracting the remainder.
|
||||
let targetWidth = aRealWidth - (aRealWidth % DEFAULT_ROUNDED_WIDTH_STEP);
|
||||
let targetHeight = aRealHeight - (aRealHeight % DEFAULT_ROUNDED_HEIGHT_STEP);
|
||||
// We can get the rounded size by subtracting twice the margin.
|
||||
let targetWidth = aRealWidth - (2 * RFPHelper.steppedRange(aRealWidth));
|
||||
let targetHeight = aRealHeight - (2 * RFPHelper.steppedRange(aRealHeight));
|
||||
|
||||
// This platform-specific code is explained in the large comment below.
|
||||
if (getPlatform() != "linux") {
|
||||
|
|
|
@ -63,6 +63,7 @@ startupRecorder.prototype = {
|
|||
if (!Services.prefs.getBoolPref("browser.startup.record", false))
|
||||
return;
|
||||
|
||||
Services.profiler.AddMarker("startupRecorder:" + name);
|
||||
this.data.code[name] = {
|
||||
components: Cu.loadedComponents,
|
||||
modules: Cu.loadedModules,
|
||||
|
@ -163,8 +164,24 @@ startupRecorder.prototype = {
|
|||
Services.prefs.readStats((key, value) => this.data.prefStats[key] = value);
|
||||
}
|
||||
paints = null;
|
||||
this._resolve();
|
||||
this._resolve = null;
|
||||
|
||||
let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
|
||||
if (!env.exists("MOZ_PROFILER_STARTUP")) {
|
||||
this._resolve();
|
||||
this._resolve = null;
|
||||
return;
|
||||
}
|
||||
|
||||
Services.profiler.getProfileDataAsync().then(profileData => {
|
||||
this.data.profile = profileData;
|
||||
// There's no equivalent StartProfiler call in this file because the
|
||||
// profiler is started using the MOZ_PROFILER_STARTUP environment
|
||||
// variable in browser/base/content/test/performance/browser.ini
|
||||
Services.profiler.StopProfiler();
|
||||
|
||||
this._resolve();
|
||||
this._resolve = null;
|
||||
});
|
||||
});
|
||||
} else {
|
||||
const topicsToNames = {
|
||||
|
|
|
@ -479,8 +479,9 @@ class UrlbarView {
|
|||
favicon.src = result.payload.icon || UrlbarUtils.ICON.DEFAULT;
|
||||
}
|
||||
|
||||
let title = item._elements.get("title");
|
||||
this._addTextContentWithHighlights(
|
||||
item._elements.get("title"), result.title, result.titleHighlights);
|
||||
title, result.title, result.titleHighlights);
|
||||
|
||||
let tagsContainer = item._elements.get("tagsContainer");
|
||||
tagsContainer.textContent = "";
|
||||
|
@ -495,6 +496,7 @@ class UrlbarView {
|
|||
}
|
||||
|
||||
let action = "";
|
||||
let isVisitAction = false;
|
||||
let setURL = false;
|
||||
switch (result.type) {
|
||||
case UrlbarUtils.RESULT_TYPE.TAB_SWITCH:
|
||||
|
@ -510,21 +512,20 @@ class UrlbarView {
|
|||
[result.payload.engine], 1);
|
||||
break;
|
||||
case UrlbarUtils.RESULT_TYPE.KEYWORD:
|
||||
if (result.payload.input.trim() == result.payload.keyword) {
|
||||
action = bundle.GetStringFromName("visit");
|
||||
}
|
||||
isVisitAction = result.payload.input.trim() == result.payload.keyword;
|
||||
break;
|
||||
case UrlbarUtils.RESULT_TYPE.OMNIBOX:
|
||||
action = result.payload.content;
|
||||
break;
|
||||
default:
|
||||
if (result.heuristic) {
|
||||
action = bundle.GetStringFromName("visit");
|
||||
isVisitAction = true;
|
||||
} else {
|
||||
setURL = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
let url = item._elements.get("url");
|
||||
if (setURL) {
|
||||
this._addTextContentWithHighlights(url, result.payload.displayUrl,
|
||||
|
@ -532,7 +533,15 @@ class UrlbarView {
|
|||
} else {
|
||||
url.textContent = "";
|
||||
}
|
||||
|
||||
if (isVisitAction) {
|
||||
action = bundle.GetStringFromName("visit");
|
||||
title.setAttribute("isurl", "true");
|
||||
} else {
|
||||
title.removeAttribute("isurl");
|
||||
}
|
||||
item._elements.get("action").textContent = action;
|
||||
|
||||
item._elements.get("titleSeparator").hidden = !action && !setURL;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,13 @@ appmenu-update-manual =
|
|||
appmenu-update-manual-message = Download a fresh copy of { -brand-shorter-name } and we’ll help you to install it.
|
||||
appmenu-update-whats-new =
|
||||
.value = See what’s new.
|
||||
appmenu-update-unsupported =
|
||||
.label = { -brand-shorter-name } is unable to update to the latest version.
|
||||
.buttonlabel = Learn more
|
||||
.buttonaccesskey = L
|
||||
.secondarybuttonlabel = Close
|
||||
.secondarybuttonaccesskey = C
|
||||
appmenu-update-unsupported-message = The latest version of { -brand-shorter-name } is not supported on your system.
|
||||
appmenu-update-restart =
|
||||
.label = Restart to update { -brand-shorter-name }.
|
||||
.buttonlabel = Restart and Restore
|
||||
|
|
|
@ -924,6 +924,7 @@ you can use these alternative items. Otherwise, their values should be empty. -
|
|||
|
||||
<!ENTITY updateAvailable.panelUI.label "Download &brandShorterName; update">
|
||||
<!ENTITY updateManual.panelUI.label "Download a fresh copy of &brandShorterName;">
|
||||
<!ENTITY updateUnsupported.panelUI.label "You cannot perform further updates">
|
||||
<!ENTITY updateRestart.panelUI.label2 "Restart to update &brandShorterName;">
|
||||
|
||||
<!ENTITY newTabControlled.header.message "Your New Tab has changed.">
|
||||
|
|
|
@ -68,8 +68,8 @@
|
|||
|
||||
#PanelUI-menu-button[badge-status="update-available"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
|
||||
#PanelUI-menu-button[badge-status="update-manual"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
|
||||
#PanelUI-menu-button[badge-status="update-restart"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
|
||||
background: #74BF43 url(chrome://browser/skin/update-badge.svg) no-repeat center;
|
||||
#PanelUI-menu-button[badge-status="update-restart"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
|
||||
#PanelUI-menu-button[badge-status="update-unsupported"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
|
||||
border-radius: 50%;
|
||||
box-shadow: none;
|
||||
/* "!important" is necessary to override the rule in toolbarbutton.css */
|
||||
|
@ -79,8 +79,25 @@
|
|||
min-height: 12px;
|
||||
}
|
||||
|
||||
.panel-banner-item[notificationid^=update]::after {
|
||||
#PanelUI-menu-button[badge-status="update-available"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
|
||||
#PanelUI-menu-button[badge-status="update-manual"] > .toolbarbutton-badge-stack > .toolbarbutton-badge,
|
||||
#PanelUI-menu-button[badge-status="update-restart"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
|
||||
background: #74BF43 url(chrome://browser/skin/update-badge.svg) no-repeat center;
|
||||
}
|
||||
|
||||
#PanelUI-menu-button[badge-status="update-unsupported"] > .toolbarbutton-badge-stack > .toolbarbutton-badge {
|
||||
background: #FFE900 url(chrome://browser/skin/update-badge.svg) no-repeat center;
|
||||
}
|
||||
|
||||
.panel-banner-item[notificationid="update-available"]::after,
|
||||
.panel-banner-item[notificationid="update-manual"]::after,
|
||||
.panel-banner-item[notificationid="update-restart"]::after {
|
||||
background: #74BF43 url(chrome://browser/skin/update-badge.svg) no-repeat center;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.panel-banner-item[notificationid="update-unsupported"]::after {
|
||||
background: #FFE900 url(chrome://browser/skin/update-badge.svg) no-repeat center;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
|
@ -940,7 +957,7 @@ panelmultiview[mainViewId="PanelUI-fxa"] #PanelUI-remotetabs-syncnow {
|
|||
|
||||
:root[lwt-popup-brighttext] .panel-banner-item:not([disabled]) {
|
||||
background-color: rgba(48,230,11,.1);
|
||||
color: #F9F9FA !important;
|
||||
color: @appmenuWarningColorBrightText@ !important;
|
||||
}
|
||||
|
||||
:root[lwt-popup-brighttext] .panel-banner-item:not([disabled]):hover {
|
||||
|
@ -951,6 +968,30 @@ panelmultiview[mainViewId="PanelUI-fxa"] #PanelUI-remotetabs-syncnow {
|
|||
background-color: rgba(48,230,11,.2);
|
||||
}
|
||||
|
||||
.panel-banner-item[notificationid="update-unsupported"] {
|
||||
background-color: @appmenuWarningBackgroundColor@;
|
||||
}
|
||||
|
||||
.panel-banner-item[notificationid="update-unsupported"]:not([disabled]):hover {
|
||||
background-color: @appmenuWarningBackgroundColorHover@;
|
||||
}
|
||||
|
||||
.panel-banner-item[notificationid="update-unsupported"]:not([disabled]):hover:active {
|
||||
background-color: @appmenuWarningBackgroundColorActive@;
|
||||
}
|
||||
|
||||
:root[lwt-popup-brighttext] .panel-banner-item[notificationid="update-unsupported"]:not([disabled]) {
|
||||
background-color: @appmenuWarningBackgroundColorBrightText@;
|
||||
}
|
||||
|
||||
:root[lwt-popup-brighttext] .panel-banner-item[notificationid="update-unsupported"]:not([disabled]):hover {
|
||||
background-color: @appmenuWarningBackgroundColorHoverBrightText@;
|
||||
}
|
||||
|
||||
:root[lwt-popup-brighttext] .panel-banner-item[notificationid="update-unsupported"]:not([disabled]):active {
|
||||
background-color: @appmenuWarningBackgroundColorActiveBrightText@;
|
||||
}
|
||||
|
||||
#customization-palette .toolbarbutton-multiline-text,
|
||||
#customization-palette .toolbarbutton-text {
|
||||
display: none;
|
||||
|
|
|
@ -381,3 +381,8 @@ html|*#webRTC-previewVideo {
|
|||
background: #74BF43 url(chrome://browser/skin/notification-icons/update.svg) no-repeat center;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.popup-notification-icon[popupid="update-unsupported"] {
|
||||
background: #FFE900 url(chrome://browser/skin/notification-icons/update.svg) no-repeat center;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
|
|
@ -58,7 +58,6 @@
|
|||
border-radius: 2px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
text-align: left;
|
||||
height: 150px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
|
@ -74,7 +73,7 @@
|
|||
}
|
||||
|
||||
#editBookmarkPanelRecommendationTitle {
|
||||
font-size: 1.5rem;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
line-height: 1.25;
|
||||
margin-bottom: 6px;
|
||||
|
@ -82,7 +81,7 @@
|
|||
}
|
||||
|
||||
#editBookmarkPanelRecommendationContent {
|
||||
font-size: 1rem;
|
||||
font-size: 11px;
|
||||
line-height: 1.5;
|
||||
margin: 0;
|
||||
}
|
||||
|
@ -102,13 +101,15 @@
|
|||
|
||||
#editBookmarkPanelRecommendation #cfrClose {
|
||||
position: absolute;
|
||||
right: 18px;
|
||||
top: 18px;
|
||||
padding: 3px 2px;
|
||||
inset-inline-end: 16px;
|
||||
top: 15px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background-image: url(chrome://browser/skin/stop.svg);
|
||||
background-size: 12px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
-moz-context-properties: fill, fill-opacity;
|
||||
fill: currentColor;
|
||||
fill-opacity: 0.6;
|
||||
|
|
|
@ -72,10 +72,15 @@
|
|||
mask-image: linear-gradient(to left, transparent, black 2em);
|
||||
}
|
||||
|
||||
.urlbarView-title[overflow]:-moz-locale-dir(rtl) {
|
||||
.urlbarView-title[overflow]:not([isurl]):-moz-locale-dir(rtl) {
|
||||
mask-image: linear-gradient(to right, transparent, black 2em);
|
||||
}
|
||||
|
||||
.urlbarView-title[isurl]:-moz-locale-dir(rtl),
|
||||
.urlbarView-url:-moz-locale-dir(rtl) {
|
||||
direction: ltr !important;
|
||||
}
|
||||
|
||||
.urlbarView-row:hover {
|
||||
background: var(--arrowpanel-dimmed);
|
||||
}
|
||||
|
@ -156,10 +161,6 @@
|
|||
color: var(--urlbar-popup-url-color);
|
||||
}
|
||||
|
||||
.urlbarView-url:-moz-locale-dir(rtl) {
|
||||
direction: ltr !important;
|
||||
}
|
||||
|
||||
.urlbarView-row[selected] > .urlbarView-row-inner > .urlbarView-title-separator::before,
|
||||
.urlbarView-row[selected] > .urlbarView-row-inner > .urlbarView-secondary {
|
||||
color: inherit;
|
||||
|
|
|
@ -59,7 +59,18 @@ const {
|
|||
const CONNECTION_TIMING_OUT_DELAY = 3000;
|
||||
const CONNECTION_CANCEL_DELAY = 13000;
|
||||
|
||||
async function getRuntimeIcon(channel) {
|
||||
async function getRuntimeIcon(runtime, channel) {
|
||||
if (runtime.isFenix) {
|
||||
switch (channel) {
|
||||
case "release":
|
||||
case "beta":
|
||||
return "chrome://devtools/skin/images/aboutdebugging-fenix.svg";
|
||||
case "aurora":
|
||||
default:
|
||||
return "chrome://devtools/skin/images/aboutdebugging-fenix-nightly.svg";
|
||||
}
|
||||
}
|
||||
|
||||
return (channel === "release" || channel === "beta" || channel === "aurora")
|
||||
? `chrome://devtools/skin/images/aboutdebugging-firefox-${ channel }.svg`
|
||||
: "chrome://devtools/skin/images/aboutdebugging-firefox-nightly.svg";
|
||||
|
@ -107,7 +118,7 @@ function connectRuntime(id) {
|
|||
|
||||
const deviceDescription = await clientWrapper.getDeviceDescription();
|
||||
const compatibilityReport = await clientWrapper.checkVersionCompatibility();
|
||||
const icon = await getRuntimeIcon(deviceDescription.channel);
|
||||
const icon = await getRuntimeIcon(runtime, deviceDescription.channel);
|
||||
|
||||
const {
|
||||
CHROME_DEBUG_ENABLED,
|
||||
|
@ -129,6 +140,19 @@ function connectRuntime(id) {
|
|||
await clientWrapper.getPreference(SERVICE_WORKERS_ENABLED, true);
|
||||
const serviceWorkersAvailable = serviceWorkersEnabled && !privateBrowsing;
|
||||
|
||||
// Fenix specific workarounds are needed until we can get proper server side APIs
|
||||
// to detect Fenix and get the proper application names and versions.
|
||||
// See https://github.com/mozilla-mobile/fenix/issues/2016.
|
||||
|
||||
// For Fenix runtimes, the ADB runtime name is more accurate than the one returned
|
||||
// by the Device actor.
|
||||
const runtimeName = runtime.isFenix ? runtime.name : deviceDescription.name;
|
||||
|
||||
// For Fenix runtimes, the version we should display is the application version
|
||||
// retrieved from ADB, and not the Gecko version returned by the Device actor.
|
||||
const version = runtime.isFenix ?
|
||||
runtime.extra.adbPackageVersion : deviceDescription.version;
|
||||
|
||||
const runtimeDetails = {
|
||||
clientWrapper,
|
||||
compatibilityReport,
|
||||
|
@ -137,10 +161,10 @@ function connectRuntime(id) {
|
|||
info: {
|
||||
deviceName: deviceDescription.deviceName,
|
||||
icon,
|
||||
name: deviceDescription.name,
|
||||
name: runtimeName,
|
||||
os: deviceDescription.os,
|
||||
type: runtime.type,
|
||||
version: deviceDescription.version,
|
||||
version,
|
||||
},
|
||||
isMultiE10s: deviceDescription.isMultiE10s,
|
||||
serviceWorkersAvailable,
|
||||
|
@ -345,6 +369,7 @@ function updateNetworkRuntimes(locations) {
|
|||
isConnectionFailed: false,
|
||||
isConnectionNotResponding: false,
|
||||
isConnectionTimeout: false,
|
||||
isFenix: false,
|
||||
isUnavailable: false,
|
||||
isUnplugged: false,
|
||||
isUnknown: false,
|
||||
|
@ -366,11 +391,13 @@ function updateUSBRuntimes(adbRuntimes) {
|
|||
extra: {
|
||||
connectionParameters,
|
||||
deviceName: adbRuntime.deviceName,
|
||||
adbPackageVersion: adbRuntime.versionName,
|
||||
},
|
||||
isConnecting: false,
|
||||
isConnectionFailed: false,
|
||||
isConnectionNotResponding: false,
|
||||
isConnectionTimeout: false,
|
||||
isFenix: adbRuntime.isFenix,
|
||||
isUnavailable: adbRuntime.isUnavailable,
|
||||
isUnplugged: adbRuntime.isUnplugged,
|
||||
name: adbRuntime.shortName,
|
||||
|
|
|
@ -37,7 +37,7 @@ class RuntimeInfo extends PureComponent {
|
|||
},
|
||||
dom.img(
|
||||
{
|
||||
className: "main-heading__icon runtime-info__icon",
|
||||
className: "main-heading__icon runtime-info__icon qa-runtime-icon",
|
||||
src: icon,
|
||||
}
|
||||
),
|
||||
|
|
|
@ -16,8 +16,10 @@ class UsbRuntime {
|
|||
this.deviceName = adbRuntime.deviceName;
|
||||
this.shortName = adbRuntime.shortName;
|
||||
this.socketPath = adbRuntime.socketPath;
|
||||
this.isFenix = adbRuntime.isFenix;
|
||||
this.isUnavailable = false;
|
||||
this.isUnplugged = false;
|
||||
this.versionName = adbRuntime.versionName;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,8 +34,10 @@ class UnavailableUsbRuntime {
|
|||
this.deviceName = adbDevice.name;
|
||||
this.shortName = "Unavailable runtime";
|
||||
this.socketPath = null;
|
||||
this.isFenix = false;
|
||||
this.isUnavailable = true;
|
||||
this.isUnplugged = false;
|
||||
this.versionName = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,8 +52,10 @@ class UnpluggedUsbRuntime {
|
|||
this.deviceName = deviceName;
|
||||
this.shortName = "Unplugged runtime";
|
||||
this.socketPath = null;
|
||||
this.isFenix = false;
|
||||
this.isUnavailable = true;
|
||||
this.isUnplugged = true;
|
||||
this.versionName = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -105,7 +105,12 @@ function runtimesReducer(state = RuntimesState(), action) {
|
|||
|
||||
case CONNECT_RUNTIME_SUCCESS: {
|
||||
const { id, runtimeDetails, type } = action.runtime;
|
||||
remoteClientManager.setClient(id, type, runtimeDetails.clientWrapper.client);
|
||||
|
||||
// Update the remoteClientManager with the connected runtime.
|
||||
const client = runtimeDetails.clientWrapper.client;
|
||||
const runtimeInfo = runtimeDetails.info;
|
||||
remoteClientManager.setClient(id, type, client, runtimeInfo);
|
||||
|
||||
const updatedState = {
|
||||
isConnecting: false,
|
||||
isConnectionFailed: false,
|
||||
|
|
|
@ -105,6 +105,10 @@ const runtimeExtra = {
|
|||
// device name
|
||||
// unavailable on this-firefox and network-location runtimes
|
||||
deviceName: PropTypes.string,
|
||||
|
||||
// version of the application coming from ADB, only available via USB. Useful for Fenix
|
||||
// runtimes, because the version can't be retrieved from Service.appInfo.
|
||||
adbPackageVersion: PropTypes.string,
|
||||
};
|
||||
|
||||
const runtime = {
|
||||
|
@ -129,6 +133,11 @@ const runtime = {
|
|||
// this flag will be true when the connection was timeout.
|
||||
isConnectionTimeout: PropTypes.bool.isRequired,
|
||||
|
||||
// this flag will be true when the detected runtime is Fenix (Firefox Preview).
|
||||
// Fenix need specific logic to get their display name, version and logos.
|
||||
// Discussion ongoing in https://github.com/mozilla-mobile/fenix/issues/2016
|
||||
isFenix: PropTypes.bool.isRequired,
|
||||
|
||||
// unavailable runtimes are placeholders for devices where the runtime has not been
|
||||
// started yet. For instance an ADB device connected without a compatible runtime
|
||||
// running.
|
||||
|
|
|
@ -70,6 +70,7 @@ skip-if = (os == "win" && ccov) # Bug 1521349
|
|||
[browser_aboutdebugging_devtoolstoolbox_target_destroyed.js]
|
||||
skip-if = debug || asan # This test leaks. See bug 1529005
|
||||
[browser_aboutdebugging_devtoolstoolbox_tooltip_markupview.js]
|
||||
[browser_aboutdebugging_fenix_runtime_display.js]
|
||||
[browser_aboutdebugging_message_close.js]
|
||||
[browser_aboutdebugging_navigate.js]
|
||||
[browser_aboutdebugging_persist_connection.js]
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const RUNTIME_ID = "1337id";
|
||||
const DEVICE_NAME = "Fancy Phone";
|
||||
const SERVER_RUNTIME_NAME = "Mozilla Firefox";
|
||||
const ADB_RUNTIME_NAME = "Firefox Preview";
|
||||
const SERVER_VERSION = "v7.3.31";
|
||||
const ADB_VERSION = "v1.3.37";
|
||||
|
||||
const FENIX_RELEASE_ICON_SRC = "chrome://devtools/skin/images/aboutdebugging-fenix.svg";
|
||||
const FENIX_NIGHTLY_ICON_SRC =
|
||||
"chrome://devtools/skin/images/aboutdebugging-fenix-nightly.svg";
|
||||
|
||||
/**
|
||||
* Check that Fenix runtime information is correctly displayed in about:debugging.
|
||||
*/
|
||||
add_task(async function() {
|
||||
const mocks = new Mocks();
|
||||
mocks.createUSBRuntime(RUNTIME_ID, {
|
||||
deviceName: DEVICE_NAME,
|
||||
isFenix: true,
|
||||
name: SERVER_RUNTIME_NAME,
|
||||
shortName: ADB_RUNTIME_NAME,
|
||||
versionName: ADB_VERSION,
|
||||
version: SERVER_VERSION,
|
||||
});
|
||||
|
||||
// open a remote runtime page
|
||||
const { document, tab, window } = await openAboutDebugging();
|
||||
await selectThisFirefoxPage(document, window.AboutDebugging.store);
|
||||
|
||||
mocks.emitUSBUpdate();
|
||||
await connectToRuntime(DEVICE_NAME, document);
|
||||
await selectRuntime(DEVICE_NAME, ADB_RUNTIME_NAME, document);
|
||||
|
||||
info("Check that the runtime information is displayed as expected");
|
||||
const runtimeInfo = document.querySelector(".qa-runtime-name");
|
||||
ok(runtimeInfo, "Runtime info for the Fenix runtime is displayed");
|
||||
const runtimeInfoText = runtimeInfo.textContent;
|
||||
|
||||
ok(runtimeInfoText.includes(ADB_RUNTIME_NAME), "Name is the ADB name");
|
||||
ok(!runtimeInfoText.includes(SERVER_RUNTIME_NAME),
|
||||
"Name does not include the server name");
|
||||
|
||||
ok(runtimeInfoText.includes(ADB_VERSION), "Version contains the ADB version");
|
||||
ok(!runtimeInfoText.includes(SERVER_VERSION),
|
||||
"Version does not contain the server version");
|
||||
|
||||
const runtimeIcon = document.querySelector(".qa-runtime-icon");
|
||||
is(runtimeIcon.src, FENIX_RELEASE_ICON_SRC, "The runtime icon is the Fenix icon");
|
||||
|
||||
info("Remove USB runtime");
|
||||
mocks.removeUSBRuntime(RUNTIME_ID);
|
||||
mocks.emitUSBUpdate();
|
||||
await waitUntilUsbDeviceIsUnplugged(DEVICE_NAME, document);
|
||||
|
||||
await removeTab(tab);
|
||||
});
|
||||
|
||||
/**
|
||||
* Check that Fenix runtime information is correctly displayed in about:devtools-toolbox.
|
||||
*/
|
||||
add_task(async function() {
|
||||
// We use a real local client combined with a mocked USB runtime to be able to open
|
||||
// about:devtools-toolbox on a real target.
|
||||
const clientWrapper = await createLocalClientWrapper();
|
||||
|
||||
// Mock getDeviceDescription() to force the local client to return "nightly" as the
|
||||
// channel. Otherwise the value of the icon source would depend on the current channel.
|
||||
const deviceDescription = await clientWrapper.getDeviceDescription();
|
||||
clientWrapper.getDeviceDescription = function() {
|
||||
return Object.assign({}, deviceDescription, {
|
||||
channel: "nightly",
|
||||
});
|
||||
};
|
||||
|
||||
const mocks = new Mocks();
|
||||
mocks.createUSBRuntime(RUNTIME_ID, {
|
||||
clientWrapper: clientWrapper,
|
||||
deviceName: DEVICE_NAME,
|
||||
isFenix: true,
|
||||
name: SERVER_RUNTIME_NAME,
|
||||
shortName: ADB_RUNTIME_NAME,
|
||||
versionName: ADB_VERSION,
|
||||
version: SERVER_VERSION,
|
||||
});
|
||||
|
||||
// open a remote runtime page
|
||||
const { document, tab, window } = await openAboutDebugging();
|
||||
await selectThisFirefoxPage(document, window.AboutDebugging.store);
|
||||
|
||||
mocks.emitUSBUpdate();
|
||||
info("Select the runtime page for the USB runtime");
|
||||
const onRequestSuccess = waitForRequestsSuccess(window.AboutDebugging.store);
|
||||
await connectToRuntime(DEVICE_NAME, document);
|
||||
await selectRuntime(DEVICE_NAME, ADB_RUNTIME_NAME, document);
|
||||
|
||||
info("Wait for requests to finish the USB runtime is backed by a real local client");
|
||||
await onRequestSuccess;
|
||||
|
||||
info("Wait for the about:debugging target to be available");
|
||||
await waitUntil(() => findDebugTargetByText("about:debugging", document));
|
||||
const { devtoolsDocument, devtoolsTab } =
|
||||
await openAboutDevtoolsToolbox(document, tab, window);
|
||||
|
||||
const runtimeInfo = devtoolsDocument.querySelector(".qa-runtime-info");
|
||||
const runtimeInfoText = runtimeInfo.textContent;
|
||||
ok(runtimeInfoText.includes(ADB_RUNTIME_NAME), "Name is the ADB runtime name");
|
||||
ok(runtimeInfoText.includes(ADB_VERSION), "Version is the ADB version");
|
||||
|
||||
const runtimeIcon = devtoolsDocument.querySelector(".qa-runtime-icon");
|
||||
is(runtimeIcon.src, FENIX_NIGHTLY_ICON_SRC, "The runtime icon is the Fenix icon");
|
||||
|
||||
info("Wait for all pending requests to settle on the DebuggerClient");
|
||||
await clientWrapper.client.waitForRequestsToSettle();
|
||||
|
||||
await closeAboutDevtoolsToolbox(document, devtoolsTab, window);
|
||||
|
||||
info("Remove USB runtime");
|
||||
mocks.removeUSBRuntime(RUNTIME_ID);
|
||||
mocks.emitUSBUpdate();
|
||||
await waitUntilUsbDeviceIsUnplugged(DEVICE_NAME, document);
|
||||
|
||||
await removeTab(tab);
|
||||
await clientWrapper.close();
|
||||
});
|
||||
|
||||
async function createLocalClientWrapper() {
|
||||
info("Create a local DebuggerClient");
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
const { DebuggerClient } = require("devtools/shared/client/debugger-client");
|
||||
const { ClientWrapper } =
|
||||
require("devtools/client/aboutdebugging-new/src/modules/client-wrapper");
|
||||
|
||||
DebuggerServer.init();
|
||||
DebuggerServer.registerAllActors();
|
||||
const client = new DebuggerClient(DebuggerServer.connectPipe());
|
||||
|
||||
await client.connect();
|
||||
return new ClientWrapper(client);
|
||||
}
|
|
@ -124,34 +124,44 @@ class Mocks {
|
|||
* The id of the runtime.
|
||||
* @param {Object} optional object used to create the fake runtime & device
|
||||
* - channel: {String} Release channel, for instance "release", "nightly"
|
||||
* - clientWrapper: {ClientWrapper} optional ClientWrapper for this runtime
|
||||
* - deviceId: {String} Device id
|
||||
* - deviceName: {String} Device name
|
||||
* - isFenix: {Boolean} set by ADB if the package name matches a Fenix package
|
||||
* - name: {String} Application name, for instance "Firefox"
|
||||
* - shortName: {String} Short name for the device
|
||||
* - socketPath: {String} (should only be used for connecting, so not here)
|
||||
* - version: {String} Version, for instance "63.0a"
|
||||
* - versionName: {String} Version return by ADB "63.0a"
|
||||
* @return {Object} Returns the mock client created for this runtime so that methods
|
||||
* can be overridden on it.
|
||||
*/
|
||||
createUSBRuntime(id, runtimeInfo = {}) {
|
||||
// Add a new runtime to the list of scanned runtimes.
|
||||
this._usbRuntimes.push({
|
||||
id: id,
|
||||
socketPath: runtimeInfo.socketPath || "test/path",
|
||||
deviceId: runtimeInfo.deviceId || "test device id",
|
||||
deviceName: runtimeInfo.deviceName || "test device name",
|
||||
id: id,
|
||||
isFenix: runtimeInfo.isFenix,
|
||||
shortName: runtimeInfo.shortName || "testshort",
|
||||
socketPath: runtimeInfo.socketPath || "test/path",
|
||||
versionName: runtimeInfo.versionName || "1.0",
|
||||
});
|
||||
|
||||
// Add a valid client that can be returned for this particular runtime id.
|
||||
const mockUsbClient = createClientMock();
|
||||
mockUsbClient.getDeviceDescription = () => {
|
||||
return {
|
||||
channel: runtimeInfo.channel || "release",
|
||||
name: runtimeInfo.name || "TestBrand",
|
||||
version: runtimeInfo.version || "1.0",
|
||||
let mockUsbClient = runtimeInfo.clientWrapper;
|
||||
if (!mockUsbClient) {
|
||||
// If no clientWrapper was provided, create a mock client here.
|
||||
mockUsbClient = createClientMock();
|
||||
mockUsbClient.getDeviceDescription = () => {
|
||||
return {
|
||||
channel: runtimeInfo.channel || "release",
|
||||
name: runtimeInfo.name || "TestBrand",
|
||||
version: runtimeInfo.version || "1.0",
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
this._clients[RUNTIMES.USB][id] = mockUsbClient;
|
||||
|
||||
return mockUsbClient;
|
||||
|
|
|
@ -18,10 +18,10 @@ class DebugTargetInfo extends PureComponent {
|
|||
return {
|
||||
debugTargetData: PropTypes.shape({
|
||||
connectionType: PropTypes.oneOf(Object.values(CONNECTION_TYPES)).isRequired,
|
||||
deviceDescription: PropTypes.shape({
|
||||
brandName: PropTypes.string.isRequired,
|
||||
channel: PropTypes.string.isRequired,
|
||||
runtimeInfo: PropTypes.shape({
|
||||
deviceName: PropTypes.string,
|
||||
icon: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
version: PropTypes.string.isRequired,
|
||||
}).isRequired,
|
||||
targetType: PropTypes.oneOf(Object.values(DEBUG_TARGET_TYPES)).isRequired,
|
||||
|
@ -58,12 +58,12 @@ class DebugTargetInfo extends PureComponent {
|
|||
|
||||
getRuntimeText() {
|
||||
const { debugTargetData, L10N } = this.props;
|
||||
const { brandName, version } = debugTargetData.deviceDescription;
|
||||
const { name, version } = debugTargetData.runtimeInfo;
|
||||
const { connectionType } = debugTargetData;
|
||||
|
||||
return (connectionType === CONNECTION_TYPES.THIS_FIREFOX)
|
||||
? L10N.getFormatStr("toolbox.debugTargetInfo.runtimeLabel.thisFirefox", version)
|
||||
: L10N.getFormatStr("toolbox.debugTargetInfo.runtimeLabel", brandName, version);
|
||||
: L10N.getFormatStr("toolbox.debugTargetInfo.runtimeLabel", name, version);
|
||||
}
|
||||
|
||||
getAssetsForConnectionType() {
|
||||
|
@ -143,18 +143,20 @@ class DebugTargetInfo extends PureComponent {
|
|||
}
|
||||
|
||||
renderRuntime() {
|
||||
const { channel, deviceName } = this.props.debugTargetData.deviceDescription;
|
||||
if (!this.props.debugTargetData.runtimeInfo) {
|
||||
// Skip the runtime render if no runtimeInfo is available.
|
||||
// Runtime info is retrieved from the remote-client-manager, which might not be
|
||||
// setup if about:devtools-toolbox was not opened from about:debugging.
|
||||
return null;
|
||||
}
|
||||
|
||||
const channelIcon =
|
||||
(channel === "release" || channel === "beta" || channel === "aurora") ?
|
||||
`chrome://devtools/skin/images/aboutdebugging-firefox-${ channel }.svg` :
|
||||
"chrome://devtools/skin/images/aboutdebugging-firefox-nightly.svg";
|
||||
const { icon, deviceName } = this.props.debugTargetData.runtimeInfo;
|
||||
|
||||
return dom.span(
|
||||
{
|
||||
className: "iconized-label",
|
||||
className: "iconized-label qa-runtime-info",
|
||||
},
|
||||
dom.img({ src: channelIcon, className: "channel-icon" }),
|
||||
dom.img({ src: icon, className: "channel-icon qa-runtime-icon" }),
|
||||
dom.b({ className: "devtools-ellipsis-text" }, this.getRuntimeText()),
|
||||
dom.span({ className: "devtools-ellipsis-text" }, deviceName),
|
||||
);
|
||||
|
|
|
@ -98,7 +98,7 @@ class ToolboxToolbar extends Component {
|
|||
visibleToolboxButtonCount: PropTypes.number,
|
||||
// Data to show debug target info, if needed
|
||||
debugTargetData: PropTypes.shape({
|
||||
deviceDescription: PropTypes.object.isRequired,
|
||||
runtimeInfo: PropTypes.object.isRequired,
|
||||
targetType: PropTypes.string.isRequired,
|
||||
}),
|
||||
};
|
||||
|
|
|
@ -13,7 +13,7 @@ add_task(async function() {
|
|||
info("Preload a local DebuggerClient as this-firefox in the remoteClientManager");
|
||||
const { remoteClientManager } =
|
||||
require("devtools/client/shared/remote-debugging/remote-client-manager");
|
||||
remoteClientManager.setClient("this-firefox", "this-firefox", debuggerClient);
|
||||
remoteClientManager.setClient("this-firefox", "this-firefox", debuggerClient, {});
|
||||
registerCleanupFunction(() => {
|
||||
remoteClientManager.removeAllClients();
|
||||
});
|
||||
|
|
|
@ -14,10 +14,10 @@ exports[`DebugTargetInfo component Connection info renders the expected snapshot
|
|||
toolbox.debugTargetInfo.connection.usb
|
||||
</span>
|
||||
<span
|
||||
className="iconized-label"
|
||||
className="iconized-label qa-runtime-info"
|
||||
>
|
||||
<img
|
||||
className="channel-icon"
|
||||
className="channel-icon qa-runtime-icon"
|
||||
src="chrome://devtools/skin/images/aboutdebugging-firefox-release.svg"
|
||||
/>
|
||||
<b
|
||||
|
@ -66,10 +66,10 @@ exports[`DebugTargetInfo component Target icon renders the expected snapshot for
|
|||
toolbox.debugTargetInfo.connection.usb
|
||||
</span>
|
||||
<span
|
||||
className="iconized-label"
|
||||
className="iconized-label qa-runtime-info"
|
||||
>
|
||||
<img
|
||||
className="channel-icon"
|
||||
className="channel-icon qa-runtime-icon"
|
||||
src="chrome://devtools/skin/images/aboutdebugging-firefox-release.svg"
|
||||
/>
|
||||
<b
|
||||
|
@ -118,10 +118,10 @@ exports[`DebugTargetInfo component Target icon renders the expected snapshot for
|
|||
toolbox.debugTargetInfo.connection.usb
|
||||
</span>
|
||||
<span
|
||||
className="iconized-label"
|
||||
className="iconized-label qa-runtime-info"
|
||||
>
|
||||
<img
|
||||
className="channel-icon"
|
||||
className="channel-icon qa-runtime-icon"
|
||||
src="chrome://devtools/skin/images/aboutdebugging-firefox-release.svg"
|
||||
/>
|
||||
<b
|
||||
|
@ -170,10 +170,10 @@ exports[`DebugTargetInfo component Target icon renders the expected snapshot for
|
|||
toolbox.debugTargetInfo.connection.usb
|
||||
</span>
|
||||
<span
|
||||
className="iconized-label"
|
||||
className="iconized-label qa-runtime-info"
|
||||
>
|
||||
<img
|
||||
className="channel-icon"
|
||||
className="channel-icon qa-runtime-icon"
|
||||
src="chrome://devtools/skin/images/aboutdebugging-firefox-release.svg"
|
||||
/>
|
||||
<b
|
||||
|
@ -222,10 +222,10 @@ exports[`DebugTargetInfo component Target icon renders the expected snapshot for
|
|||
toolbox.debugTargetInfo.connection.usb
|
||||
</span>
|
||||
<span
|
||||
className="iconized-label"
|
||||
className="iconized-label qa-runtime-info"
|
||||
>
|
||||
<img
|
||||
className="channel-icon"
|
||||
className="channel-icon qa-runtime-icon"
|
||||
src="chrome://devtools/skin/images/aboutdebugging-firefox-release.svg"
|
||||
/>
|
||||
<b
|
||||
|
@ -265,10 +265,10 @@ exports[`DebugTargetInfo component Target title renders the expected snapshot fo
|
|||
className="debug-target-info qa-debug-target-info"
|
||||
>
|
||||
<span
|
||||
className="iconized-label"
|
||||
className="iconized-label qa-runtime-info"
|
||||
>
|
||||
<img
|
||||
className="channel-icon"
|
||||
className="channel-icon qa-runtime-icon"
|
||||
src="chrome://devtools/skin/images/aboutdebugging-firefox-release.svg"
|
||||
/>
|
||||
<b
|
||||
|
@ -306,10 +306,10 @@ exports[`DebugTargetInfo component Target title renders the expected snapshot fo
|
|||
className="debug-target-info qa-debug-target-info"
|
||||
>
|
||||
<span
|
||||
className="iconized-label"
|
||||
className="iconized-label qa-runtime-info"
|
||||
>
|
||||
<img
|
||||
className="channel-icon"
|
||||
className="channel-icon qa-runtime-icon"
|
||||
src="chrome://devtools/skin/images/aboutdebugging-firefox-release.svg"
|
||||
/>
|
||||
<b
|
||||
|
|
|
@ -32,31 +32,33 @@ const TEST_TOOLBOX = {
|
|||
name: "Test Tab Name",
|
||||
url: "http://some.target/url",
|
||||
},
|
||||
doc: {},
|
||||
};
|
||||
|
||||
const TEST_TOOLBOX_NO_NAME = {
|
||||
target: {
|
||||
url: "http://some.target/without/a/name",
|
||||
},
|
||||
doc: {},
|
||||
};
|
||||
|
||||
const USB_DEVICE_DESCRIPTION = {
|
||||
brandName: "usbRuntimeBrandName",
|
||||
channel: "release",
|
||||
deviceName: "usbDeviceName",
|
||||
icon: "chrome://devtools/skin/images/aboutdebugging-firefox-release.svg",
|
||||
name: "usbRuntimeBrandName",
|
||||
version: "1.0.0",
|
||||
};
|
||||
|
||||
const THIS_FIREFOX_DEVICE_DESCRIPTION = {
|
||||
brandName: "thisFirefoxRuntimeBrandName",
|
||||
channel: "release",
|
||||
icon: "chrome://devtools/skin/images/aboutdebugging-firefox-release.svg",
|
||||
version: "1.0.0",
|
||||
name: "thisFirefoxRuntimeBrandName",
|
||||
};
|
||||
|
||||
const USB_TARGET_INFO = {
|
||||
debugTargetData: {
|
||||
connectionType: CONNECTION_TYPES.USB,
|
||||
deviceDescription: USB_DEVICE_DESCRIPTION,
|
||||
runtimeInfo: USB_DEVICE_DESCRIPTION,
|
||||
targetType: DEBUG_TARGET_TYPES.TAB,
|
||||
},
|
||||
toolbox: TEST_TOOLBOX,
|
||||
|
@ -66,7 +68,7 @@ const USB_TARGET_INFO = {
|
|||
const THIS_FIREFOX_TARGET_INFO = {
|
||||
debugTargetData: {
|
||||
connectionType: CONNECTION_TYPES.THIS_FIREFOX,
|
||||
deviceDescription: THIS_FIREFOX_DEVICE_DESCRIPTION,
|
||||
runtimeInfo: THIS_FIREFOX_DEVICE_DESCRIPTION,
|
||||
targetType: DEBUG_TARGET_TYPES.TAB,
|
||||
},
|
||||
toolbox: TEST_TOOLBOX,
|
||||
|
@ -76,7 +78,7 @@ const THIS_FIREFOX_TARGET_INFO = {
|
|||
const THIS_FIREFOX_NO_NAME_TARGET_INFO = {
|
||||
debugTargetData: {
|
||||
connectionType: CONNECTION_TYPES.THIS_FIREFOX,
|
||||
deviceDescription: THIS_FIREFOX_DEVICE_DESCRIPTION,
|
||||
runtimeInfo: THIS_FIREFOX_DEVICE_DESCRIPTION,
|
||||
targetType: DEBUG_TARGET_TYPES.TAB,
|
||||
},
|
||||
toolbox: TEST_TOOLBOX_NO_NAME,
|
||||
|
|
|
@ -463,7 +463,7 @@ Toolbox.prototype = {
|
|||
// Displays DebugTargetInfo which shows the basic information of debug target,
|
||||
// if `about:devtools-toolbox` URL opens directly.
|
||||
// DebugTargetInfo requires this._debugTargetData to be populated
|
||||
this._debugTargetData = await this._getDebugTargetData();
|
||||
this._debugTargetData = this._getDebugTargetData();
|
||||
}
|
||||
|
||||
const domHelper = new DOMHelpers(this.win);
|
||||
|
@ -794,20 +794,19 @@ Toolbox.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
_getDebugTargetData: async function() {
|
||||
_getDebugTargetData: function() {
|
||||
const url = new URL(this.win.location);
|
||||
const searchParams = new this.win.URLSearchParams(url.search);
|
||||
|
||||
const targetType = searchParams.get("type") || DEBUG_TARGET_TYPES.TAB;
|
||||
|
||||
const deviceFront = await this.target.client.mainRoot.getFront("device");
|
||||
const deviceDescription = await deviceFront.getDescription();
|
||||
const remoteId = searchParams.get("remoteId");
|
||||
const runtimeInfo = remoteClientManager.getRuntimeInfoByRemoteId(remoteId);
|
||||
const connectionType = remoteClientManager.getConnectionTypeByRemoteId(remoteId);
|
||||
|
||||
return {
|
||||
connectionType,
|
||||
deviceDescription,
|
||||
runtimeInfo,
|
||||
targetType,
|
||||
};
|
||||
},
|
||||
|
|
|
@ -75,6 +75,8 @@ devtools.jar:
|
|||
skin/images/checkbox.svg (themes/images/checkbox.svg)
|
||||
skin/images/filter-swatch.svg (themes/images/filter-swatch.svg)
|
||||
skin/images/aboutdebugging-connect-icon.svg (themes/images/aboutdebugging-connect-icon.svg)
|
||||
skin/images/aboutdebugging-fenix-nightly.svg (themes/images/aboutdebugging-fenix-nightly.svg)
|
||||
skin/images/aboutdebugging-fenix.svg (themes/images/aboutdebugging-fenix.svg)
|
||||
skin/images/aboutdebugging-firefox-aurora.svg (themes/images/aboutdebugging-firefox-aurora.svg)
|
||||
skin/images/aboutdebugging-firefox-beta.svg (themes/images/aboutdebugging-firefox-beta.svg)
|
||||
skin/images/aboutdebugging-firefox-logo.svg (themes/images/aboutdebugging-firefox-logo.svg)
|
||||
|
|
|
@ -30,8 +30,6 @@ const SWAPPED_BROWSER_STATE = [
|
|||
"_characterSet",
|
||||
"_contentPrincipal",
|
||||
"_imageDocument",
|
||||
"_fullZoom",
|
||||
"_textZoom",
|
||||
"_isSyntheticDocument",
|
||||
"_innerWindowID",
|
||||
];
|
||||
|
|
|
@ -352,6 +352,25 @@ ResponsiveUI.prototype = {
|
|||
debug("Wait until swap start");
|
||||
await this.swap.start();
|
||||
|
||||
// Set the ui toolWindow to fullZoom and textZoom of 100%. Directly change
|
||||
// the zoom levels of the toolwindow docshell. That doesn't affect the zoom
|
||||
// of the RDM content, but it does send events that confuse the Zoom UI.
|
||||
// So before we adjust the zoom levels of the toolWindow, we first cache
|
||||
// the reported zoom levels of the RDM content, because we'll have to
|
||||
// re-apply them to re-sync the Zoom UI.
|
||||
|
||||
// Cache the values now and we'll re-apply them near the end of this function.
|
||||
// This is important since other steps here can also cause the Zoom UI update
|
||||
// event to be sent for other browsers, and this means that the changes from
|
||||
// our Zoom UI update event would be overwritten. After this function, future
|
||||
// changes to zoom levels will send Zoom UI update events in an order that
|
||||
// keeps the Zoom UI synchronized with the RDM content zoom levels.
|
||||
const fullZoom = this.tab.linkedBrowser.fullZoom;
|
||||
const textZoom = this.tab.linkedBrowser.textZoom;
|
||||
|
||||
ui.toolWindow.docShell.contentViewer.fullZoom = 1;
|
||||
ui.toolWindow.docShell.contentViewer.textZoom = 1;
|
||||
|
||||
this.tab.addEventListener("BeforeTabRemotenessChange", this);
|
||||
|
||||
// Notify the inner browser to start the frame script
|
||||
|
@ -371,6 +390,11 @@ ResponsiveUI.prototype = {
|
|||
new SettingOnboardingTooltip(ui.toolWindow.document);
|
||||
}
|
||||
|
||||
// Re-apply our cached zoom levels. Other Zoom UI update events have finished
|
||||
// by now.
|
||||
this.tab.linkedBrowser.fullZoom = fullZoom;
|
||||
this.tab.linkedBrowser.textZoom = textZoom;
|
||||
|
||||
// Non-blocking message to tool UI to start any delayed init activities
|
||||
message.post(this.toolWindow, "post-init");
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ function setZoomForBrowser(browser, zoom) {
|
|||
|
||||
add_task(async function() {
|
||||
const INITIAL_ZOOM_LEVEL = 1;
|
||||
const PRE_RDM_ZOOM_LEVEL = 1.5;
|
||||
const MID_RDM_ZOOM_LEVEL = 2;
|
||||
|
||||
const tab = await addTab(TEST_URL);
|
||||
|
@ -24,8 +25,17 @@ add_task(async function() {
|
|||
|
||||
await load(browser, TEST_URL);
|
||||
|
||||
// Get the initial zoom level.
|
||||
const initialOuterZoom = getZoomForBrowser(browser);
|
||||
is(initialOuterZoom, INITIAL_ZOOM_LEVEL, "Initial outer zoom should be " +
|
||||
INITIAL_ZOOM_LEVEL + ".");
|
||||
|
||||
// Change the zoom level before we open RDM.
|
||||
setZoomForBrowser(browser, INITIAL_ZOOM_LEVEL);
|
||||
setZoomForBrowser(browser, PRE_RDM_ZOOM_LEVEL);
|
||||
|
||||
const preRDMOuterZoom = getZoomForBrowser(browser);
|
||||
is(preRDMOuterZoom, PRE_RDM_ZOOM_LEVEL, "Pre-RDM outer zoom should be " +
|
||||
PRE_RDM_ZOOM_LEVEL + ".");
|
||||
|
||||
// Start RDM on the tab. This will fundamentally change the way that browser behaves.
|
||||
// It will now pass all of its messages through to the RDM docshell, meaning that when
|
||||
|
@ -37,18 +47,18 @@ add_task(async function() {
|
|||
// interactively. Interactively, many features of the container docShell -- including
|
||||
// zoom -- are copied over to the RDM browser. In the test harness, this seems to first
|
||||
// reset the docShell before toggling RDM, which makes checking the initial zoom of the
|
||||
// UI and the RDM pane not useful.
|
||||
// RDM pane not useful.
|
||||
|
||||
const initialUIZoom = uiDocShell.contentViewer.fullZoom;
|
||||
isnot(initialUIZoom, MID_RDM_ZOOM_LEVEL,
|
||||
"We should have a different UI initial zoom, so we can ensure it stays unchanged.");
|
||||
const preZoomUIZoom = uiDocShell.contentViewer.fullZoom;
|
||||
is(preZoomUIZoom, INITIAL_ZOOM_LEVEL,
|
||||
"Pre-zoom UI zoom should be " + INITIAL_ZOOM_LEVEL + ".");
|
||||
|
||||
// Set the zoom level. This should tunnel to the inner browser and leave the UI alone.
|
||||
setZoomForBrowser(browser, MID_RDM_ZOOM_LEVEL);
|
||||
|
||||
// The UI zoom should be unchanged by this.
|
||||
const postZoomUIZoom = uiDocShell.contentViewer.fullZoom;
|
||||
is(postZoomUIZoom, initialUIZoom, "UI zoom should be unchanged by RDM zoom.");
|
||||
is(postZoomUIZoom, preZoomUIZoom, "UI zoom should be unchanged by RDM zoom.");
|
||||
|
||||
// The RDM zoom should be changed.
|
||||
const finalRDMZoom = getZoomForBrowser(browser);
|
||||
|
@ -56,4 +66,8 @@ add_task(async function() {
|
|||
|
||||
// Leave RDM. This should cause the outer pane to take on the full zoom of the RDM pane.
|
||||
await closeRDM(tab);
|
||||
|
||||
// Bug 1541692: the following todo_is check will become an is check when this bug lands.
|
||||
const finalOuterZoom = getZoomForBrowser(browser);
|
||||
todo_is(finalOuterZoom, finalRDMZoom, "Final outer zoom should match last RDM zoom.");
|
||||
});
|
||||
|
|
|
@ -13,6 +13,7 @@ const { CONNECTION_TYPES } = require("devtools/client/shared/remote-debugging/co
|
|||
class RemoteClientManager {
|
||||
constructor() {
|
||||
this._clients = new Map();
|
||||
this._runtimeInfoMap = new Map();
|
||||
this._onClientClosed = this._onClientClosed.bind(this);
|
||||
}
|
||||
|
||||
|
@ -24,10 +25,15 @@ class RemoteClientManager {
|
|||
* @param {String} type
|
||||
* Remote runtime type (see devtools/client/aboutdebugging-new/src/types).
|
||||
* @param {DebuggerClient} client
|
||||
* @param {Object} runtimeInfo
|
||||
* See runtimeInfo type from client/aboutdebugging-new/src/types/runtime.js
|
||||
*/
|
||||
setClient(id, type, client) {
|
||||
setClient(id, type, client, runtimeInfo) {
|
||||
const key = this._getKey(id, type);
|
||||
this._clients.set(key, client);
|
||||
if (runtimeInfo) {
|
||||
this._runtimeInfoMap.set(key, runtimeInfo);
|
||||
}
|
||||
client.addOneTimeListener("closed", this._onClientClosed);
|
||||
}
|
||||
|
||||
|
@ -66,20 +72,26 @@ class RemoteClientManager {
|
|||
* using getRemoteId.
|
||||
*/
|
||||
getClientByRemoteId(remoteId) {
|
||||
const key = decodeURIComponent(remoteId);
|
||||
const key = this._getKeyByRemoteId(remoteId);
|
||||
return this._clients.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the runtime info for a remote id. To display metadata about a runtime, such
|
||||
* as name, device name, version... this runtimeInfo should be used rather than calling
|
||||
* APIs on the client.
|
||||
*/
|
||||
getRuntimeInfoByRemoteId(remoteId) {
|
||||
const key = this._getKeyByRemoteId(remoteId);
|
||||
return this._runtimeInfoMap.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a managed client for a remote id. The remote id should have been generated
|
||||
* using getRemoteId.
|
||||
*/
|
||||
getConnectionTypeByRemoteId(remoteId) {
|
||||
if (!remoteId) {
|
||||
return CONNECTION_TYPES.THIS_FIREFOX;
|
||||
}
|
||||
|
||||
const key = decodeURIComponent(remoteId);
|
||||
const key = this._getKeyByRemoteId(remoteId);
|
||||
for (const type of Object.values(CONNECTION_TYPES)) {
|
||||
if (key.endsWith(type)) {
|
||||
return type;
|
||||
|
@ -92,11 +104,23 @@ class RemoteClientManager {
|
|||
return id + "-" + type;
|
||||
}
|
||||
|
||||
_getKeyByRemoteId(remoteId) {
|
||||
if (!remoteId) {
|
||||
// If no remote id was provided, return the key corresponding to the local
|
||||
// this-firefox runtime.
|
||||
const { THIS_FIREFOX } = CONNECTION_TYPES;
|
||||
return this._getKey(THIS_FIREFOX, THIS_FIREFOX);
|
||||
}
|
||||
|
||||
return decodeURIComponent(remoteId);
|
||||
}
|
||||
|
||||
_removeClientByKey(key) {
|
||||
const client = this._clients.get(key);
|
||||
if (client) {
|
||||
client.removeListener("closed", this._onClientClosed);
|
||||
this._clients.delete(key);
|
||||
this._runtimeInfoMap.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ const { CONNECTION_TYPES } =
|
|||
add_task(async function testRemoteClientManager() {
|
||||
for (const type of Object.values(CONNECTION_TYPES)) {
|
||||
const fakeClient = createFakeClient();
|
||||
const runtimeInfo = {};
|
||||
const clientId = "clientId";
|
||||
const remoteId = remoteClientManager.getRemoteId(clientId, type);
|
||||
|
||||
|
@ -24,14 +25,18 @@ add_task(async function testRemoteClientManager() {
|
|||
`[${type}]: getClient returns null if no client was set`);
|
||||
equal(remoteClientManager.getClientByRemoteId(remoteId), null,
|
||||
`[${type}]: getClientByRemoteId returns null if no client was set`);
|
||||
equal(remoteClientManager.getRuntimeInfoByRemoteId(remoteId), null,
|
||||
`[${type}]: getRuntimeInfoByRemoteId returns null if no client was set`);
|
||||
|
||||
remoteClientManager.setClient(clientId, type, fakeClient);
|
||||
remoteClientManager.setClient(clientId, type, fakeClient, runtimeInfo);
|
||||
equal(remoteClientManager.hasClient(clientId, type), true,
|
||||
`[${type}]: hasClient returns true`);
|
||||
equal(remoteClientManager.getClient(clientId, type), fakeClient,
|
||||
`[${type}]: getClient returns the correct client`);
|
||||
equal(remoteClientManager.getClientByRemoteId(remoteId), fakeClient,
|
||||
`[${type}]: getClientByRemoteId returns the correct client`);
|
||||
equal(remoteClientManager.getRuntimeInfoByRemoteId(remoteId), runtimeInfo,
|
||||
`[${type}]: getRuntimeInfoByRemoteId returns the correct object`);
|
||||
|
||||
remoteClientManager.removeClient(clientId, type);
|
||||
equal(remoteClientManager.hasClient(clientId, type), false,
|
||||
|
@ -40,7 +45,28 @@ add_task(async function testRemoteClientManager() {
|
|||
`[${type}]: getClient returns null after removing the client`);
|
||||
equal(remoteClientManager.getClientByRemoteId(remoteId), null,
|
||||
`[${type}]: getClientByRemoteId returns null after removing the client`);
|
||||
equal(remoteClientManager.getRuntimeInfoByRemoteId(), null,
|
||||
`[${type}]: getRuntimeInfoByRemoteId returns null after removing the client`);
|
||||
}
|
||||
|
||||
// Test various fallback scenarios for APIs relying on remoteId, when called without a
|
||||
// remoteId, we expect to get the information for the local this-firefox runtime.
|
||||
const { THIS_FIREFOX } = CONNECTION_TYPES;
|
||||
const thisFirefoxClient = createFakeClient();
|
||||
const thisFirefoxInfo = {};
|
||||
remoteClientManager.setClient(THIS_FIREFOX, THIS_FIREFOX, thisFirefoxClient,
|
||||
thisFirefoxInfo);
|
||||
|
||||
equal(remoteClientManager.getClientByRemoteId(), thisFirefoxClient,
|
||||
`[fallback]: getClientByRemoteId returns this-firefox if remoteId is null`);
|
||||
equal(remoteClientManager.getRuntimeInfoByRemoteId(), thisFirefoxInfo,
|
||||
`[fallback]: getRuntimeInfoByRemoteId returns this-firefox if remoteId is null`);
|
||||
|
||||
const otherRemoteId = remoteClientManager.getRemoteId("clientId", CONNECTION_TYPES.USB);
|
||||
equal(remoteClientManager.getClientByRemoteId(otherRemoteId), null,
|
||||
`[fallback]: getClientByRemoteId does not fallback if remoteId is non-null`);
|
||||
equal(remoteClientManager.getRuntimeInfoByRemoteId(otherRemoteId), null,
|
||||
`[fallback]: getRuntimeInfoByRemoteId does not fallback if remoteId is non-null`);
|
||||
});
|
||||
|
||||
add_task(async function testRemoteClientManagerWithUnknownType() {
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
После Ширина: | Высота: | Размер: 7.2 KiB |
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
После Ширина: | Высота: | Размер: 7.2 KiB |
|
@ -191,7 +191,7 @@ var PromisesActor = protocol.ActorClassWithSpec(promisesSpec, {
|
|||
return;
|
||||
}
|
||||
|
||||
this._navigationLifetimePool.cleanup();
|
||||
this._navigationLifetimePool.destroy();
|
||||
this.dbg.removeAllDebuggees();
|
||||
this.dbg.addDebuggees();
|
||||
}),
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
const { RuntimeTypes } = require("devtools/client/webide/modules/runtime-types");
|
||||
const { prepareTCPConnection } = require("devtools/shared/adb/commands/index");
|
||||
const { shell } = require("devtools/shared/adb/commands/index");
|
||||
|
||||
class AdbRuntime {
|
||||
constructor(adbDevice, socketPath) {
|
||||
|
@ -15,10 +16,24 @@ class AdbRuntime {
|
|||
this._socketPath = socketPath;
|
||||
}
|
||||
|
||||
async init() {
|
||||
const packageName = this._packageName();
|
||||
const query = `dumpsys package ${packageName} | grep versionName`;
|
||||
const versionNameString = await shell(this._adbDevice.id, query);
|
||||
const matches = versionNameString.match(/versionName=([\d.]+)/);
|
||||
if (matches && matches[1]) {
|
||||
this._versionName = matches[1];
|
||||
}
|
||||
}
|
||||
|
||||
get id() {
|
||||
return this._adbDevice.id + "|" + this._socketPath;
|
||||
}
|
||||
|
||||
get isFenix() {
|
||||
return this._packageName().includes("org.mozilla.fenix");
|
||||
}
|
||||
|
||||
get deviceId() {
|
||||
return this._adbDevice.id;
|
||||
}
|
||||
|
@ -27,8 +42,35 @@ class AdbRuntime {
|
|||
return this._adbDevice.name;
|
||||
}
|
||||
|
||||
get versionName() {
|
||||
return this._versionName;
|
||||
}
|
||||
|
||||
get shortName() {
|
||||
return `Firefox ${this._channel()}`;
|
||||
const packageName = this._packageName();
|
||||
|
||||
switch (packageName) {
|
||||
case "org.mozilla.firefox":
|
||||
return "Firefox";
|
||||
case "org.mozilla.firefox_beta":
|
||||
return "Firefox Beta";
|
||||
case "org.mozilla.fennec":
|
||||
case "org.mozilla.fennec_aurora":
|
||||
// This package name is now the one for Firefox Nightly distributed
|
||||
// through the Google Play Store since "dawn project"
|
||||
// cf. https://bugzilla.mozilla.org/show_bug.cgi?id=1357351#c8
|
||||
return "Firefox Nightly";
|
||||
case "org.mozilla.fenix":
|
||||
// The current Nightly build for Fenix is available under this package name
|
||||
// but the official packages will use fenix, fenix.beta and fenix.nightly.
|
||||
return "Firefox Preview";
|
||||
case "org.mozilla.fenix.beta":
|
||||
return "Firefox Preview Beta";
|
||||
case "org.mozilla.fenix.nightly":
|
||||
return "Firefox Preview Nightly";
|
||||
default:
|
||||
return "Firefox Custom";
|
||||
}
|
||||
}
|
||||
|
||||
get socketPath() {
|
||||
|
@ -47,25 +89,6 @@ class AdbRuntime {
|
|||
});
|
||||
}
|
||||
|
||||
_channel() {
|
||||
const packageName = this._packageName();
|
||||
|
||||
switch (packageName) {
|
||||
case "org.mozilla.firefox":
|
||||
return "";
|
||||
case "org.mozilla.firefox_beta":
|
||||
return "Beta";
|
||||
case "org.mozilla.fennec":
|
||||
case "org.mozilla.fennec_aurora":
|
||||
// This package name is now the one for Firefox Nightly distributed
|
||||
// through the Google Play Store since "dawn project"
|
||||
// cf. https://bugzilla.mozilla.org/show_bug.cgi?id=1357351#c8
|
||||
return "Nightly";
|
||||
default:
|
||||
return "Custom";
|
||||
}
|
||||
}
|
||||
|
||||
_packageName() {
|
||||
// If using abstract socket address, it is "@org.mozilla.firefox/..."
|
||||
// If using path base socket, it is "/data/data/<package>...""
|
||||
|
|
|
@ -134,7 +134,13 @@ class Adb extends EventEmitter {
|
|||
|
||||
async _getDeviceRuntimes(device) {
|
||||
const socketPaths = [...await device.getRuntimeSocketPaths()];
|
||||
return socketPaths.map(socketPath => new AdbRuntime(device, socketPath));
|
||||
const runtimes = [];
|
||||
for (const socketPath of socketPaths) {
|
||||
const runtime = new AdbRuntime(device, socketPath);
|
||||
await runtime.init();
|
||||
runtimes.push(runtime);
|
||||
}
|
||||
return runtimes;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@ inline void nsIContent::SetPrimaryFrame(nsIFrame* aFrame) {
|
|||
"Losing track of existing primary frame");
|
||||
|
||||
if (aFrame) {
|
||||
MOZ_ASSERT(!aFrame->IsPlaceholderFrame());
|
||||
if (MOZ_LIKELY(!IsHTMLElement(nsGkAtoms::area)) ||
|
||||
aFrame->GetContent() == this) {
|
||||
aFrame->SetIsPrimaryFrame(true);
|
||||
|
|
|
@ -307,12 +307,12 @@ WINDOW_EVENT(pageshow, ePageShow, EventNameType_HTMLBodyOrFramesetOnly,
|
|||
WINDOW_EVENT(popstate, ePopState,
|
||||
EventNameType_XUL | EventNameType_HTMLBodyOrFramesetOnly,
|
||||
eBasicEventClass)
|
||||
// Not supported yet
|
||||
// WINDOW_EVENT(redo)
|
||||
WINDOW_EVENT(rejectionhandled, eRejectionHandled,
|
||||
EventNameType_HTMLBodyOrFramesetOnly, eBasicEventClass)
|
||||
WINDOW_EVENT(storage, eStorage, EventNameType_HTMLBodyOrFramesetOnly,
|
||||
eBasicEventClass)
|
||||
// Not supported yet
|
||||
// WINDOW_EVENT(undo)
|
||||
WINDOW_EVENT(unhandledrejection, eUnhandledRejection,
|
||||
EventNameType_HTMLBodyOrFramesetOnly, eBasicEventClass)
|
||||
WINDOW_EVENT(unload, eUnload,
|
||||
(EventNameType_XUL | EventNameType_SVGSVG |
|
||||
EventNameType_HTMLBodyOrFramesetOnly),
|
||||
|
|
|
@ -617,9 +617,11 @@ bool AudioCallbackDriver::Init() {
|
|||
output.channels = mOutputChannels;
|
||||
output.layout = CUBEB_LAYOUT_UNDEFINED;
|
||||
output.prefs = CubebUtils::GetDefaultStreamPrefs();
|
||||
#if !defined(XP_WIN)
|
||||
if (mInputDevicePreference == CUBEB_DEVICE_PREF_VOICE) {
|
||||
output.prefs |= static_cast<cubeb_stream_prefs>(CUBEB_STREAM_PREF_VOICE);
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t latency_frames = CubebUtils::GetCubebMSGLatencyInFrames(&output);
|
||||
|
||||
|
|
|
@ -2199,13 +2199,13 @@ class RTCRtpReceiver {
|
|||
_getRtpSourcesByType(type) {
|
||||
this._fetchRtpSources();
|
||||
// Only return the values from within the last 10 seconds as per the spec
|
||||
let cutoffTime = this._rtpSourcesJsTimestamp - 10 * 1000;
|
||||
let sources = [...this._rtpSources.values()].filter(
|
||||
const cutoffTime = this._rtpSourcesJsTimestamp - 10 * 1000;
|
||||
return [...this._rtpSources.values()].filter(
|
||||
(entry) => {
|
||||
return entry.sourceType == type &&
|
||||
(entry.timestamp + entry.sourceClockOffset) >= cutoffTime;
|
||||
}).map(e => {
|
||||
let newEntry = {
|
||||
const newEntry = {
|
||||
source: e.source,
|
||||
timestamp: e.timestamp + e.sourceClockOffset,
|
||||
audioLevel: e.audioLevel,
|
||||
|
@ -2214,8 +2214,7 @@ class RTCRtpReceiver {
|
|||
Object.assign(newEntry, {voiceActivityFlag: e.voiceActivityFlag});
|
||||
}
|
||||
return newEntry;
|
||||
});
|
||||
return sources;
|
||||
}).sort((a, b) => b.timestamp - a.timestamp);
|
||||
}
|
||||
|
||||
getContributingSources() {
|
||||
|
|
|
@ -226,6 +226,7 @@ void CamerasParent::StopVideoCapture() {
|
|||
}
|
||||
nsresult rv = GetShutdownBarrier()->RemoveBlocker(self);
|
||||
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
|
||||
Unused << rv;
|
||||
return NS_OK;
|
||||
}));
|
||||
if (NS_FAILED(rv)) {
|
||||
|
|
|
@ -96,7 +96,12 @@ function check_mp4(v, enabled) {
|
|||
check(codec, "probably");
|
||||
ok(MediaSource.isTypeSupported(codec), "VP9 in MP4 should be supported in MSE");
|
||||
});
|
||||
check("video/mp4; codecs=\"av1\"", "probably");
|
||||
|
||||
if (IsAndroid()) {
|
||||
check("video/mp4; codecs=\"av1\"", "");
|
||||
} else {
|
||||
check("video/mp4; codecs=\"av1\"", "probably");
|
||||
}
|
||||
}
|
||||
|
||||
function check_mp3(v, enabled) {
|
||||
|
@ -138,6 +143,10 @@ function getPref(name) {
|
|||
return pref;
|
||||
}
|
||||
|
||||
function IsAndroid() {
|
||||
return getAndroidVersion() >= 0;
|
||||
}
|
||||
|
||||
function IsSupportedAndroid() {
|
||||
return getAndroidVersion() >= 14;
|
||||
}
|
||||
|
|
|
@ -111,6 +111,24 @@
|
|||
is(JSON.stringify(contributingSources),
|
||||
JSON.stringify(remoteReceiver.getContributingSources()),
|
||||
"getContributingSources is cached");
|
||||
// Check that sources are sorted in descending order by time stamp
|
||||
const timestamp3 = SpWrap(test.pcLocal).mozGetNowInRtpSourceReferenceTime();
|
||||
// Larger offsets are further back in time
|
||||
const testOffsets = [3, 7, 5, 6, 1, 4];
|
||||
for (const offset of testOffsets) {
|
||||
SpWrap(test.pcLocal).mozInsertAudioLevelForContributingSource(
|
||||
localReceiver,
|
||||
offset, // Using offset for SSRC for convenience
|
||||
timestamp3 - offset,
|
||||
true,
|
||||
offset);
|
||||
}
|
||||
const sources = localReceiver.getContributingSources();
|
||||
const sourceOffsets = sources.map(s => s.source);
|
||||
is(JSON.stringify(sourceOffsets),
|
||||
JSON.stringify([...testOffsets].sort((a, b) => a - b)),
|
||||
`Contributing sources are sorted in descending order by timestamp:`
|
||||
+ ` ${JSON.stringify(sources)}`);
|
||||
};
|
||||
|
||||
var test;
|
||||
|
|
|
@ -302,12 +302,12 @@ void AudioBuffer::CopyFromChannel(const Float32Array& aDestination,
|
|||
uint32_t aStartInChannel, ErrorResult& aRv) {
|
||||
aDestination.ComputeLengthAndData();
|
||||
|
||||
uint32_t length = aDestination.Length();
|
||||
if (aChannelNumber >= NumberOfChannels() || aStartInChannel > Length()) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t count = std::min(Length() - aStartInChannel, aDestination.Length());
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
JSObject* channelArray = mJSChannels[aChannelNumber];
|
||||
if (channelArray) {
|
||||
|
@ -323,18 +323,17 @@ void AudioBuffer::CopyFromChannel(const Float32Array& aDestination,
|
|||
// The sourceData arrays should all have originated in
|
||||
// RestoreJSChannelData, where they are created unshared.
|
||||
MOZ_ASSERT(!isShared);
|
||||
PodMove(aDestination.Data(), sourceData + aStartInChannel,
|
||||
std::min(Length() - aStartInChannel, length));
|
||||
PodMove(aDestination.Data(), sourceData + aStartInChannel, count);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mSharedChannels.IsNull()) {
|
||||
CopyChannelDataToFloat(mSharedChannels, aChannelNumber, aStartInChannel,
|
||||
aDestination.Data(), length);
|
||||
aDestination.Data(), count);
|
||||
return;
|
||||
}
|
||||
|
||||
PodZero(aDestination.Data(), length);
|
||||
PodZero(aDestination.Data(), count);
|
||||
}
|
||||
|
||||
void AudioBuffer::CopyToChannel(JSContext* aJSContext,
|
||||
|
@ -343,7 +342,6 @@ void AudioBuffer::CopyToChannel(JSContext* aJSContext,
|
|||
uint32_t aStartInChannel, ErrorResult& aRv) {
|
||||
aSource.ComputeLengthAndData();
|
||||
|
||||
uint32_t length = aSource.Length();
|
||||
if (aChannelNumber >= NumberOfChannels() || aStartInChannel > Length()) {
|
||||
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
|
||||
return;
|
||||
|
@ -362,13 +360,13 @@ void AudioBuffer::CopyToChannel(JSContext* aJSContext,
|
|||
return;
|
||||
}
|
||||
|
||||
uint32_t count = std::min(Length() - aStartInChannel, aSource.Length());
|
||||
bool isShared = false;
|
||||
float* channelData = JS_GetFloat32ArrayData(channelArray, &isShared, nogc);
|
||||
// The channelData arrays should all have originated in
|
||||
// RestoreJSChannelData, where they are created unshared.
|
||||
MOZ_ASSERT(!isShared);
|
||||
PodMove(channelData + aStartInChannel, aSource.Data(),
|
||||
std::min(Length() - aStartInChannel, length));
|
||||
PodMove(channelData + aStartInChannel, aSource.Data(), count);
|
||||
}
|
||||
|
||||
void AudioBuffer::GetChannelData(JSContext* aJSContext, uint32_t aChannel,
|
||||
|
|
|
@ -326,4 +326,4 @@ skip-if = verify || serviceworker_e10s
|
|||
[test_file_upload.html]
|
||||
support-files = script_file_upload.js sw_file_upload.js server_file_upload.sjs
|
||||
[test_self_update_worker.html]
|
||||
skip-if = serviceworker_e10s
|
||||
skip-if = serviceworker_e10s || (toolkit == 'android' && !is_fennec)
|
||||
|
|
|
@ -155,7 +155,11 @@ interface WindowEventHandlers {
|
|||
attribute EventHandler onpagehide;
|
||||
attribute EventHandler onpageshow;
|
||||
attribute EventHandler onpopstate;
|
||||
[Func="mozilla::dom::DOMPrefs::dom_promise_rejection_events_enabled"]
|
||||
attribute EventHandler onrejectionhandled;
|
||||
attribute EventHandler onstorage;
|
||||
[Func="mozilla::dom::DOMPrefs::dom_promise_rejection_events_enabled"]
|
||||
attribute EventHandler onunhandledrejection;
|
||||
attribute EventHandler onunload;
|
||||
};
|
||||
|
||||
|
|
|
@ -26,6 +26,10 @@ interface WorkerGlobalScope : EventTarget {
|
|||
|
||||
attribute EventHandler onoffline;
|
||||
attribute EventHandler ononline;
|
||||
[Func="mozilla::dom::DOMPrefs::dom_promise_rejection_events_enabled"]
|
||||
attribute EventHandler onrejectionhandled;
|
||||
[Func="mozilla::dom::DOMPrefs::dom_promise_rejection_events_enabled"]
|
||||
attribute EventHandler onunhandledrejection;
|
||||
// also has additional members in a partial interface
|
||||
};
|
||||
|
||||
|
|
|
@ -130,6 +130,8 @@ class WorkerGlobalScope : public DOMEventTargetHelper,
|
|||
|
||||
IMPL_EVENT_HANDLER(online)
|
||||
IMPL_EVENT_HANDLER(offline)
|
||||
IMPL_EVENT_HANDLER(rejectionhandled)
|
||||
IMPL_EVENT_HANDLER(unhandledrejection)
|
||||
|
||||
void Dump(const Optional<nsAString>& aString) const;
|
||||
|
||||
|
|
|
@ -2540,7 +2540,7 @@ nsresult EditorBase::InsertTextWithTransaction(
|
|||
// In some cases, the node may be the anonymous div elemnt or a mozBR
|
||||
// element. Let's try to look for better insertion point in the nearest
|
||||
// text node if there is.
|
||||
EditorRawDOMPoint pointToInsert = FindBetterInsertionPoint(aPointToInsert);
|
||||
EditorDOMPoint pointToInsert = FindBetterInsertionPoint(aPointToInsert);
|
||||
|
||||
// If a neighboring text node already exists, use that
|
||||
if (!pointToInsert.IsInTextNode()) {
|
||||
|
@ -2573,7 +2573,7 @@ nsresult EditorBase::InsertTextWithTransaction(
|
|||
NS_ENSURE_TRUE(newOffset.isValid(), NS_ERROR_FAILURE);
|
||||
}
|
||||
nsresult rv = InsertTextIntoTextNodeWithTransaction(
|
||||
aStringToInsert, *pointToInsert.GetContainerAsText(),
|
||||
aStringToInsert, MOZ_KnownLive(*pointToInsert.GetContainerAsText()),
|
||||
pointToInsert.Offset());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (aPointAfterInsertedString) {
|
||||
|
@ -2588,7 +2588,7 @@ nsresult EditorBase::InsertTextWithTransaction(
|
|||
NS_ENSURE_TRUE(newOffset.isValid(), NS_ERROR_FAILURE);
|
||||
// we are inserting text into an existing text node.
|
||||
nsresult rv = InsertTextIntoTextNodeWithTransaction(
|
||||
aStringToInsert, *pointToInsert.GetContainerAsText(),
|
||||
aStringToInsert, MOZ_KnownLive(*pointToInsert.GetContainerAsText()),
|
||||
pointToInsert.Offset());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (aPointAfterInsertedString) {
|
||||
|
|
|
@ -911,6 +911,7 @@ class EditorBase : public nsIEditor,
|
|||
* E.g., adjusting whitespaces during composition.
|
||||
* false, otherwise.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
nsresult InsertTextIntoTextNodeWithTransaction(
|
||||
const nsAString& aStringToInsert, Text& aTextNode, int32_t aOffset,
|
||||
bool aSuppressIME = false);
|
||||
|
|
|
@ -1543,8 +1543,9 @@ nsresult HTMLEditRules::WillInsertText(EditSubAction aEditSubAction,
|
|||
}
|
||||
// is it a return?
|
||||
else if (subStr.Equals(newlineStr)) {
|
||||
RefPtr<Element> newBRElement = wsObj.InsertBreak(
|
||||
*SelectionRefPtr(), currentPoint, nsIEditor::eNone);
|
||||
RefPtr<Element> newBRElement =
|
||||
wsObj.InsertBreak(MOZ_KnownLive(*SelectionRefPtr()), currentPoint,
|
||||
nsIEditor::eNone);
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
|
@ -1853,9 +1854,9 @@ EditActionResult HTMLEditRules::WillInsertParagraphSeparator() {
|
|||
|
||||
if (HTMLEditUtils::IsHeader(*blockParent)) {
|
||||
// Headers: close (or split) header
|
||||
nsresult rv =
|
||||
ReturnInHeader(*blockParent, *atStartOfSelection.GetContainer(),
|
||||
atStartOfSelection.Offset());
|
||||
nsresult rv = ReturnInHeader(
|
||||
*blockParent, MOZ_KnownLive(*atStartOfSelection.GetContainer()),
|
||||
atStartOfSelection.Offset());
|
||||
if (NS_WARN_IF(rv == NS_ERROR_EDITOR_DESTROYED)) {
|
||||
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
|
@ -1952,8 +1953,8 @@ nsresult HTMLEditRules::InsertBRElement(const EditorDOMPoint& aPointToBreak) {
|
|||
}
|
||||
pointToBreak = splitLinkNodeResult.SplitPoint();
|
||||
}
|
||||
brElement =
|
||||
wsObj.InsertBreak(*SelectionRefPtr(), pointToBreak, nsIEditor::eNone);
|
||||
brElement = wsObj.InsertBreak(MOZ_KnownLive(*SelectionRefPtr()),
|
||||
pointToBreak, nsIEditor::eNone);
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
|
@ -2432,8 +2433,9 @@ nsresult HTMLEditRules::WillDeleteSelection(
|
|||
so = range->StartOffset();
|
||||
eo = range->EndOffset();
|
||||
}
|
||||
rv = WSRunObject::PrepareToDeleteRange(
|
||||
&HTMLEditorRef(), address_of(visNode), &so, address_of(visNode), &eo);
|
||||
rv = WSRunObject::PrepareToDeleteRange(MOZ_KnownLive(&HTMLEditorRef()),
|
||||
address_of(visNode), &so,
|
||||
address_of(visNode), &eo);
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
|
@ -2577,8 +2579,8 @@ nsresult HTMLEditRules::WillDeleteSelection(
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsIContent* otherContent = otherNode->AsContent();
|
||||
rv = WSRunObject::PrepareToDeleteNode(&HTMLEditorRef(),
|
||||
otherContent);
|
||||
rv = WSRunObject::PrepareToDeleteNode(
|
||||
MOZ_KnownLive(&HTMLEditorRef()), MOZ_KnownLive(otherContent));
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
|
@ -2603,8 +2605,8 @@ nsresult HTMLEditRules::WillDeleteSelection(
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// Found break or image, or hr.
|
||||
rv = WSRunObject::PrepareToDeleteNode(&HTMLEditorRef(),
|
||||
visNode->AsContent());
|
||||
rv = WSRunObject::PrepareToDeleteNode(
|
||||
MOZ_KnownLive(&HTMLEditorRef()), MOZ_KnownLive(visNode->AsContent()));
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
|
@ -2877,7 +2879,7 @@ nsresult HTMLEditRules::WillDeleteSelection(
|
|||
// surrounding whitespace in preparation to delete selection.
|
||||
if (!IsPlaintextEditor()) {
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(HTMLEditorRef());
|
||||
rv = WSRunObject::PrepareToDeleteRange(&HTMLEditorRef(),
|
||||
rv = WSRunObject::PrepareToDeleteRange(MOZ_KnownLive(&HTMLEditorRef()),
|
||||
address_of(startNode), &startOffset,
|
||||
address_of(endNode), &endOffset);
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
|
@ -3535,8 +3537,8 @@ EditActionResult HTMLEditRules::TryToJoinBlocksWithTransaction(
|
|||
// if you backspace from li into p.
|
||||
|
||||
// Adjust whitespace at block boundaries
|
||||
nsresult rv =
|
||||
WSRunObject::PrepareToJoinBlocks(&HTMLEditorRef(), leftBlock, rightBlock);
|
||||
nsresult rv = WSRunObject::PrepareToJoinBlocks(
|
||||
MOZ_KnownLive(&HTMLEditorRef()), leftBlock, rightBlock);
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
return EditActionIgnored(NS_ERROR_EDITOR_DESTROYED);
|
||||
}
|
||||
|
@ -7678,7 +7680,7 @@ nsresult HTMLEditRules::ReturnInHeader(Element& aHeader, nsINode& aNode,
|
|||
// Get ws code to adjust any ws
|
||||
nsCOMPtr<nsINode> node = &aNode;
|
||||
nsresult rv = WSRunObject::PrepareToSplitAcrossBlocks(
|
||||
&HTMLEditorRef(), address_of(node), &aOffset);
|
||||
MOZ_KnownLive(&HTMLEditorRef()), address_of(node), &aOffset);
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
|
@ -8000,7 +8002,7 @@ nsresult HTMLEditRules::SplitParagraph(
|
|||
nsCOMPtr<nsINode> selNode = aStartOfRightNode.GetContainer();
|
||||
int32_t selOffset = aStartOfRightNode.Offset();
|
||||
nsresult rv = WSRunObject::PrepareToSplitAcrossBlocks(
|
||||
&HTMLEditorRef(), address_of(selNode), &selOffset);
|
||||
MOZ_KnownLive(&HTMLEditorRef()), address_of(selNode), &selOffset);
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
|
@ -8196,7 +8198,7 @@ nsresult HTMLEditRules::ReturnInListItem(Element& aListItem, nsINode& aNode,
|
|||
// adjust any ws.
|
||||
nsCOMPtr<nsINode> selNode = &aNode;
|
||||
nsresult rv = WSRunObject::PrepareToSplitAcrossBlocks(
|
||||
&HTMLEditorRef(), address_of(selNode), &aOffset);
|
||||
MOZ_KnownLive(&HTMLEditorRef()), address_of(selNode), &aOffset);
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
|
|
|
@ -658,6 +658,7 @@ class HTMLEditRules : public TextEditRules {
|
|||
* @param aOffset Typically, Selection start offset in the
|
||||
* start container, where to be split.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
MOZ_MUST_USE nsresult ReturnInHeader(Element& aHeader, nsINode& aNode,
|
||||
int32_t aOffset);
|
||||
|
||||
|
@ -672,6 +673,7 @@ class HTMLEditRules : public TextEditRules {
|
|||
* unexpected situation. If this method tries to
|
||||
* split the paragraph, marked as handled.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
MOZ_MUST_USE EditActionResult ReturnInParagraph(Element& aParentDivOrP);
|
||||
|
||||
/**
|
||||
|
@ -687,7 +689,7 @@ class HTMLEditRules : public TextEditRules {
|
|||
* removed.
|
||||
*/
|
||||
template <typename PT, typename CT>
|
||||
MOZ_MUST_USE nsresult SplitParagraph(
|
||||
MOZ_CAN_RUN_SCRIPT MOZ_MUST_USE nsresult SplitParagraph(
|
||||
Element& aParentDivOrP,
|
||||
const EditorDOMPointBase<PT, CT>& aStartOfRightNode, nsIContent* aBRNode);
|
||||
|
||||
|
|
|
@ -289,8 +289,9 @@ nsresult WSRunObject::InsertText(Document& aDocument,
|
|||
} else if (afterRun->mType == WSType::normalWS) {
|
||||
// Try to change an nbsp to a space, if possible, just to prevent nbsp
|
||||
// proliferation
|
||||
nsresult rv = CheckLeadingNBSP(afterRun, pointToInsert.GetContainer(),
|
||||
pointToInsert.Offset());
|
||||
nsresult rv = CheckLeadingNBSP(
|
||||
afterRun, MOZ_KnownLive(pointToInsert.GetContainer()),
|
||||
pointToInsert.Offset());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
@ -413,8 +414,8 @@ nsresult WSRunObject::DeleteWSBackward() {
|
|||
nsCOMPtr<nsINode> startNode = startNodeText.get();
|
||||
nsCOMPtr<nsINode> endNode = endNodeText.get();
|
||||
nsresult rv = WSRunObject::PrepareToDeleteRange(
|
||||
mHTMLEditor, address_of(startNode), &startOffset, address_of(endNode),
|
||||
&endOffset);
|
||||
MOZ_KnownLive(mHTMLEditor), address_of(startNode), &startOffset,
|
||||
address_of(endNode), &endOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// finally, delete that ws
|
||||
|
@ -432,8 +433,8 @@ nsresult WSRunObject::DeleteWSBackward() {
|
|||
int32_t startOffset = point.mOffset;
|
||||
int32_t endOffset = point.mOffset + 1;
|
||||
nsresult rv = WSRunObject::PrepareToDeleteRange(
|
||||
mHTMLEditor, address_of(node), &startOffset, address_of(node),
|
||||
&endOffset);
|
||||
MOZ_KnownLive(mHTMLEditor), address_of(node), &startOffset,
|
||||
address_of(node), &endOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// finally, delete that ws
|
||||
|
@ -476,8 +477,8 @@ nsresult WSRunObject::DeleteWSForward() {
|
|||
// Adjust surrounding ws
|
||||
nsCOMPtr<nsINode> startNode(startNodeText), endNode(endNodeText);
|
||||
nsresult rv = WSRunObject::PrepareToDeleteRange(
|
||||
mHTMLEditor, address_of(startNode), &startOffset, address_of(endNode),
|
||||
&endOffset);
|
||||
MOZ_KnownLive(mHTMLEditor), address_of(startNode), &startOffset,
|
||||
address_of(endNode), &endOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Finally, delete that ws
|
||||
|
@ -495,8 +496,8 @@ nsresult WSRunObject::DeleteWSForward() {
|
|||
int32_t startOffset = point.mOffset;
|
||||
int32_t endOffset = point.mOffset + 1;
|
||||
nsresult rv = WSRunObject::PrepareToDeleteRange(
|
||||
mHTMLEditor, address_of(node), &startOffset, address_of(node),
|
||||
&endOffset);
|
||||
MOZ_KnownLive(mHTMLEditor), address_of(node), &startOffset,
|
||||
address_of(node), &endOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Finally, delete that ws
|
||||
|
@ -1501,7 +1502,8 @@ nsresult WSRunObject::InsertNBSPAndRemoveFollowingASCIIWhitespaces(
|
|||
// First, insert an NBSP.
|
||||
AutoTransactionsConserveSelection dontChangeMySelection(*htmlEditor);
|
||||
nsresult rv = htmlEditor->InsertTextIntoTextNodeWithTransaction(
|
||||
nsDependentSubstring(&kNBSP, 1), *aPoint.mTextNode, aPoint.mOffset, true);
|
||||
nsDependentSubstring(&kNBSP, 1), MOZ_KnownLive(*aPoint.mTextNode),
|
||||
aPoint.mOffset, true);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -1833,7 +1835,7 @@ nsresult WSRunObject::CheckTrailingNBSPOfRun(WSFragment* aRun) {
|
|||
AutoTransactionsConserveSelection dontChangeMySelection(*htmlEditor);
|
||||
nsAutoString spaceStr(char16_t(32));
|
||||
nsresult rv = htmlEditor->InsertTextIntoTextNodeWithTransaction(
|
||||
spaceStr, *thePoint.mTextNode, thePoint.mOffset, true);
|
||||
spaceStr, MOZ_KnownLive(*thePoint.mTextNode), thePoint.mOffset, true);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -1926,7 +1928,7 @@ nsresult WSRunObject::ReplacePreviousNBSPIfUnncessary(
|
|||
AutoTransactionsConserveSelection dontChangeMySelection(*htmlEditor);
|
||||
nsAutoString spaceStr(char16_t(32));
|
||||
nsresult rv = htmlEditor->InsertTextIntoTextNodeWithTransaction(
|
||||
spaceStr, *thePoint.mTextNode, thePoint.mOffset, true);
|
||||
spaceStr, MOZ_KnownLive(*thePoint.mTextNode), thePoint.mOffset, true);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -1973,7 +1975,7 @@ nsresult WSRunObject::CheckLeadingNBSP(WSFragment* aRun, nsINode* aNode,
|
|||
AutoTransactionsConserveSelection dontChangeMySelection(*htmlEditor);
|
||||
nsAutoString spaceStr(char16_t(32));
|
||||
nsresult rv = htmlEditor->InsertTextIntoTextNodeWithTransaction(
|
||||
spaceStr, *thePoint.mTextNode, thePoint.mOffset, true);
|
||||
spaceStr, MOZ_KnownLive(*thePoint.mTextNode), thePoint.mOffset, true);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -184,6 +184,7 @@ class MOZ_STACK_CLASS WSRunObject final {
|
|||
// PrepareToJoinBlocks fixes up ws at the end of aLeftBlock and the
|
||||
// beginning of aRightBlock in preperation for them to be joined. Example
|
||||
// of fixup: trailingws in aLeftBlock needs to be removed.
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
static nsresult PrepareToJoinBlocks(HTMLEditor* aHTMLEditor,
|
||||
dom::Element* aLeftBlock,
|
||||
dom::Element* aRightBlock);
|
||||
|
@ -195,6 +196,7 @@ class MOZ_STACK_CLASS WSRunObject final {
|
|||
// adjusting ws.
|
||||
// example of fixup: trailingws before {aStartNode,aStartOffset}
|
||||
// needs to be removed.
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
static nsresult PrepareToDeleteRange(HTMLEditor* aHTMLEditor,
|
||||
nsCOMPtr<nsINode>* aStartNode,
|
||||
int32_t* aStartOffset,
|
||||
|
@ -204,6 +206,7 @@ class MOZ_STACK_CLASS WSRunObject final {
|
|||
// PrepareToDeleteNode fixes up ws before and after aContent in preparation
|
||||
// for aContent to be deleted. Example of fixup: trailingws before
|
||||
// aContent needs to be removed.
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
static nsresult PrepareToDeleteNode(HTMLEditor* aHTMLEditor,
|
||||
nsIContent* aContent);
|
||||
|
||||
|
@ -212,6 +215,7 @@ class MOZ_STACK_CLASS WSRunObject final {
|
|||
// Note that the aSplitNode and aSplitOffset are adjusted in response to
|
||||
// any DOM changes we make while adjusting ws. Example of fixup: normalws
|
||||
// before {aSplitNode,aSplitOffset} needs to end with nbsp.
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
static nsresult PrepareToSplitAcrossBlocks(HTMLEditor* aHTMLEditor,
|
||||
nsCOMPtr<nsINode>* aSplitNode,
|
||||
int32_t* aSplitOffset);
|
||||
|
@ -236,7 +240,7 @@ class MOZ_STACK_CLASS WSRunObject final {
|
|||
* node, returns nullptr.
|
||||
*/
|
||||
template <typename PT, typename CT>
|
||||
already_AddRefed<dom::Element> InsertBreak(
|
||||
MOZ_CAN_RUN_SCRIPT already_AddRefed<dom::Element> InsertBreak(
|
||||
Selection& aSelection, const EditorDOMPointBase<PT, CT>& aPointToInsert,
|
||||
nsIEditor::EDirection aSelect);
|
||||
|
||||
|
@ -267,12 +271,12 @@ class MOZ_STACK_CLASS WSRunObject final {
|
|||
// point (the point to create the wsRunObject, passed to its constructor).
|
||||
// It makes any needed conversion to adjacent ws to retain its
|
||||
// significance.
|
||||
nsresult DeleteWSBackward();
|
||||
MOZ_CAN_RUN_SCRIPT nsresult DeleteWSBackward();
|
||||
|
||||
// DeleteWSForward deletes a single visible piece of ws after the ws point
|
||||
// (the point to create the wsRunObject, passed to its constructor). It
|
||||
// makes any needed conversion to adjacent ws to retain its significance.
|
||||
nsresult DeleteWSForward();
|
||||
MOZ_CAN_RUN_SCRIPT nsresult DeleteWSForward();
|
||||
|
||||
// PriorVisibleNode() returns the first piece of visible thing before aPoint.
|
||||
// If there is no visible ws qualifying it returns what is before the ws run.
|
||||
|
@ -310,7 +314,7 @@ class MOZ_STACK_CLASS WSRunObject final {
|
|||
|
||||
// AdjustWhitespace examines the ws object for nbsp's that can
|
||||
// be safely converted to regular ascii space and converts them.
|
||||
nsresult AdjustWhitespace();
|
||||
MOZ_CAN_RUN_SCRIPT nsresult AdjustWhitespace();
|
||||
|
||||
protected:
|
||||
// WSFragment represents a single run of ws (all leadingws, or all normalws,
|
||||
|
@ -370,8 +374,8 @@ class MOZ_STACK_CLASS WSRunObject final {
|
|||
nsIContent* GetNextWSNodeInner(nsINode* aStartNode, nsINode* aBlockParent);
|
||||
nsIContent* GetNextWSNode(const EditorDOMPoint& aPoint,
|
||||
nsINode* aBlockParent);
|
||||
nsresult PrepareToDeleteRangePriv(WSRunObject* aEndObject);
|
||||
nsresult PrepareToSplitAcrossBlocksPriv();
|
||||
MOZ_CAN_RUN_SCRIPT nsresult PrepareToDeleteRangePriv(WSRunObject* aEndObject);
|
||||
MOZ_CAN_RUN_SCRIPT nsresult PrepareToSplitAcrossBlocksPriv();
|
||||
|
||||
/**
|
||||
* DeleteRange() removes the range between aStartPoint and aEndPoint.
|
||||
|
@ -422,6 +426,7 @@ class MOZ_STACK_CLASS WSRunObject final {
|
|||
* InsertNBSPAndRemoveFollowingASCIIWhitespaces() inserts an NBSP first.
|
||||
* Then, if following characters are ASCII whitespaces, will remove them.
|
||||
*/
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
nsresult InsertNBSPAndRemoveFollowingASCIIWhitespaces(WSPoint aPoint);
|
||||
|
||||
/**
|
||||
|
@ -475,7 +480,7 @@ class MOZ_STACK_CLASS WSRunObject final {
|
|||
bool aForward) const;
|
||||
|
||||
char16_t GetCharAt(dom::Text* aTextNode, int32_t aOffset) const;
|
||||
nsresult CheckTrailingNBSPOfRun(WSFragment* aRun);
|
||||
MOZ_CAN_RUN_SCRIPT nsresult CheckTrailingNBSPOfRun(WSFragment* aRun);
|
||||
|
||||
/**
|
||||
* ReplacePreviousNBSPIfUnncessary() replaces previous character of aPoint
|
||||
|
@ -486,9 +491,10 @@ class MOZ_STACK_CLASS WSRunObject final {
|
|||
* unnecessary NBSP will be checked.
|
||||
*/
|
||||
template <typename PT, typename CT>
|
||||
nsresult ReplacePreviousNBSPIfUnncessary(
|
||||
MOZ_CAN_RUN_SCRIPT nsresult ReplacePreviousNBSPIfUnncessary(
|
||||
WSFragment* aRun, const EditorDOMPointBase<PT, CT>& aPoint);
|
||||
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
nsresult CheckLeadingNBSP(WSFragment* aRun, nsINode* aNode, int32_t aOffset);
|
||||
|
||||
nsresult Scrub();
|
||||
|
|
|
@ -104,6 +104,7 @@ void CompositorVsyncScheduler::Destroy() {
|
|||
|
||||
mCompositeRequestedAt = TimeStamp();
|
||||
CancelCurrentCompositeTask();
|
||||
CancelCurrentVRTask();
|
||||
}
|
||||
|
||||
void CompositorVsyncScheduler::PostCompositeTask(
|
||||
|
@ -122,7 +123,7 @@ void CompositorVsyncScheduler::PostCompositeTask(
|
|||
void CompositorVsyncScheduler::PostVRTask(TimeStamp aTimestamp) {
|
||||
MonitorAutoLock lockVR(mCurrentVRTaskMonitor);
|
||||
if (mCurrentVRTask == nullptr && CompositorThreadHolder::Loop()) {
|
||||
RefPtr<Runnable> task = NewRunnableMethod<TimeStamp>(
|
||||
RefPtr<CancelableRunnable> task = NewCancelableRunnableMethod<TimeStamp>(
|
||||
"layers::CompositorVsyncScheduler::DispatchVREvents", this,
|
||||
&CompositorVsyncScheduler::DispatchVREvents, aTimestamp);
|
||||
mCurrentVRTask = task;
|
||||
|
@ -190,6 +191,16 @@ bool CompositorVsyncScheduler::NotifyVsync(const VsyncEvent& aVsync) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void CompositorVsyncScheduler::CancelCurrentVRTask() {
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread() ||
|
||||
NS_IsMainThread());
|
||||
MonitorAutoLock lock(mCurrentVRTaskMonitor);
|
||||
if (mCurrentVRTask) {
|
||||
mCurrentVRTask->Cancel();
|
||||
mCurrentVRTask = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void CompositorVsyncScheduler::CancelCurrentCompositeTask() {
|
||||
MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread() ||
|
||||
NS_IsMainThread());
|
||||
|
|
|
@ -120,6 +120,11 @@ class CompositorVsyncScheduler {
|
|||
// such a task already queued. Can be called from any thread.
|
||||
void PostVRTask(TimeStamp aTimestamp);
|
||||
|
||||
/**
|
||||
* Cancel any VR task that has been scheduled but hasn't run yet.
|
||||
*/
|
||||
void CancelCurrentVRTask();
|
||||
|
||||
// This gets run at vsync time and "does" a composite (which really means
|
||||
// update internal state and call the owner to do the composite).
|
||||
void Composite(VsyncId aId, TimeStamp aVsyncTimestamp);
|
||||
|
@ -159,7 +164,7 @@ class CompositorVsyncScheduler {
|
|||
RefPtr<CancelableRunnable> mCurrentCompositeTask;
|
||||
|
||||
mozilla::Monitor mCurrentVRTaskMonitor;
|
||||
RefPtr<Runnable> mCurrentVRTask;
|
||||
RefPtr<CancelableRunnable> mCurrentVRTask;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -1043,8 +1043,9 @@ impl AlphaBatchBuilder {
|
|||
.expect("BUG: 3d primitive was not assigned a surface");
|
||||
let (uv_rect_address, _) = render_tasks.resolve_surface(
|
||||
ctx.surfaces[raster_config.surface_index.0]
|
||||
.surface
|
||||
.expect("BUG: no surface"),
|
||||
.render_tasks
|
||||
.expect("BUG: no surface")
|
||||
.root,
|
||||
gpu_cache,
|
||||
);
|
||||
|
||||
|
@ -1097,7 +1098,10 @@ impl AlphaBatchBuilder {
|
|||
render_tasks,
|
||||
).unwrap_or(OPAQUE_TASK_ADDRESS);
|
||||
|
||||
let surface = ctx.surfaces[raster_config.surface_index.0].surface;
|
||||
let surface = ctx
|
||||
.surfaces[raster_config.surface_index.0]
|
||||
.render_tasks
|
||||
.map(|s| s.root);
|
||||
|
||||
match raster_config.composite_mode {
|
||||
PictureCompositeMode::TileCache { .. } => {
|
||||
|
|
|
@ -903,6 +903,9 @@ pub struct Capabilities {
|
|||
/// is available on some mobile GPUs. This allows fast access to
|
||||
/// the per-pixel tile memory.
|
||||
pub supports_pixel_local_storage: bool,
|
||||
/// Whether KHR_debug is supported for getting debug messages from
|
||||
/// the driver.
|
||||
pub supports_khr_debug: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -1134,16 +1137,6 @@ impl Device {
|
|||
cached_programs: Option<Rc<ProgramCache>>,
|
||||
allow_pixel_local_storage_support: bool,
|
||||
) -> Device {
|
||||
// On debug builds, assert that each GL call is error-free. We don't do
|
||||
// this on release builds because the synchronous call can stall the
|
||||
// pipeline.
|
||||
if cfg!(debug_assertions) {
|
||||
gl = gl::ErrorReactingGl::wrap(gl, |gl, name, code| {
|
||||
Self::echo_driver_messages(gl);
|
||||
panic!("Caught GL error {:x} at {}", code, name);
|
||||
});
|
||||
}
|
||||
|
||||
let mut max_texture_size = [0];
|
||||
let mut max_texture_layers = [0];
|
||||
unsafe {
|
||||
|
@ -1165,6 +1158,19 @@ impl Device {
|
|||
extensions.push(gl.get_string_i(gl::EXTENSIONS, i));
|
||||
}
|
||||
|
||||
// On debug builds, assert that each GL call is error-free. We don't do
|
||||
// this on release builds because the synchronous call can stall the
|
||||
// pipeline.
|
||||
let supports_khr_debug = supports_extension(&extensions, "GL_KHR_debug");
|
||||
if cfg!(debug_assertions) {
|
||||
gl = gl::ErrorReactingGl::wrap(gl, move |gl, name, code| {
|
||||
if supports_khr_debug {
|
||||
Self::log_driver_messages(gl);
|
||||
}
|
||||
panic!("Caught GL error {:x} at {}", code, name);
|
||||
});
|
||||
}
|
||||
|
||||
// Our common-case image data in Firefox is BGRA, so we make an effort
|
||||
// to use BGRA as the internal texture storage format to avoid the need
|
||||
// to swizzle during upload. Currently we only do this on GLES (and thus
|
||||
|
@ -1285,6 +1291,7 @@ impl Device {
|
|||
supports_copy_image_sub_data,
|
||||
supports_blit_to_texture_array,
|
||||
supports_pixel_local_storage,
|
||||
supports_khr_debug,
|
||||
},
|
||||
|
||||
bgra_format_internal,
|
||||
|
@ -3093,7 +3100,13 @@ impl Device {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn echo_driver_messages(gl: &gl::Gl) {
|
||||
pub fn echo_driver_messages(&self) {
|
||||
if self.capabilities.supports_khr_debug {
|
||||
Device::log_driver_messages(self.gl());
|
||||
}
|
||||
}
|
||||
|
||||
fn log_driver_messages(gl: &gl::Gl) {
|
||||
for msg in gl.get_debug_messages() {
|
||||
let level = match msg.severity {
|
||||
gl::DEBUG_SEVERITY_HIGH => Level::Error,
|
||||
|
|
|
@ -15,7 +15,7 @@ use crate::hit_test::{HitTester, HitTestingScene};
|
|||
use crate::hit_test::HitTestingSceneStats;
|
||||
use crate::internal_types::{FastHashMap, PlaneSplitter};
|
||||
use crate::picture::{PictureUpdateState, SurfaceInfo, ROOT_SURFACE_INDEX, SurfaceIndex};
|
||||
use crate::picture::{RetainedTiles, TileCache, DirtyRegion};
|
||||
use crate::picture::{RetainedTiles, TileCache, DirtyRegion, SurfaceRenderTasks};
|
||||
use crate::prim_store::{PrimitiveStore, SpaceMapper, PictureIndex, PrimitiveDebugId, PrimitiveScratchBuffer};
|
||||
#[cfg(feature = "replay")]
|
||||
use crate::prim_store::{PrimitiveStoreStats};
|
||||
|
@ -29,6 +29,7 @@ use crate::segment::SegmentBuilder;
|
|||
use std::{f32, mem};
|
||||
use std::sync::Arc;
|
||||
use crate::tiling::{Frame, RenderPassKind, RenderTargetContext, RenderTarget};
|
||||
use crate::util::MaxRect;
|
||||
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
|
@ -444,7 +445,10 @@ impl FrameBuilder {
|
|||
.surfaces
|
||||
.first_mut()
|
||||
.unwrap()
|
||||
.surface = Some(root_render_task_id);
|
||||
.render_tasks = Some(SurfaceRenderTasks {
|
||||
root: root_render_task_id,
|
||||
port: root_render_task_id,
|
||||
});
|
||||
|
||||
// Push a default dirty region which culls primitives
|
||||
// against the screen world rect, in absence of any
|
||||
|
@ -460,6 +464,7 @@ impl FrameBuilder {
|
|||
.pictures[self.root_pic_index.0]
|
||||
.take_context(
|
||||
self.root_pic_index,
|
||||
WorldRect::max_rect(),
|
||||
root_spatial_node_index,
|
||||
root_spatial_node_index,
|
||||
ROOT_SURFACE_INDEX,
|
||||
|
@ -492,17 +497,6 @@ impl FrameBuilder {
|
|||
|
||||
frame_state.pop_dirty_region();
|
||||
|
||||
let child_tasks = frame_state
|
||||
.surfaces[ROOT_SURFACE_INDEX.0]
|
||||
.take_render_tasks();
|
||||
|
||||
for child_task_id in child_tasks {
|
||||
frame_state.render_tasks.add_dependency(
|
||||
root_render_task_id,
|
||||
child_task_id,
|
||||
);
|
||||
}
|
||||
|
||||
Some(root_render_task_id)
|
||||
}
|
||||
|
||||
|
|
|
@ -1780,6 +1780,17 @@ pub struct SurfaceIndex(pub usize);
|
|||
|
||||
pub const ROOT_SURFACE_INDEX: SurfaceIndex = SurfaceIndex(0);
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct SurfaceRenderTasks {
|
||||
/// The root of the render task chain for this surface. This
|
||||
/// is attached to parent tasks, and also the surface that
|
||||
/// gets added during batching.
|
||||
pub root: RenderTaskId,
|
||||
/// The port of the render task change for this surface. This
|
||||
/// is where child tasks for this surface get attached to.
|
||||
pub port: RenderTaskId,
|
||||
}
|
||||
|
||||
/// Information about an offscreen surface. For now,
|
||||
/// it contains information about the size and coordinate
|
||||
/// system of the surface. In the future, it will contain
|
||||
|
@ -1799,9 +1810,7 @@ pub struct SurfaceInfo {
|
|||
pub raster_spatial_node_index: SpatialNodeIndex,
|
||||
pub surface_spatial_node_index: SpatialNodeIndex,
|
||||
/// This is set when the render task is created.
|
||||
pub surface: Option<RenderTaskId>,
|
||||
/// A list of render tasks that are dependencies of this surface.
|
||||
pub tasks: Vec<RenderTaskId>,
|
||||
pub render_tasks: Option<SurfaceRenderTasks>,
|
||||
/// How much the local surface rect should be inflated (for blur radii).
|
||||
pub inflation_factor: f32,
|
||||
/// The device pixel ratio specific to this surface.
|
||||
|
@ -1839,21 +1848,14 @@ impl SurfaceInfo {
|
|||
SurfaceInfo {
|
||||
rect: PictureRect::zero(),
|
||||
map_local_to_surface,
|
||||
surface: None,
|
||||
render_tasks: None,
|
||||
raster_spatial_node_index,
|
||||
surface_spatial_node_index,
|
||||
tasks: Vec::new(),
|
||||
inflation_factor,
|
||||
device_pixel_scale,
|
||||
allow_subpixel_aa,
|
||||
}
|
||||
}
|
||||
|
||||
/// Take the set of child render tasks for this surface. This is
|
||||
/// used when constructing the render task tree.
|
||||
pub fn take_render_tasks(&mut self) -> Vec<RenderTaskId> {
|
||||
mem::replace(&mut self.tasks, Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -2152,7 +2154,7 @@ pub struct PicturePrimitive {
|
|||
pub prim_list: PrimitiveList,
|
||||
|
||||
#[cfg_attr(feature = "capture", serde(skip))]
|
||||
pub state: Option<(PictureState, PictureContext)>,
|
||||
pub state: Option<PictureState>,
|
||||
|
||||
/// The pipeline that the primitives on this picture belong to.
|
||||
pub pipeline_id: PipelineId,
|
||||
|
@ -2350,9 +2352,10 @@ impl PicturePrimitive {
|
|||
pub fn take_context(
|
||||
&mut self,
|
||||
pic_index: PictureIndex,
|
||||
clipped_prim_bounding_rect: WorldRect,
|
||||
surface_spatial_node_index: SpatialNodeIndex,
|
||||
raster_spatial_node_index: SpatialNodeIndex,
|
||||
surface_index: SurfaceIndex,
|
||||
parent_surface_index: SurfaceIndex,
|
||||
frame_state: &mut FrameBuildingState,
|
||||
frame_context: &FrameBuildingContext,
|
||||
) -> Option<(PictureContext, PictureState, PrimitiveList)> {
|
||||
|
@ -2378,7 +2381,7 @@ impl PicturePrimitive {
|
|||
(
|
||||
raster_spatial_node_index,
|
||||
surface_spatial_node_index,
|
||||
surface_index,
|
||||
parent_surface_index,
|
||||
0.0,
|
||||
)
|
||||
}
|
||||
|
@ -2418,6 +2421,304 @@ impl PicturePrimitive {
|
|||
}
|
||||
};
|
||||
|
||||
let (is_composite, is_passthrough) = match self.raster_config {
|
||||
Some(ref rc @ RasterConfig { composite_mode: PictureCompositeMode::TileCache { .. }, .. }) => {
|
||||
// For a picture surface, just push any child tasks and tile
|
||||
// blits up to the parent surface.
|
||||
let port = frame_state
|
||||
.surfaces[parent_surface_index.0]
|
||||
.render_tasks
|
||||
.expect("bug: no render tasks set for parent!")
|
||||
.port;
|
||||
|
||||
frame_state
|
||||
.surfaces[rc.surface_index.0]
|
||||
.render_tasks = Some(SurfaceRenderTasks {
|
||||
root: RenderTaskId::INVALID,
|
||||
port,
|
||||
});
|
||||
|
||||
(false, false)
|
||||
},
|
||||
Some(ref raster_config) => {
|
||||
let pic_rect = PictureRect::from_untyped(&self.snapped_local_rect.to_untyped());
|
||||
|
||||
let device_pixel_scale = frame_state
|
||||
.surfaces[raster_config.surface_index.0]
|
||||
.device_pixel_scale;
|
||||
|
||||
let (clipped, unclipped) = match get_raster_rects(
|
||||
pic_rect,
|
||||
&map_pic_to_raster,
|
||||
&map_raster_to_world,
|
||||
clipped_prim_bounding_rect,
|
||||
device_pixel_scale,
|
||||
) {
|
||||
Some(info) => info,
|
||||
None => {
|
||||
return None
|
||||
}
|
||||
};
|
||||
let transform = map_pic_to_raster.get_transform();
|
||||
|
||||
let (root, port) = match raster_config.composite_mode {
|
||||
PictureCompositeMode::TileCache { .. } => {
|
||||
unreachable!();
|
||||
}
|
||||
PictureCompositeMode::Filter(FilterOp::Blur(blur_radius)) => {
|
||||
let blur_std_deviation = blur_radius * device_pixel_scale.0;
|
||||
let scale_factors = scale_factors(&transform);
|
||||
let blur_std_deviation = DeviceSize::new(
|
||||
blur_std_deviation * scale_factors.0,
|
||||
blur_std_deviation * scale_factors.1
|
||||
);
|
||||
let inflation_factor = frame_state.surfaces[raster_config.surface_index.0].inflation_factor;
|
||||
let inflation_factor = (inflation_factor * device_pixel_scale.0).ceil() as i32;
|
||||
|
||||
// The clipped field is the part of the picture that is visible
|
||||
// on screen. The unclipped field is the screen-space rect of
|
||||
// the complete picture, if no screen / clip-chain was applied
|
||||
// (this includes the extra space for blur region). To ensure
|
||||
// that we draw a large enough part of the picture to get correct
|
||||
// blur results, inflate that clipped area by the blur range, and
|
||||
// then intersect with the total screen rect, to minimize the
|
||||
// allocation size.
|
||||
let mut device_rect = clipped
|
||||
.inflate(inflation_factor, inflation_factor)
|
||||
.intersection(&unclipped.to_i32())
|
||||
.unwrap();
|
||||
// Adjust the size to avoid introducing sampling errors during the down-scaling passes.
|
||||
// what would be even better is to rasterize the picture at the down-scaled size
|
||||
// directly.
|
||||
device_rect.size = RenderTask::adjusted_blur_source_size(
|
||||
device_rect.size,
|
||||
blur_std_deviation,
|
||||
);
|
||||
|
||||
let uv_rect_kind = calculate_uv_rect_kind(
|
||||
&pic_rect,
|
||||
&transform,
|
||||
&device_rect,
|
||||
device_pixel_scale,
|
||||
true,
|
||||
);
|
||||
|
||||
let picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, device_rect.size),
|
||||
unclipped.size,
|
||||
pic_index,
|
||||
device_rect.origin,
|
||||
Vec::new(),
|
||||
uv_rect_kind,
|
||||
raster_spatial_node_index,
|
||||
device_pixel_scale,
|
||||
);
|
||||
|
||||
let picture_task_id = frame_state.render_tasks.add(picture_task);
|
||||
|
||||
let blur_render_task = RenderTask::new_blur(
|
||||
blur_std_deviation,
|
||||
picture_task_id,
|
||||
frame_state.render_tasks,
|
||||
RenderTargetKind::Color,
|
||||
ClearMode::Transparent,
|
||||
);
|
||||
|
||||
let render_task_id = frame_state.render_tasks.add(blur_render_task);
|
||||
|
||||
(render_task_id, picture_task_id)
|
||||
}
|
||||
PictureCompositeMode::Filter(FilterOp::DropShadow(_, blur_radius, _)) => {
|
||||
let blur_std_deviation = blur_radius * device_pixel_scale.0;
|
||||
let blur_range = (blur_std_deviation * BLUR_SAMPLE_SCALE).ceil() as i32;
|
||||
let rounded_std_dev = blur_std_deviation.round();
|
||||
let rounded_std_dev = DeviceSize::new(rounded_std_dev, rounded_std_dev);
|
||||
// The clipped field is the part of the picture that is visible
|
||||
// on screen. The unclipped field is the screen-space rect of
|
||||
// the complete picture, if no screen / clip-chain was applied
|
||||
// (this includes the extra space for blur region). To ensure
|
||||
// that we draw a large enough part of the picture to get correct
|
||||
// blur results, inflate that clipped area by the blur range, and
|
||||
// then intersect with the total screen rect, to minimize the
|
||||
// allocation size.
|
||||
let mut device_rect = clipped.inflate(blur_range, blur_range)
|
||||
.intersection(&unclipped.to_i32())
|
||||
.unwrap();
|
||||
device_rect.size = RenderTask::adjusted_blur_source_size(
|
||||
device_rect.size,
|
||||
rounded_std_dev,
|
||||
);
|
||||
|
||||
let uv_rect_kind = calculate_uv_rect_kind(
|
||||
&pic_rect,
|
||||
&transform,
|
||||
&device_rect,
|
||||
device_pixel_scale,
|
||||
true,
|
||||
);
|
||||
|
||||
let mut picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, device_rect.size),
|
||||
unclipped.size,
|
||||
pic_index,
|
||||
device_rect.origin,
|
||||
Vec::new(),
|
||||
uv_rect_kind,
|
||||
raster_spatial_node_index,
|
||||
device_pixel_scale,
|
||||
);
|
||||
picture_task.mark_for_saving();
|
||||
|
||||
let picture_task_id = frame_state.render_tasks.add(picture_task);
|
||||
|
||||
let blur_render_task = RenderTask::new_blur(
|
||||
rounded_std_dev,
|
||||
picture_task_id,
|
||||
frame_state.render_tasks,
|
||||
RenderTargetKind::Color,
|
||||
ClearMode::Transparent,
|
||||
);
|
||||
|
||||
self.secondary_render_task_id = Some(picture_task_id);
|
||||
|
||||
let render_task_id = frame_state.render_tasks.add(blur_render_task);
|
||||
|
||||
(render_task_id, picture_task_id)
|
||||
}
|
||||
PictureCompositeMode::MixBlend(..) if !frame_context.fb_config.gpu_supports_advanced_blend => {
|
||||
let uv_rect_kind = calculate_uv_rect_kind(
|
||||
&pic_rect,
|
||||
&transform,
|
||||
&clipped,
|
||||
device_pixel_scale,
|
||||
true,
|
||||
);
|
||||
|
||||
let picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, clipped.size),
|
||||
unclipped.size,
|
||||
pic_index,
|
||||
clipped.origin,
|
||||
Vec::new(),
|
||||
uv_rect_kind,
|
||||
raster_spatial_node_index,
|
||||
device_pixel_scale,
|
||||
);
|
||||
|
||||
let readback_task_id = frame_state.render_tasks.add(
|
||||
RenderTask::new_readback(clipped)
|
||||
);
|
||||
|
||||
frame_state.render_tasks.add_dependency(
|
||||
frame_state.surfaces[parent_surface_index.0].render_tasks.unwrap().port,
|
||||
readback_task_id,
|
||||
);
|
||||
|
||||
self.secondary_render_task_id = Some(readback_task_id);
|
||||
|
||||
let render_task_id = frame_state.render_tasks.add(picture_task);
|
||||
|
||||
(render_task_id, render_task_id)
|
||||
}
|
||||
PictureCompositeMode::Filter(..) => {
|
||||
let uv_rect_kind = calculate_uv_rect_kind(
|
||||
&pic_rect,
|
||||
&transform,
|
||||
&clipped,
|
||||
device_pixel_scale,
|
||||
true,
|
||||
);
|
||||
|
||||
let picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, clipped.size),
|
||||
unclipped.size,
|
||||
pic_index,
|
||||
clipped.origin,
|
||||
Vec::new(),
|
||||
uv_rect_kind,
|
||||
raster_spatial_node_index,
|
||||
device_pixel_scale,
|
||||
);
|
||||
|
||||
let render_task_id = frame_state.render_tasks.add(picture_task);
|
||||
|
||||
(render_task_id, render_task_id)
|
||||
}
|
||||
PictureCompositeMode::ComponentTransferFilter(..) => {
|
||||
let uv_rect_kind = calculate_uv_rect_kind(
|
||||
&pic_rect,
|
||||
&transform,
|
||||
&clipped,
|
||||
device_pixel_scale,
|
||||
true,
|
||||
);
|
||||
|
||||
let picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, clipped.size),
|
||||
unclipped.size,
|
||||
pic_index,
|
||||
clipped.origin,
|
||||
Vec::new(),
|
||||
uv_rect_kind,
|
||||
raster_spatial_node_index,
|
||||
device_pixel_scale,
|
||||
);
|
||||
|
||||
let render_task_id = frame_state.render_tasks.add(picture_task);
|
||||
|
||||
(render_task_id, render_task_id)
|
||||
}
|
||||
PictureCompositeMode::MixBlend(..) |
|
||||
PictureCompositeMode::Blit(_) => {
|
||||
// The SplitComposite shader used for 3d contexts doesn't snap
|
||||
// to pixels, so we shouldn't snap our uv coordinates either.
|
||||
let supports_snapping = match self.context_3d {
|
||||
Picture3DContext::In{ .. } => false,
|
||||
_ => true,
|
||||
};
|
||||
|
||||
let uv_rect_kind = calculate_uv_rect_kind(
|
||||
&pic_rect,
|
||||
&transform,
|
||||
&clipped,
|
||||
device_pixel_scale,
|
||||
supports_snapping,
|
||||
);
|
||||
|
||||
let picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, clipped.size),
|
||||
unclipped.size,
|
||||
pic_index,
|
||||
clipped.origin,
|
||||
Vec::new(),
|
||||
uv_rect_kind,
|
||||
raster_spatial_node_index,
|
||||
device_pixel_scale,
|
||||
);
|
||||
|
||||
let render_task_id = frame_state.render_tasks.add(picture_task);
|
||||
|
||||
(render_task_id, render_task_id)
|
||||
}
|
||||
};
|
||||
|
||||
frame_state.surfaces[raster_config.surface_index.0].render_tasks = Some(SurfaceRenderTasks {
|
||||
root,
|
||||
port,
|
||||
});
|
||||
|
||||
frame_state.render_tasks.add_dependency(
|
||||
frame_state.surfaces[parent_surface_index.0].render_tasks.unwrap().port,
|
||||
root,
|
||||
);
|
||||
|
||||
(true, false)
|
||||
}
|
||||
None => {
|
||||
(false, true)
|
||||
}
|
||||
};
|
||||
|
||||
let state = PictureState {
|
||||
//TODO: check for MAX_CACHE_SIZE here?
|
||||
map_local_to_pic,
|
||||
|
@ -2427,18 +2728,6 @@ impl PicturePrimitive {
|
|||
plane_splitter,
|
||||
};
|
||||
|
||||
let (is_composite, is_passthrough) = match self.raster_config {
|
||||
Some(RasterConfig { composite_mode: PictureCompositeMode::TileCache { .. }, .. }) => {
|
||||
(false, false)
|
||||
},
|
||||
Some(_) => {
|
||||
(true, false)
|
||||
}
|
||||
None => {
|
||||
(false, true)
|
||||
}
|
||||
};
|
||||
|
||||
let mut dirty_region_count = 0;
|
||||
|
||||
// If this is a picture cache, push the dirty region to ensure any
|
||||
|
@ -2488,10 +2777,10 @@ impl PicturePrimitive {
|
|||
}
|
||||
|
||||
self.prim_list = prim_list;
|
||||
self.state = Some((state, context));
|
||||
self.state = Some(state);
|
||||
}
|
||||
|
||||
pub fn take_state_and_context(&mut self) -> (PictureState, PictureContext) {
|
||||
pub fn take_state(&mut self) -> PictureState {
|
||||
self.state.take().expect("bug: no state present!")
|
||||
}
|
||||
|
||||
|
@ -2876,14 +3165,11 @@ impl PicturePrimitive {
|
|||
|
||||
pub fn prepare_for_render(
|
||||
&mut self,
|
||||
pic_index: PictureIndex,
|
||||
clipped_prim_bounding_rect: WorldRect,
|
||||
surface_index: SurfaceIndex,
|
||||
frame_context: &FrameBuildingContext,
|
||||
frame_state: &mut FrameBuildingState,
|
||||
data_stores: &mut DataStores,
|
||||
) -> bool {
|
||||
let (mut pic_state_for_children, pic_context) = self.take_state_and_context();
|
||||
let mut pic_state_for_children = self.take_state();
|
||||
|
||||
if let Some(ref mut splitter) = pic_state_for_children.plane_splitter {
|
||||
self.resolve_split_planes(splitter, frame_state);
|
||||
|
@ -2896,36 +3182,6 @@ impl PicturePrimitive {
|
|||
}
|
||||
};
|
||||
|
||||
let (raster_spatial_node_index, child_tasks, device_pixel_scale) = {
|
||||
let surface_info = &mut frame_state.surfaces[raster_config.surface_index.0];
|
||||
(
|
||||
surface_info.raster_spatial_node_index,
|
||||
surface_info.take_render_tasks(),
|
||||
surface_info.device_pixel_scale,
|
||||
)
|
||||
};
|
||||
|
||||
let (map_raster_to_world, map_pic_to_raster) = create_raster_mappers(
|
||||
self.spatial_node_index,
|
||||
raster_spatial_node_index,
|
||||
frame_context.screen_world_rect,
|
||||
frame_context.clip_scroll_tree,
|
||||
);
|
||||
|
||||
let pic_rect = PictureRect::from_untyped(&self.snapped_local_rect.to_untyped());
|
||||
|
||||
let (clipped, unclipped) = match get_raster_rects(
|
||||
pic_rect,
|
||||
&map_pic_to_raster,
|
||||
&map_raster_to_world,
|
||||
clipped_prim_bounding_rect,
|
||||
device_pixel_scale,
|
||||
) {
|
||||
Some(info) => info,
|
||||
None => return false,
|
||||
};
|
||||
let transform = map_pic_to_raster.get_transform();
|
||||
|
||||
// TODO(gw): Almost all of the Picture types below use extra_gpu_cache_data
|
||||
// to store the same type of data. The exception is the filter
|
||||
// with a ColorMatrix, which stores the color matrix here. It's
|
||||
|
@ -2933,136 +3189,10 @@ impl PicturePrimitive {
|
|||
// Perhaps store the color matrix after the common data, even though
|
||||
// it's not used by that shader.
|
||||
|
||||
let surface = match raster_config.composite_mode {
|
||||
PictureCompositeMode::TileCache { .. } => {
|
||||
// For a picture surface, just push any child tasks and tile
|
||||
// blits up to the parent surface.
|
||||
let surface = &mut frame_state.surfaces[surface_index.0];
|
||||
surface.tasks.extend(child_tasks);
|
||||
|
||||
return true;
|
||||
}
|
||||
PictureCompositeMode::Filter(FilterOp::Blur(blur_radius)) => {
|
||||
let blur_std_deviation = blur_radius * device_pixel_scale.0;
|
||||
let scale_factors = scale_factors(&transform);
|
||||
let blur_std_deviation = DeviceSize::new(
|
||||
blur_std_deviation * scale_factors.0,
|
||||
blur_std_deviation * scale_factors.1
|
||||
);
|
||||
let inflation_factor = frame_state.surfaces[raster_config.surface_index.0].inflation_factor;
|
||||
let inflation_factor = (inflation_factor * device_pixel_scale.0).ceil() as i32;
|
||||
|
||||
// The clipped field is the part of the picture that is visible
|
||||
// on screen. The unclipped field is the screen-space rect of
|
||||
// the complete picture, if no screen / clip-chain was applied
|
||||
// (this includes the extra space for blur region). To ensure
|
||||
// that we draw a large enough part of the picture to get correct
|
||||
// blur results, inflate that clipped area by the blur range, and
|
||||
// then intersect with the total screen rect, to minimize the
|
||||
// allocation size.
|
||||
let mut device_rect = clipped
|
||||
.inflate(inflation_factor, inflation_factor)
|
||||
.intersection(&unclipped.to_i32())
|
||||
.unwrap();
|
||||
// Adjust the size to avoid introducing sampling errors during the down-scaling passes.
|
||||
// what would be even better is to rasterize the picture at the down-scaled size
|
||||
// directly.
|
||||
device_rect.size = RenderTask::adjusted_blur_source_size(
|
||||
device_rect.size,
|
||||
blur_std_deviation,
|
||||
);
|
||||
|
||||
let uv_rect_kind = calculate_uv_rect_kind(
|
||||
&pic_rect,
|
||||
&transform,
|
||||
&device_rect,
|
||||
device_pixel_scale,
|
||||
true,
|
||||
);
|
||||
|
||||
let picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, device_rect.size),
|
||||
unclipped.size,
|
||||
pic_index,
|
||||
device_rect.origin,
|
||||
child_tasks,
|
||||
uv_rect_kind,
|
||||
pic_context.raster_spatial_node_index,
|
||||
device_pixel_scale,
|
||||
);
|
||||
|
||||
let picture_task_id = frame_state.render_tasks.add(picture_task);
|
||||
|
||||
let blur_render_task = RenderTask::new_blur(
|
||||
blur_std_deviation,
|
||||
picture_task_id,
|
||||
frame_state.render_tasks,
|
||||
RenderTargetKind::Color,
|
||||
ClearMode::Transparent,
|
||||
);
|
||||
|
||||
let render_task_id = frame_state.render_tasks.add(blur_render_task);
|
||||
|
||||
frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
|
||||
|
||||
render_task_id
|
||||
}
|
||||
PictureCompositeMode::Filter(FilterOp::DropShadow(offset, blur_radius, color)) => {
|
||||
let blur_std_deviation = blur_radius * device_pixel_scale.0;
|
||||
let blur_range = (blur_std_deviation * BLUR_SAMPLE_SCALE).ceil() as i32;
|
||||
let rounded_std_dev = blur_std_deviation.round();
|
||||
let rounded_std_dev = DeviceSize::new(rounded_std_dev, rounded_std_dev);
|
||||
// The clipped field is the part of the picture that is visible
|
||||
// on screen. The unclipped field is the screen-space rect of
|
||||
// the complete picture, if no screen / clip-chain was applied
|
||||
// (this includes the extra space for blur region). To ensure
|
||||
// that we draw a large enough part of the picture to get correct
|
||||
// blur results, inflate that clipped area by the blur range, and
|
||||
// then intersect with the total screen rect, to minimize the
|
||||
// allocation size.
|
||||
let mut device_rect = clipped.inflate(blur_range, blur_range)
|
||||
.intersection(&unclipped.to_i32())
|
||||
.unwrap();
|
||||
device_rect.size = RenderTask::adjusted_blur_source_size(
|
||||
device_rect.size,
|
||||
rounded_std_dev,
|
||||
);
|
||||
|
||||
let uv_rect_kind = calculate_uv_rect_kind(
|
||||
&pic_rect,
|
||||
&transform,
|
||||
&device_rect,
|
||||
device_pixel_scale,
|
||||
true,
|
||||
);
|
||||
|
||||
let mut picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, device_rect.size),
|
||||
unclipped.size,
|
||||
pic_index,
|
||||
device_rect.origin,
|
||||
child_tasks,
|
||||
uv_rect_kind,
|
||||
pic_context.raster_spatial_node_index,
|
||||
device_pixel_scale,
|
||||
);
|
||||
picture_task.mark_for_saving();
|
||||
|
||||
let picture_task_id = frame_state.render_tasks.add(picture_task);
|
||||
|
||||
let blur_render_task = RenderTask::new_blur(
|
||||
rounded_std_dev,
|
||||
picture_task_id,
|
||||
frame_state.render_tasks,
|
||||
RenderTargetKind::Color,
|
||||
ClearMode::Transparent,
|
||||
);
|
||||
|
||||
self.secondary_render_task_id = Some(picture_task_id);
|
||||
|
||||
let render_task_id = frame_state.render_tasks.add(blur_render_task);
|
||||
frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
|
||||
|
||||
match raster_config.composite_mode {
|
||||
PictureCompositeMode::TileCache { .. } => {}
|
||||
PictureCompositeMode::Filter(FilterOp::Blur(..)) => {}
|
||||
PictureCompositeMode::Filter(FilterOp::DropShadow(offset, _, color)) => {
|
||||
if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handle) {
|
||||
// TODO(gw): This is very hacky code below! It stores an extra
|
||||
// brush primitive below for the special case of a
|
||||
|
@ -3090,40 +3220,8 @@ impl PicturePrimitive {
|
|||
request.push(shadow_rect);
|
||||
request.push([0.0, 0.0, 0.0, 0.0]);
|
||||
}
|
||||
|
||||
render_task_id
|
||||
}
|
||||
PictureCompositeMode::MixBlend(..) if !frame_context.fb_config.gpu_supports_advanced_blend => {
|
||||
let uv_rect_kind = calculate_uv_rect_kind(
|
||||
&pic_rect,
|
||||
&transform,
|
||||
&clipped,
|
||||
device_pixel_scale,
|
||||
true,
|
||||
);
|
||||
|
||||
let picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, clipped.size),
|
||||
unclipped.size,
|
||||
pic_index,
|
||||
clipped.origin,
|
||||
child_tasks,
|
||||
uv_rect_kind,
|
||||
pic_context.raster_spatial_node_index,
|
||||
device_pixel_scale,
|
||||
);
|
||||
|
||||
let readback_task_id = frame_state.render_tasks.add(
|
||||
RenderTask::new_readback(clipped)
|
||||
);
|
||||
|
||||
self.secondary_render_task_id = Some(readback_task_id);
|
||||
frame_state.surfaces[surface_index.0].tasks.push(readback_task_id);
|
||||
|
||||
let render_task_id = frame_state.render_tasks.add(picture_task);
|
||||
frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
|
||||
render_task_id
|
||||
}
|
||||
PictureCompositeMode::MixBlend(..) if !frame_context.fb_config.gpu_supports_advanced_blend => {}
|
||||
PictureCompositeMode::Filter(ref filter) => {
|
||||
if let FilterOp::ColorMatrix(m) = *filter {
|
||||
if let Some(mut request) = frame_state.gpu_cache.request(&mut self.extra_gpu_data_handle) {
|
||||
|
@ -3132,92 +3230,14 @@ impl PicturePrimitive {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
let uv_rect_kind = calculate_uv_rect_kind(
|
||||
&pic_rect,
|
||||
&transform,
|
||||
&clipped,
|
||||
device_pixel_scale,
|
||||
true,
|
||||
);
|
||||
|
||||
let picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, clipped.size),
|
||||
unclipped.size,
|
||||
pic_index,
|
||||
clipped.origin,
|
||||
child_tasks,
|
||||
uv_rect_kind,
|
||||
pic_context.raster_spatial_node_index,
|
||||
device_pixel_scale,
|
||||
);
|
||||
|
||||
let render_task_id = frame_state.render_tasks.add(picture_task);
|
||||
frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
|
||||
render_task_id
|
||||
}
|
||||
PictureCompositeMode::ComponentTransferFilter(handle) => {
|
||||
let filter_data = &mut data_stores.filter_data[handle];
|
||||
filter_data.update(frame_state);
|
||||
|
||||
let uv_rect_kind = calculate_uv_rect_kind(
|
||||
&pic_rect,
|
||||
&transform,
|
||||
&clipped,
|
||||
device_pixel_scale,
|
||||
true,
|
||||
);
|
||||
|
||||
let picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, clipped.size),
|
||||
unclipped.size,
|
||||
pic_index,
|
||||
clipped.origin,
|
||||
child_tasks,
|
||||
uv_rect_kind,
|
||||
pic_context.raster_spatial_node_index,
|
||||
device_pixel_scale,
|
||||
);
|
||||
|
||||
let render_task_id = frame_state.render_tasks.add(picture_task);
|
||||
frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
|
||||
render_task_id
|
||||
}
|
||||
PictureCompositeMode::MixBlend(..) |
|
||||
PictureCompositeMode::Blit(_) => {
|
||||
// The SplitComposite shader used for 3d contexts doesn't snap
|
||||
// to pixels, so we shouldn't snap our uv coordinates either.
|
||||
let supports_snapping = match self.context_3d {
|
||||
Picture3DContext::In{ .. } => false,
|
||||
_ => true,
|
||||
};
|
||||
|
||||
let uv_rect_kind = calculate_uv_rect_kind(
|
||||
&pic_rect,
|
||||
&transform,
|
||||
&clipped,
|
||||
device_pixel_scale,
|
||||
supports_snapping,
|
||||
);
|
||||
|
||||
let picture_task = RenderTask::new_picture(
|
||||
RenderTaskLocation::Dynamic(None, clipped.size),
|
||||
unclipped.size,
|
||||
pic_index,
|
||||
clipped.origin,
|
||||
child_tasks,
|
||||
uv_rect_kind,
|
||||
pic_context.raster_spatial_node_index,
|
||||
device_pixel_scale,
|
||||
);
|
||||
|
||||
let render_task_id = frame_state.render_tasks.add(picture_task);
|
||||
frame_state.surfaces[surface_index.0].tasks.push(render_task_id);
|
||||
render_task_id
|
||||
}
|
||||
};
|
||||
|
||||
frame_state.surfaces[raster_config.surface_index.0].surface = Some(surface);
|
||||
PictureCompositeMode::Blit(_) => {}
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
|
|
@ -988,7 +988,10 @@ impl BrushSegment {
|
|||
);
|
||||
|
||||
let clip_task_id = frame_state.render_tasks.add(clip_task);
|
||||
frame_state.surfaces[surface_index.0].tasks.push(clip_task_id);
|
||||
frame_state.render_tasks.add_dependency(
|
||||
frame_state.surfaces[surface_index.0].render_tasks.unwrap().port,
|
||||
clip_task_id,
|
||||
);
|
||||
ClipMaskKind::Mask(clip_task_id)
|
||||
}
|
||||
None => {
|
||||
|
@ -2470,8 +2473,13 @@ impl PrimitiveStore {
|
|||
PrimitiveInstanceKind::Picture { pic_index ,.. } => {
|
||||
let pic = &mut self.pictures[pic_index.0];
|
||||
|
||||
let clipped_prim_bounding_rect = scratch
|
||||
.prim_info[prim_instance.visibility_info.0 as usize]
|
||||
.clipped_world_rect;
|
||||
|
||||
match pic.take_context(
|
||||
pic_index,
|
||||
clipped_prim_bounding_rect,
|
||||
pic_context.surface_spatial_node_index,
|
||||
pic_context.raster_spatial_node_index,
|
||||
pic_context.surface_index,
|
||||
|
@ -2484,6 +2492,8 @@ impl PrimitiveStore {
|
|||
println!("\tculled for carrying an invisible composite filter");
|
||||
}
|
||||
|
||||
prim_instance.visibility_info = PrimitiveVisibilityIndex::INVALID;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -3071,9 +3081,6 @@ impl PrimitiveStore {
|
|||
let pic = &mut self.pictures[pic_index.0];
|
||||
let prim_info = &scratch.prim_info[prim_instance.visibility_info.0 as usize];
|
||||
if pic.prepare_for_render(
|
||||
*pic_index,
|
||||
prim_info.clipped_world_rect,
|
||||
pic_context.surface_index,
|
||||
frame_context,
|
||||
frame_state,
|
||||
data_stores,
|
||||
|
@ -3747,7 +3754,10 @@ impl PrimitiveInstance {
|
|||
let clip_task_index = ClipTaskIndex(scratch.clip_mask_instances.len() as _);
|
||||
scratch.clip_mask_instances.push(ClipMaskKind::Mask(clip_task_id));
|
||||
prim_info.clip_task_index = clip_task_index;
|
||||
frame_state.surfaces[pic_context.surface_index.0].tasks.push(clip_task_id);
|
||||
frame_state.render_tasks.add_dependency(
|
||||
frame_state.surfaces[pic_context.surface_index.0].render_tasks.unwrap().port,
|
||||
clip_task_id,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3168,7 +3168,7 @@ impl Renderer {
|
|||
}
|
||||
|
||||
if self.debug_flags.contains(DebugFlags::ECHO_DRIVER_MESSAGES) {
|
||||
Device::echo_driver_messages(self.device.gl());
|
||||
self.device.echo_driver_messages();
|
||||
}
|
||||
|
||||
results.stats.texture_upload_kb = self.profile_counters.texture_data_uploaded.get();
|
||||
|
|
|
@ -2258,7 +2258,7 @@ bool BytecodeEmitter::allocateResumeIndex(ptrdiff_t offset,
|
|||
static constexpr uint32_t MaxResumeIndex = JS_BITMASK(24);
|
||||
|
||||
static_assert(
|
||||
MaxResumeIndex < uint32_t(AbstractGeneratorObject::RESUME_INDEX_CLOSING),
|
||||
MaxResumeIndex < uint32_t(AbstractGeneratorObject::RESUME_INDEX_RUNNING),
|
||||
"resumeIndex should not include magic AbstractGeneratorObject "
|
||||
"resumeIndex values");
|
||||
static_assert(
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// |jit-test| crash; skip-if: getBuildConfiguration()['arm64']
|
||||
//
|
||||
// Test skipped on ARM64 due to bug 1549763.
|
||||
|
||||
for (var actual = .5; actual < 100; actual++) {
|
||||
var test2 = {
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
function testNativeGetter() {
|
||||
function test() {
|
||||
var xs = [Symbol("a"), Symbol("b")];
|
||||
var ys = ["a", "b"];
|
||||
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
var r = xs[i & 1].description;
|
||||
assertEq(r, ys[i & 1]);
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) test();
|
||||
}
|
||||
testNativeGetter();
|
||||
|
||||
function testScriptedGetter() {
|
||||
Object.defineProperty(Symbol.prototype, "desc", {
|
||||
get() {
|
||||
"use strict";
|
||||
assertEq(typeof this, "symbol");
|
||||
return this.description;
|
||||
}
|
||||
});
|
||||
|
||||
function test() {
|
||||
var xs = [Symbol("a"), Symbol("b")];
|
||||
var ys = ["a", "b"];
|
||||
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
var r = xs[i & 1].desc;
|
||||
assertEq(r, ys[i & 1]);
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) test();
|
||||
}
|
||||
testScriptedGetter();
|
||||
|
||||
function testScriptedGetterNonStrict() {
|
||||
Object.defineProperty(Symbol.prototype, "desc_nonstrict", {
|
||||
get() {
|
||||
assertEq(typeof this, "object");
|
||||
return this.description;
|
||||
}
|
||||
});
|
||||
|
||||
function test() {
|
||||
var xs = [Symbol("a"), Symbol("b")];
|
||||
var ys = ["a", "b"];
|
||||
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
var r = xs[i & 1].desc_nonstrict;
|
||||
assertEq(r, ys[i & 1]);
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) test();
|
||||
}
|
||||
testScriptedGetterNonStrict();
|
||||
|
||||
function testNativeGetterPrototype() {
|
||||
Object.defineProperty(Object.prototype, "description_proto",
|
||||
Object.getOwnPropertyDescriptor(Symbol.prototype, "description"));
|
||||
|
||||
function test() {
|
||||
var xs = [Symbol("a"), Symbol("b")];
|
||||
var ys = ["a", "b"];
|
||||
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
var r = xs[i & 1].description_proto;
|
||||
assertEq(r, ys[i & 1]);
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) test();
|
||||
}
|
||||
testNativeGetterPrototype();
|
||||
|
||||
function testScriptedGetterPrototype() {
|
||||
Object.defineProperty(Object.prototype, "desc_proto", {
|
||||
get() {
|
||||
"use strict";
|
||||
assertEq(typeof this, "symbol");
|
||||
return this.description;
|
||||
}
|
||||
});
|
||||
|
||||
function test() {
|
||||
var xs = [Symbol("a"), Symbol("b")];
|
||||
var ys = ["a", "b"];
|
||||
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
var r = xs[i & 1].desc_proto;
|
||||
assertEq(r, ys[i & 1]);
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) test();
|
||||
}
|
||||
testScriptedGetterPrototype();
|
||||
|
||||
function testScriptedGetterNonStrictPrototype() {
|
||||
Object.defineProperty(Object.prototype, "desc_nonstrict_proto", {
|
||||
get() {
|
||||
assertEq(typeof this, "object");
|
||||
return this.description;
|
||||
}
|
||||
});
|
||||
|
||||
function test() {
|
||||
var xs = [Symbol("a"), Symbol("b")];
|
||||
var ys = ["a", "b"];
|
||||
|
||||
for (var i = 0; i < 100; ++i) {
|
||||
var r = xs[i & 1].desc_nonstrict_proto;
|
||||
assertEq(r, ys[i & 1]);
|
||||
}
|
||||
}
|
||||
for (var i = 0; i < 2; ++i) test();
|
||||
}
|
||||
testScriptedGetterNonStrictPrototype();
|
|
@ -0,0 +1,21 @@
|
|||
// An onPop handler can return its input argument for async generators. The
|
||||
// debugger correctly adjusts the state of the async generator object.
|
||||
|
||||
let g = newGlobal({newCompartment: true});
|
||||
g.eval(`
|
||||
async function* f() {}
|
||||
`);
|
||||
|
||||
let hits = 0;
|
||||
let dbg = new Debugger(g);
|
||||
dbg.onEnterFrame = frame => {
|
||||
frame.onPop = completion => {
|
||||
hits++;
|
||||
return completion;
|
||||
};
|
||||
};
|
||||
|
||||
let it = g.f();
|
||||
let p = it.next();
|
||||
|
||||
assertEq(hits, 1);
|
|
@ -91,6 +91,13 @@ class MOZ_RAII BaselineCacheIRCompiler : public CacheIRCompiler {
|
|||
enum class NativeCallType { Native, ClassHook };
|
||||
bool emitCallNativeShared(NativeCallType callType);
|
||||
|
||||
MOZ_MUST_USE bool emitCallScriptedGetterResultShared(
|
||||
TypedOrValueRegister receiver);
|
||||
|
||||
template <typename T, typename CallVM>
|
||||
MOZ_MUST_USE bool emitCallNativeGetterResultShared(T receiver,
|
||||
const CallVM& emitCallVM);
|
||||
|
||||
public:
|
||||
friend class AutoStubFrame;
|
||||
|
||||
|
@ -553,9 +560,8 @@ bool BaselineCacheIRCompiler::emitGuardHasGetterSetter() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BaselineCacheIRCompiler::emitCallScriptedGetterResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
bool BaselineCacheIRCompiler::emitCallScriptedGetterResultShared(
|
||||
TypedOrValueRegister receiver) {
|
||||
Address getterAddr(stubAddress(reader.stubOffset()));
|
||||
bool isSameRealm = reader.readBool();
|
||||
|
||||
|
@ -589,10 +595,10 @@ bool BaselineCacheIRCompiler::emitCallScriptedGetterResult() {
|
|||
// JitStackAlignment.
|
||||
masm.alignJitStackBasedOnNArgs(0);
|
||||
|
||||
// Getter is called with 0 arguments, just |obj| as thisv.
|
||||
// Getter is called with 0 arguments, just |receiver| as thisv.
|
||||
// Note that we use Push, not push, so that callJit will align the stack
|
||||
// properly on ARM.
|
||||
masm.Push(TypedOrValueRegister(MIRType::Object, AnyRegister(obj)));
|
||||
masm.Push(receiver);
|
||||
|
||||
EmitBaselineCreateStubFrameDescriptor(masm, scratch, JitFrameLayout::Size());
|
||||
masm.Push(Imm32(0)); // ActualArgc is 0
|
||||
|
@ -622,9 +628,24 @@ bool BaselineCacheIRCompiler::emitCallScriptedGetterResult() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BaselineCacheIRCompiler::emitCallNativeGetterResult() {
|
||||
bool BaselineCacheIRCompiler::emitCallScriptedGetterResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
|
||||
return emitCallScriptedGetterResultShared(
|
||||
TypedOrValueRegister(MIRType::Object, AnyRegister(obj)));
|
||||
}
|
||||
|
||||
bool BaselineCacheIRCompiler::emitCallScriptedGetterByValueResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
|
||||
|
||||
return emitCallScriptedGetterResultShared(val);
|
||||
}
|
||||
|
||||
template <typename T, typename CallVM>
|
||||
bool BaselineCacheIRCompiler::emitCallNativeGetterResultShared(
|
||||
T receiver, const CallVM& emitCallVM) {
|
||||
Address getterAddr(stubAddress(reader.stubOffset()));
|
||||
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
|
@ -637,17 +658,37 @@ bool BaselineCacheIRCompiler::emitCallNativeGetterResult() {
|
|||
// Load the callee in the scratch register.
|
||||
masm.loadPtr(getterAddr, scratch);
|
||||
|
||||
masm.Push(obj);
|
||||
masm.Push(receiver);
|
||||
masm.Push(scratch);
|
||||
|
||||
using Fn =
|
||||
bool (*)(JSContext*, HandleFunction, HandleObject, MutableHandleValue);
|
||||
callVM<Fn, CallNativeGetter>(masm);
|
||||
emitCallVM();
|
||||
|
||||
stubFrame.leave(masm);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaselineCacheIRCompiler::emitCallNativeGetterResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
|
||||
return emitCallNativeGetterResultShared(obj, [this]() {
|
||||
using Fn =
|
||||
bool (*)(JSContext*, HandleFunction, HandleObject, MutableHandleValue);
|
||||
callVM<Fn, CallNativeGetter>(masm);
|
||||
});
|
||||
}
|
||||
|
||||
bool BaselineCacheIRCompiler::emitCallNativeGetterByValueResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
|
||||
|
||||
return emitCallNativeGetterResultShared(val, [this]() {
|
||||
using Fn =
|
||||
bool (*)(JSContext*, HandleFunction, HandleValue, MutableHandleValue);
|
||||
callVM<Fn, CallNativeGetterByValue>(masm);
|
||||
});
|
||||
}
|
||||
|
||||
bool BaselineCacheIRCompiler::emitCallProxyGetResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
|
|
|
@ -920,23 +920,26 @@ static void EmitCallGetterResultNoGuards(CacheIRWriter& writer, JSObject* obj,
|
|||
MOZ_ASSERT(target->isBuiltinNative());
|
||||
writer.callNativeGetterResult(receiverId, target);
|
||||
writer.typeMonitorResult();
|
||||
} break;
|
||||
break;
|
||||
}
|
||||
case CanAttachScriptedGetter: {
|
||||
JSFunction* target = &shape->getterValue().toObject().as<JSFunction>();
|
||||
MOZ_ASSERT(target->hasJitEntry());
|
||||
writer.callScriptedGetterResult(receiverId, target);
|
||||
writer.typeMonitorResult();
|
||||
} break;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// CanAttachNativeGetProp guarantees that the getter is either a native or
|
||||
// a scripted function.
|
||||
MOZ_ASSERT_UNREACHABLE("Can't attach getter");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void EmitCallGetterResult(CacheIRWriter& writer, JSObject* obj,
|
||||
JSObject* holder, Shape* shape,
|
||||
ObjOperandId objId, ObjOperandId receiverId,
|
||||
ICState::Mode mode) {
|
||||
static void EmitCallGetterResultGuards(CacheIRWriter& writer, JSObject* obj,
|
||||
JSObject* holder, Shape* shape,
|
||||
ObjOperandId objId, ICState::Mode mode) {
|
||||
// Use the megamorphic guard if we're in megamorphic mode, except if |obj|
|
||||
// is a Window as GuardHasGetterSetter doesn't support this yet (Window may
|
||||
// require outerizing).
|
||||
|
@ -953,7 +956,13 @@ static void EmitCallGetterResult(CacheIRWriter& writer, JSObject* obj,
|
|||
} else {
|
||||
writer.guardHasGetterSetter(objId, shape);
|
||||
}
|
||||
}
|
||||
|
||||
static void EmitCallGetterResult(CacheIRWriter& writer, JSObject* obj,
|
||||
JSObject* holder, Shape* shape,
|
||||
ObjOperandId objId, ObjOperandId receiverId,
|
||||
ICState::Mode mode) {
|
||||
EmitCallGetterResultGuards(writer, obj, holder, shape, objId, mode);
|
||||
EmitCallGetterResultNoGuards(writer, obj, holder, shape, receiverId);
|
||||
}
|
||||
|
||||
|
@ -963,6 +972,36 @@ static void EmitCallGetterResult(CacheIRWriter& writer, JSObject* obj,
|
|||
EmitCallGetterResult(writer, obj, holder, shape, objId, objId, mode);
|
||||
}
|
||||
|
||||
static void EmitCallGetterByValueResult(CacheIRWriter& writer, JSObject* obj,
|
||||
JSObject* holder, Shape* shape,
|
||||
ObjOperandId objId,
|
||||
ValOperandId receiverId,
|
||||
ICState::Mode mode) {
|
||||
EmitCallGetterResultGuards(writer, obj, holder, shape, objId, mode);
|
||||
|
||||
switch (IsCacheableGetPropCall(obj, holder, shape)) {
|
||||
case CanAttachNativeGetter: {
|
||||
JSFunction* target = &shape->getterValue().toObject().as<JSFunction>();
|
||||
MOZ_ASSERT(target->isBuiltinNative());
|
||||
writer.callNativeGetterByValueResult(receiverId, target);
|
||||
writer.typeMonitorResult();
|
||||
break;
|
||||
}
|
||||
case CanAttachScriptedGetter: {
|
||||
JSFunction* target = &shape->getterValue().toObject().as<JSFunction>();
|
||||
MOZ_ASSERT(target->hasJitEntry());
|
||||
writer.callScriptedGetterByValueResult(receiverId, target);
|
||||
writer.typeMonitorResult();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// CanAttachNativeGetProp guarantees that the getter is either a native or
|
||||
// a scripted function.
|
||||
MOZ_ASSERT_UNREACHABLE("Can't attach getter");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void GetPropIRGenerator::attachMegamorphicNativeSlot(ObjOperandId objId,
|
||||
jsid id,
|
||||
bool handleMissing) {
|
||||
|
@ -1850,33 +1889,59 @@ AttachDecision GetPropIRGenerator::tryAttachPrimitive(ValOperandId valId,
|
|||
RootedNativeObject holder(cx_);
|
||||
NativeGetPropCacheability type = CanAttachNativeGetProp(
|
||||
cx_, proto, id, &holder, &shape, pc_, resultFlags_);
|
||||
if (type == CanAttachTemporarilyUnoptimizable) {
|
||||
return AttachDecision::TemporarilyUnoptimizable;
|
||||
}
|
||||
if (type != CanAttachReadSlot) {
|
||||
return AttachDecision::NoAction;
|
||||
}
|
||||
switch (type) {
|
||||
case CanAttachNone:
|
||||
return AttachDecision::NoAction;
|
||||
case CanAttachTemporarilyUnoptimizable:
|
||||
return AttachDecision::TemporarilyUnoptimizable;
|
||||
case CanAttachReadSlot: {
|
||||
if (holder) {
|
||||
// Instantiate this property, for use during Ion compilation.
|
||||
if (IsIonEnabled(cx_)) {
|
||||
EnsureTrackPropertyTypes(cx_, holder, id);
|
||||
}
|
||||
}
|
||||
|
||||
if (holder) {
|
||||
// Instantiate this property, for use during Ion compilation.
|
||||
if (IsIonEnabled(cx_)) {
|
||||
EnsureTrackPropertyTypes(cx_, holder, id);
|
||||
if (val_.isNumber()) {
|
||||
writer.guardIsNumber(valId);
|
||||
} else {
|
||||
writer.guardType(valId, val_.type());
|
||||
}
|
||||
maybeEmitIdGuard(id);
|
||||
|
||||
ObjOperandId protoId = writer.loadObject(proto);
|
||||
EmitReadSlotResult(writer, proto, holder, shape, protoId);
|
||||
EmitReadSlotReturn(writer, proto, holder, shape);
|
||||
|
||||
trackAttached("PrimitiveSlot");
|
||||
return AttachDecision::Attach;
|
||||
}
|
||||
case CanAttachScriptedGetter:
|
||||
case CanAttachNativeGetter: {
|
||||
MOZ_ASSERT(!idempotent());
|
||||
|
||||
// The primitive stubs don't currently support |super| access.
|
||||
if (isSuper()) {
|
||||
return AttachDecision::NoAction;
|
||||
}
|
||||
|
||||
if (val_.isNumber()) {
|
||||
writer.guardIsNumber(valId);
|
||||
} else {
|
||||
writer.guardType(valId, val_.type());
|
||||
}
|
||||
maybeEmitIdGuard(id);
|
||||
|
||||
ObjOperandId protoId = writer.loadObject(proto);
|
||||
EmitCallGetterByValueResult(writer, proto, holder, shape, protoId, valId,
|
||||
mode_);
|
||||
|
||||
trackAttached("PrimitiveGetter");
|
||||
return AttachDecision::Attach;
|
||||
}
|
||||
}
|
||||
|
||||
if (val_.isNumber()) {
|
||||
writer.guardIsNumber(valId);
|
||||
} else {
|
||||
writer.guardType(valId, val_.type());
|
||||
}
|
||||
maybeEmitIdGuard(id);
|
||||
|
||||
ObjOperandId protoId = writer.loadObject(proto);
|
||||
EmitReadSlotResult(writer, proto, holder, shape, protoId);
|
||||
EmitReadSlotReturn(writer, proto, holder, shape);
|
||||
|
||||
trackAttached("Primitive");
|
||||
return AttachDecision::Attach;
|
||||
MOZ_CRASH("Bad NativeGetPropCacheability");
|
||||
}
|
||||
|
||||
AttachDecision GetPropIRGenerator::tryAttachStringLength(ValOperandId valId,
|
||||
|
|
|
@ -326,7 +326,9 @@ extern const uint32_t ArgLengths[];
|
|||
_(LoadEnvironmentDynamicSlotResult, Id, Field) \
|
||||
_(LoadObjectResult, Id) \
|
||||
_(CallScriptedGetterResult, Id, Field, Byte) \
|
||||
_(CallScriptedGetterByValueResult, Id, Field, Byte) \
|
||||
_(CallNativeGetterResult, Id, Field) \
|
||||
_(CallNativeGetterByValueResult, Id, Field) \
|
||||
_(CallProxyGetResult, Id, Field) \
|
||||
_(CallProxyGetByValueResult, Id, Id) \
|
||||
_(CallProxyHasPropResult, Id, Id, Byte) \
|
||||
|
@ -1639,10 +1641,19 @@ class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter {
|
|||
addStubField(uintptr_t(getter), StubField::Type::JSObject);
|
||||
buffer_.writeByte(cx_->realm() == getter->realm());
|
||||
}
|
||||
void callScriptedGetterByValueResult(ValOperandId obj, JSFunction* getter) {
|
||||
writeOpWithOperandId(CacheOp::CallScriptedGetterByValueResult, obj);
|
||||
addStubField(uintptr_t(getter), StubField::Type::JSObject);
|
||||
buffer_.writeByte(cx_->realm() == getter->realm());
|
||||
}
|
||||
void callNativeGetterResult(ObjOperandId obj, JSFunction* getter) {
|
||||
writeOpWithOperandId(CacheOp::CallNativeGetterResult, obj);
|
||||
addStubField(uintptr_t(getter), StubField::Type::JSObject);
|
||||
}
|
||||
void callNativeGetterByValueResult(ValOperandId obj, JSFunction* getter) {
|
||||
writeOpWithOperandId(CacheOp::CallNativeGetterByValueResult, obj);
|
||||
addStubField(uintptr_t(getter), StubField::Type::JSObject);
|
||||
}
|
||||
void callProxyGetResult(ObjOperandId obj, jsid id) {
|
||||
writeOpWithOperandId(CacheOp::CallProxyGetResult, obj);
|
||||
addStubField(uintptr_t(JSID_BITS(id)), StubField::Type::Id);
|
||||
|
|
|
@ -4358,13 +4358,13 @@ bool CacheIRCompiler::emitCallIsSuspendedGeneratorResult() {
|
|||
&GeneratorObject::class_, scratch2, scratch,
|
||||
&returnFalse);
|
||||
|
||||
// If the resumeIndex slot holds an int32 value < RESUME_INDEX_CLOSING,
|
||||
// If the resumeIndex slot holds an int32 value < RESUME_INDEX_RUNNING,
|
||||
// the generator is suspended.
|
||||
Address addr(scratch, AbstractGeneratorObject::offsetOfResumeIndexSlot());
|
||||
masm.branchTestInt32(Assembler::NotEqual, addr, &returnFalse);
|
||||
masm.unboxInt32(addr, scratch);
|
||||
masm.branch32(Assembler::AboveOrEqual, scratch,
|
||||
Imm32(AbstractGeneratorObject::RESUME_INDEX_CLOSING),
|
||||
Imm32(AbstractGeneratorObject::RESUME_INDEX_RUNNING),
|
||||
&returnFalse);
|
||||
|
||||
masm.moveValue(BooleanValue(true), output.valueReg());
|
||||
|
|
|
@ -113,6 +113,11 @@ class MOZ_RAII IonCacheIRCompiler : public CacheIRCompiler {
|
|||
}
|
||||
|
||||
MOZ_MUST_USE bool emitAddAndStoreSlotShared(CacheOp op);
|
||||
MOZ_MUST_USE bool emitCallScriptedGetterResultShared(
|
||||
TypedOrValueRegister receiver, TypedOrValueRegister output);
|
||||
MOZ_MUST_USE bool emitCallNativeGetterResultShared(
|
||||
TypedOrValueRegister receiver, const AutoOutputRegister& output,
|
||||
AutoSaveLiveRegisters& save);
|
||||
|
||||
bool needsPostBarrier() const {
|
||||
return ic_->asSetPropertyIC()->needsPostBarrier();
|
||||
|
@ -925,12 +930,8 @@ bool IonCacheIRCompiler::emitGuardHasGetterSetter() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool IonCacheIRCompiler::emitCallScriptedGetterResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
AutoSaveLiveRegisters save(*this);
|
||||
AutoOutputRegister output(*this);
|
||||
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
bool IonCacheIRCompiler::emitCallScriptedGetterResultShared(
|
||||
TypedOrValueRegister receiver, TypedOrValueRegister output) {
|
||||
JSFunction* target = &objectStubField(reader.stubOffset())->as<JSFunction>();
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
|
||||
|
@ -961,7 +962,7 @@ bool IonCacheIRCompiler::emitCallScriptedGetterResult() {
|
|||
for (size_t i = 0; i < target->nargs(); i++) {
|
||||
masm.Push(UndefinedValue());
|
||||
}
|
||||
masm.Push(TypedOrValueRegister(MIRType::Object, AnyRegister(obj)));
|
||||
masm.Push(receiver);
|
||||
|
||||
if (!isSameRealm) {
|
||||
masm.switchToRealm(target->realm(), scratch);
|
||||
|
@ -997,16 +998,34 @@ bool IonCacheIRCompiler::emitCallScriptedGetterResult() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool IonCacheIRCompiler::emitCallNativeGetterResult() {
|
||||
bool IonCacheIRCompiler::emitCallScriptedGetterResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
AutoSaveLiveRegisters save(*this);
|
||||
AutoOutputRegister output(*this);
|
||||
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
|
||||
return emitCallScriptedGetterResultShared(
|
||||
TypedOrValueRegister(MIRType::Object, AnyRegister(obj)), output);
|
||||
}
|
||||
|
||||
bool IonCacheIRCompiler::emitCallScriptedGetterByValueResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
AutoSaveLiveRegisters save(*this);
|
||||
AutoOutputRegister output(*this);
|
||||
|
||||
ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
|
||||
|
||||
return emitCallScriptedGetterResultShared(val, output);
|
||||
}
|
||||
|
||||
bool IonCacheIRCompiler::emitCallNativeGetterResultShared(
|
||||
TypedOrValueRegister receiver, const AutoOutputRegister& output,
|
||||
AutoSaveLiveRegisters& save) {
|
||||
JSFunction* target = &objectStubField(reader.stubOffset())->as<JSFunction>();
|
||||
MOZ_ASSERT(target->isNative());
|
||||
|
||||
AutoScratchRegister argJSContext(allocator, masm);
|
||||
AutoScratchRegisterMaybeOutput argJSContext(allocator, masm, output);
|
||||
AutoScratchRegister argUintN(allocator, masm);
|
||||
AutoScratchRegister argVp(allocator, masm);
|
||||
AutoScratchRegister scratch(allocator, masm);
|
||||
|
@ -1019,8 +1038,8 @@ bool IonCacheIRCompiler::emitCallNativeGetterResult() {
|
|||
// are the function arguments.
|
||||
|
||||
// Construct vp array:
|
||||
// Push object value for |this|
|
||||
masm.Push(TypedOrValueRegister(MIRType::Object, AnyRegister(obj)));
|
||||
// Push receiver value for |this|
|
||||
masm.Push(receiver);
|
||||
// Push callee/outparam.
|
||||
masm.Push(ObjectValue(*target));
|
||||
|
||||
|
@ -1071,6 +1090,27 @@ bool IonCacheIRCompiler::emitCallNativeGetterResult() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool IonCacheIRCompiler::emitCallNativeGetterResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
AutoSaveLiveRegisters save(*this);
|
||||
AutoOutputRegister output(*this);
|
||||
|
||||
Register obj = allocator.useRegister(masm, reader.objOperandId());
|
||||
|
||||
return emitCallNativeGetterResultShared(
|
||||
TypedOrValueRegister(MIRType::Object, AnyRegister(obj)), output, save);
|
||||
}
|
||||
|
||||
bool IonCacheIRCompiler::emitCallNativeGetterByValueResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
AutoSaveLiveRegisters save(*this);
|
||||
AutoOutputRegister output(*this);
|
||||
|
||||
ValueOperand val = allocator.useValueRegister(masm, reader.valOperandId());
|
||||
|
||||
return emitCallNativeGetterResultShared(val, output, save);
|
||||
}
|
||||
|
||||
bool IonCacheIRCompiler::emitCallProxyGetResult() {
|
||||
JitSpew(JitSpew_Codegen, __FUNCTION__);
|
||||
AutoSaveLiveRegisters save(*this);
|
||||
|
|
|
@ -56,6 +56,7 @@ namespace jit {
|
|||
_(BoxNonStrictThis, js::BoxNonStrictThis) \
|
||||
_(BuiltinProtoOperation, js::BuiltinProtoOperation) \
|
||||
_(CallNativeGetter, js::jit::CallNativeGetter) \
|
||||
_(CallNativeGetterByValue, js::jit::CallNativeGetterByValue) \
|
||||
_(CallNativeSetter, js::jit::CallNativeSetter) \
|
||||
_(CharCodeAt, js::jit::CharCodeAt) \
|
||||
_(CheckClassHeritageOperation, js::CheckClassHeritageOperation) \
|
||||
|
|
|
@ -1559,6 +1559,25 @@ bool CallNativeGetter(JSContext* cx, HandleFunction callee, HandleObject obj,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CallNativeGetterByValue(JSContext* cx, HandleFunction callee,
|
||||
HandleValue receiver, MutableHandleValue result) {
|
||||
AutoRealm ar(cx, callee);
|
||||
|
||||
MOZ_ASSERT(callee->isNative());
|
||||
JSNative natfun = callee->native();
|
||||
|
||||
JS::AutoValueArray<2> vp(cx);
|
||||
vp[0].setObject(*callee.get());
|
||||
vp[1].set(receiver);
|
||||
|
||||
if (!natfun(cx, 0, vp.begin())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
result.set(vp[0]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CallNativeSetter(JSContext* cx, HandleFunction callee, HandleObject obj,
|
||||
HandleValue rhs) {
|
||||
AutoRealm ar(cx, callee);
|
||||
|
|
|
@ -1056,6 +1056,10 @@ MOZ_MUST_USE bool BaselineGetFunctionThis(JSContext* cx, BaselineFrame* frame,
|
|||
MOZ_MUST_USE bool CallNativeGetter(JSContext* cx, HandleFunction callee,
|
||||
HandleObject obj, MutableHandleValue result);
|
||||
|
||||
MOZ_MUST_USE bool CallNativeGetterByValue(JSContext* cx, HandleFunction callee,
|
||||
HandleValue receiver,
|
||||
MutableHandleValue result);
|
||||
|
||||
MOZ_MUST_USE bool CallNativeSetter(JSContext* cx, HandleFunction callee,
|
||||
HandleObject obj, HandleValue rhs);
|
||||
|
||||
|
|
|
@ -1676,7 +1676,7 @@ static void AdjustGeneratorResumptionValue(JSContext* cx,
|
|||
// bytecode, so we have to simulate that here. For async generators, our
|
||||
// C++ implementation of AsyncGeneratorResolve will do this. So don't do it
|
||||
// twice:
|
||||
if (!frame.callee()->isAsync()) {
|
||||
if (!genObj->is<AsyncGeneratorObject>()) {
|
||||
JSObject* pair = CreateIterResultObject(cx, vp, true);
|
||||
if (!pair) {
|
||||
getAndClearExceptionThenThrow();
|
||||
|
@ -1687,6 +1687,12 @@ static void AdjustGeneratorResumptionValue(JSContext* cx,
|
|||
|
||||
// 2. The generator must be closed.
|
||||
genObj->setClosed();
|
||||
|
||||
// Async generators have additionally bookkeeping which must be adjusted
|
||||
// when switching over to the closed state.
|
||||
if (genObj->is<AsyncGeneratorObject>()) {
|
||||
genObj->as<AsyncGeneratorObject>().setCompleted();
|
||||
}
|
||||
} else if (frame.callee()->isAsync()) {
|
||||
if (AbstractGeneratorObject* genObj =
|
||||
GetGeneratorObjectForFrame(cx, frame)) {
|
||||
|
@ -2083,7 +2089,7 @@ ResumeMode Debugger::fireEnterFrame(JSContext* cx, MutableHandleValue vp) {
|
|||
// Assert that the hook won't be able to re-enter the generator.
|
||||
if (iter.hasScript() && *iter.pc() == JSOP_AFTERYIELD) {
|
||||
auto* genObj = GetGeneratorObjectForFrame(cx, iter.abstractFramePtr());
|
||||
MOZ_ASSERT(genObj->isRunning() || genObj->isClosing());
|
||||
MOZ_ASSERT(genObj->isRunning());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ bool AbstractGeneratorObject::suspend(JSContext* cx, HandleObject obj,
|
|||
|
||||
void AbstractGeneratorObject::finalSuspend(HandleObject obj) {
|
||||
auto* genObj = &obj->as<AbstractGeneratorObject>();
|
||||
MOZ_ASSERT(genObj->isRunning() || genObj->isClosing());
|
||||
MOZ_ASSERT(genObj->isRunning());
|
||||
genObj->setClosed();
|
||||
}
|
||||
|
||||
|
@ -139,6 +139,7 @@ bool js::GeneratorThrowOrReturn(JSContext* cx, AbstractFramePtr frame,
|
|||
Handle<AbstractGeneratorObject*> genObj,
|
||||
HandleValue arg,
|
||||
GeneratorResumeKind resumeKind) {
|
||||
MOZ_ASSERT(genObj->isRunning());
|
||||
if (resumeKind == GeneratorResumeKind::Throw) {
|
||||
cx->setPendingExceptionAndCaptureStack(arg);
|
||||
} else {
|
||||
|
@ -149,7 +150,6 @@ bool js::GeneratorThrowOrReturn(JSContext* cx, AbstractFramePtr frame,
|
|||
|
||||
RootedValue closing(cx, MagicValue(JS_GENERATOR_CLOSING));
|
||||
cx->setPendingException(closing, nullptr);
|
||||
genObj->setClosing();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -309,7 +309,7 @@ bool AbstractGeneratorObject::isAfterAwait() {
|
|||
}
|
||||
|
||||
bool AbstractGeneratorObject::isAfterYieldOrAwait(JSOp op) {
|
||||
if (isClosed() || isClosing() || isRunning()) {
|
||||
if (isClosed() || isRunning()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,10 +20,9 @@ enum class GeneratorResumeKind { Next, Throw, Return };
|
|||
|
||||
class AbstractGeneratorObject : public NativeObject {
|
||||
public:
|
||||
// Magic values stored in the resumeIndex slot when the generator is
|
||||
// Magic value stored in the resumeIndex slot when the generator is
|
||||
// running or closing. See the resumeIndex comment below.
|
||||
static const int32_t RESUME_INDEX_RUNNING = INT32_MAX;
|
||||
static const int32_t RESUME_INDEX_CLOSING = INT32_MAX - 1;
|
||||
|
||||
enum {
|
||||
CALLEE_SLOT = 0,
|
||||
|
@ -116,8 +115,7 @@ class AbstractGeneratorObject : public NativeObject {
|
|||
// The resumeIndex slot is abused for a few purposes. It's undefined if
|
||||
// it hasn't been set yet (before the initial yield), and null if the
|
||||
// generator is closed. If the generator is running, the resumeIndex is
|
||||
// RESUME_INDEX_RUNNING. If the generator is in that bizarre "closing"
|
||||
// state, the resumeIndex is RESUME_INDEX_CLOSING.
|
||||
// RESUME_INDEX_RUNNING.
|
||||
//
|
||||
// If the generator is suspended, it's the resumeIndex (stored as
|
||||
// JSOP_INITIALYIELD/JSOP_YIELD/JSOP_AWAIT operand) of the yield instruction
|
||||
|
@ -130,35 +128,26 @@ class AbstractGeneratorObject : public NativeObject {
|
|||
bool isRunning() const {
|
||||
return getFixedSlot(RESUME_INDEX_SLOT) == Int32Value(RESUME_INDEX_RUNNING);
|
||||
}
|
||||
bool isClosing() const {
|
||||
return getFixedSlot(RESUME_INDEX_SLOT) == Int32Value(RESUME_INDEX_CLOSING);
|
||||
}
|
||||
bool isSuspended() const {
|
||||
// Note: also update Baseline's IsSuspendedGenerator code if this
|
||||
// changes.
|
||||
static_assert(RESUME_INDEX_CLOSING < RESUME_INDEX_RUNNING,
|
||||
"test below should return false for RESUME_INDEX_RUNNING");
|
||||
Value resumeIndex = getFixedSlot(RESUME_INDEX_SLOT);
|
||||
return resumeIndex.isInt32() && resumeIndex.toInt32() < RESUME_INDEX_CLOSING;
|
||||
return resumeIndex.isInt32() && resumeIndex.toInt32() < RESUME_INDEX_RUNNING;
|
||||
}
|
||||
void setRunning() {
|
||||
MOZ_ASSERT(isSuspended());
|
||||
setFixedSlot(RESUME_INDEX_SLOT, Int32Value(RESUME_INDEX_RUNNING));
|
||||
}
|
||||
void setClosing() {
|
||||
MOZ_ASSERT(isRunning());
|
||||
setFixedSlot(RESUME_INDEX_SLOT, Int32Value(RESUME_INDEX_CLOSING));
|
||||
}
|
||||
void setResumeIndex(jsbytecode* pc) {
|
||||
MOZ_ASSERT(*pc == JSOP_INITIALYIELD || *pc == JSOP_YIELD ||
|
||||
*pc == JSOP_AWAIT);
|
||||
|
||||
MOZ_ASSERT_IF(JSOp(*pc) == JSOP_INITIALYIELD,
|
||||
getFixedSlot(RESUME_INDEX_SLOT).isUndefined());
|
||||
MOZ_ASSERT_IF(JSOp(*pc) != JSOP_INITIALYIELD, isRunning() || isClosing());
|
||||
MOZ_ASSERT_IF(JSOp(*pc) != JSOP_INITIALYIELD, isRunning());
|
||||
|
||||
uint32_t resumeIndex = GET_UINT24(pc);
|
||||
MOZ_ASSERT(resumeIndex < uint32_t(RESUME_INDEX_CLOSING));
|
||||
MOZ_ASSERT(resumeIndex < uint32_t(RESUME_INDEX_RUNNING));
|
||||
|
||||
setFixedSlot(RESUME_INDEX_SLOT, Int32Value(resumeIndex));
|
||||
MOZ_ASSERT(isSuspended());
|
||||
|
|
|
@ -966,7 +966,7 @@ static bool intrinsic_GeneratorIsRunning(JSContext* cx, unsigned argc,
|
|||
MOZ_ASSERT(args[0].isObject());
|
||||
|
||||
GeneratorObject* genObj = &args[0].toObject().as<GeneratorObject>();
|
||||
args.rval().setBoolean(genObj->isRunning() || genObj->isClosing());
|
||||
args.rval().setBoolean(genObj->isRunning());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -2420,8 +2420,7 @@ nsView* nsDocumentViewer::FindContainerView() {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsIFrame* subdocFrame =
|
||||
nsLayoutUtils::GetRealPrimaryFrameFor(containerElement);
|
||||
nsIFrame* subdocFrame = containerElement->GetPrimaryFrame();
|
||||
if (!subdocFrame) {
|
||||
// XXX Silenced by default in bug 1175289
|
||||
LAYOUT_WARNING("Subdocument container has no frame");
|
||||
|
|
|
@ -1579,16 +1579,6 @@ bool nsLayoutUtils::IsPrimaryStyleFrame(const nsIFrame* aFrame) {
|
|||
return aFrame->IsPrimaryFrame();
|
||||
}
|
||||
|
||||
/* static */
|
||||
nsIFrame* nsLayoutUtils::GetRealPrimaryFrameFor(const nsIContent* aContent) {
|
||||
nsIFrame* frame = aContent->GetPrimaryFrame();
|
||||
if (!frame) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nsPlaceholderFrame::GetRealFrameFor(frame);
|
||||
}
|
||||
|
||||
nsIFrame* nsLayoutUtils::GetFloatFromPlaceholder(nsIFrame* aFrame) {
|
||||
NS_ASSERTION(aFrame->IsPlaceholderFrame(), "Must have a placeholder here");
|
||||
if (aFrame->GetStateBits() & PLACEHOLDER_FOR_FLOAT) {
|
||||
|
|
|
@ -434,15 +434,6 @@ class nsLayoutUtils {
|
|||
*/
|
||||
static bool IsPrimaryStyleFrame(const nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Gets the real primary frame associated with the content object.
|
||||
*
|
||||
* In the case of absolutely positioned elements and floated elements,
|
||||
* the real primary frame is the frame that is out of the flow and not the
|
||||
* placeholder frame.
|
||||
*/
|
||||
static nsIFrame* GetRealPrimaryFrameFor(const nsIContent* aContent);
|
||||
|
||||
#ifdef DEBUG
|
||||
// TODO: remove, see bug 598468.
|
||||
static bool gPreventAssertInCompareTreePosition;
|
||||
|
|
|
@ -1905,7 +1905,10 @@ bool BuildTextRunsScanner::ContinueTextRunAcrossFrames(nsTextFrame* aFrame1,
|
|||
}
|
||||
|
||||
const nsStyleText* textStyle2 = sc2->StyleText();
|
||||
if (sc1 == sc2) return true;
|
||||
if (textStyle1->mTextTransform != textStyle2->mTextTransform ||
|
||||
textStyle1->EffectiveWordBreak() != textStyle2->EffectiveWordBreak()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsPresContext* pc = aFrame1->PresContext();
|
||||
MOZ_ASSERT(pc == aFrame2->PresContext());
|
||||
|
@ -1916,7 +1919,6 @@ bool BuildTextRunsScanner::ContinueTextRunAcrossFrames(nsTextFrame* aFrame1,
|
|||
nscoord letterSpacing2 = LetterSpacing(aFrame2);
|
||||
return fontStyle1->mFont == fontStyle2->mFont &&
|
||||
fontStyle1->mLanguage == fontStyle2->mLanguage &&
|
||||
textStyle1->mTextTransform == textStyle2->mTextTransform &&
|
||||
nsLayoutUtils::GetTextRunFlagsForStyle(sc1, pc, fontStyle1, textStyle1,
|
||||
letterSpacing1) ==
|
||||
nsLayoutUtils::GetTextRunFlagsForStyle(sc2, pc, fontStyle2,
|
||||
|
@ -2570,7 +2572,8 @@ void BuildTextRunsScanner::SetupBreakSinksForTextRun(gfxTextRun* aTextRun,
|
|||
const void* aTextPtr) {
|
||||
using mozilla::intl::LineBreaker;
|
||||
|
||||
auto wordBreak = mLineContainer->StyleText()->EffectiveWordBreak();
|
||||
auto wordBreak =
|
||||
mMappedFlows[0].mStartFrame->StyleText()->EffectiveWordBreak();
|
||||
switch (wordBreak) {
|
||||
case StyleWordBreak::BreakAll:
|
||||
mLineBreaker.SetWordBreak(LineBreaker::kWordBreak_BreakAll);
|
||||
|
@ -5855,7 +5858,7 @@ void nsTextFrame::PaintOneShadow(const PaintShadowParams& aParams,
|
|||
|
||||
// Gecko already inflates the bounding rect of text shadows,
|
||||
// so tell WR not to inflate again.
|
||||
wrShadow.should_inflate = false;
|
||||
wrShadow.should_inflate = true;
|
||||
|
||||
wrShadow.offset = {
|
||||
PresContext()->AppUnitsToFloatDevPixels(aShadowDetails->mXOffset),
|
||||
|
|
|
@ -8985,16 +8985,10 @@ bool nsDisplayText::CreateWebRenderCommands(
|
|||
auto* f = static_cast<nsTextFrame*>(mFrame);
|
||||
auto appUnitsPerDevPixel = f->PresContext()->AppUnitsPerDevPixel();
|
||||
|
||||
// FIXME: the webrender backend is having a lot of snapping issues, and
|
||||
// having it do inflation for us is causing problems. For now, we pass
|
||||
// down the wrong bounds. Try to turn this back on when things are in
|
||||
// better shape.
|
||||
//
|
||||
// nsRect bounds = f->WebRenderBounds() + ToReferenceFrame();
|
||||
nsRect bounds = f->WebRenderBounds() + ToReferenceFrame();
|
||||
// Bug 748228
|
||||
// bounds.Inflate(appUnitsPerDevPixel);
|
||||
bounds.Inflate(appUnitsPerDevPixel);
|
||||
|
||||
nsRect bounds = mBounds;
|
||||
if (bounds.IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -2102,7 +2102,7 @@ pref(layout.css.supports-selector.enabled,true) == 1499386.html 1499386-ref.html
|
|||
pref(layout.css.supports-selector.enabled,false) != 1499386.html 1499386-ref.html
|
||||
== 1509425-1.html 1509425-1-ref.html
|
||||
== 1511570.html 1511570-ref.html
|
||||
fuzzy-if(!webrender,1-5,66-547) fails-if(webrender) == 1529992-1.html 1529992-1-ref.html
|
||||
fuzzy-if(!webrender,1-5,66-547) == 1529992-1.html 1529992-1-ref.html
|
||||
fuzzy-if(!webrender,0-6,0-34) fails-if(webrender) == 1529992-2.html 1529992-2-ref.html
|
||||
== 1535040-1.html 1535040-1-ref.html
|
||||
== 1545360-1.xhtml 1545360-1-ref.xhtml
|
||||
|
|
|
@ -5,7 +5,7 @@ random-if(Android) == basic-negcoord.xul basic-negcoord-ref.xul
|
|||
!= blur.xul blur-notref.xul
|
||||
== color-inherit.xul color-inherit-ref.xul
|
||||
== multiple-noblur.xul multiple-noblur-ref.xul
|
||||
== blur-opacity.html blur-opacity-ref.html
|
||||
fuzzy-if(webrender&>kWidget,128-128,160-160) == blur-opacity.html blur-opacity-ref.html
|
||||
|
||||
== basic.html basic-ref.html
|
||||
== basic-negcoord.html basic-negcoord-ref.html
|
||||
|
|
|
@ -141,12 +141,12 @@ class IntegerRange {
|
|||
|
||||
template <typename T, bool = IsUnsigned<T>::value>
|
||||
struct GeqZero {
|
||||
static bool check(T t) { return t >= 0; }
|
||||
static bool isNonNegative(T t) { return t >= 0; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct GeqZero<T, true> {
|
||||
static bool check(T t) { return true; }
|
||||
static bool isNonNegative(T t) { return true; }
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
@ -154,7 +154,7 @@ struct GeqZero<T, true> {
|
|||
template <typename IntType>
|
||||
detail::IntegerRange<IntType> IntegerRange(IntType aEnd) {
|
||||
static_assert(IsIntegral<IntType>::value, "value must be integral");
|
||||
MOZ_ASSERT(detail::GeqZero<IntType>::check(aEnd),
|
||||
MOZ_ASSERT(detail::GeqZero<IntType>::isNonNegative(aEnd),
|
||||
"Should never have negative value here");
|
||||
return detail::IntegerRange<IntType>(aEnd);
|
||||
}
|
||||
|
|
|
@ -766,7 +766,7 @@ class MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS MOZ_NON_PARAM Variant {
|
|||
* Note that this does not hash the actual contents; you must take
|
||||
* care of that yourself, perhaps by using a match.
|
||||
*/
|
||||
mozilla::HashNumber addTagToHash(mozilla::HashNumber hashValue) {
|
||||
mozilla::HashNumber addTagToHash(mozilla::HashNumber hashValue) const {
|
||||
return mozilla::AddToHash(hashValue, tag);
|
||||
}
|
||||
};
|
||||
|
|
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 46 KiB |
|
@ -1,5 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<org.mozilla.gecko.preferences.NotificationSettingsLinkPreference
|
||||
android:key="android.not_a_preference.notifications.settings_link"
|
||||
android:title="@string/pref_notification_settings_link" />
|
||||
<SwitchPreference android:key="android.not_a_preference.notifications.whats_new"
|
||||
android:title="@string/pref_whats_new_notification"
|
||||
android:summary="@string/pref_whats_new_notification_summary"
|
||||
|
|
|
@ -209,19 +209,15 @@ public class GeckoApplication extends Application
|
|||
db.expireHistory(getContentResolver(), BrowserContract.ExpirePriority.NORMAL);
|
||||
}
|
||||
});
|
||||
|
||||
GeckoNetworkManager.getInstance().stop();
|
||||
}
|
||||
|
||||
public void onApplicationForeground() {
|
||||
if (mIsInitialResume) {
|
||||
GeckoBatteryManager.getInstance().start(this);
|
||||
GeckoNetworkManager.getInstance().start(this);
|
||||
mIsInitialResume = false;
|
||||
} else if (mPausedGecko) {
|
||||
GeckoThread.onResume();
|
||||
mPausedGecko = false;
|
||||
GeckoNetworkManager.getInstance().start(this);
|
||||
}
|
||||
|
||||
mInBackground = false;
|
||||
|
|
|
@ -23,6 +23,10 @@ public class DefaultBrowserPreference extends LinkPreference {
|
|||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open Default apps screen of Settings for API Levels>=24.
|
||||
* Support URL will open for lower API levels.
|
||||
*/
|
||||
@Override
|
||||
protected void onClick() {
|
||||
if (GeckoPreferences.PREFS_DEFAULT_BROWSER.equals(getKey()) && AppConstants.Versions.feature24Plus) {
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче