Merge mozilla-central to mozilla-inbound. CLOSED TREE

--HG--
extra : amend_source : d757a37614ac9d59e154d34ede3ca871a643cdb7
This commit is contained in:
Dorel Luca 2018-10-18 02:02:07 +03:00
commit 2b0bec5ab3
214 changed files with 10248 additions and 1372 deletions

View File

@ -16,6 +16,8 @@ ChromeUtils.defineModuleGetter(this, "WebNavigationFrames",
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
XPCOMUtils.defineLazyGlobalGetters(this, ["URL"]);
XPCOMUtils.defineLazyGetter(this, "gPipNSSBundle", function() {
return Services.strings.createBundle("chrome://pipnss/locale/pipnss.properties");
});
@ -330,6 +332,7 @@ class NetErrorChild extends ActorChild {
detailLink.append(input.data.codeString);
detailLink.title = input.data.codeString;
detailLink.id = "errorCode";
detailLink.dataset.telemetryId = "error_code_link";
let fragment = BrowserUtils.getLocalizedFragment(doc, linkPrefix, detailLink);
technicalInfo.appendChild(fragment);
var errorCode = doc.getElementById("errorCode");
@ -364,6 +367,12 @@ class NetErrorChild extends ActorChild {
// This is set to true later if the user's system clock is at fault for this error.
let clockSkew = false;
doc.body.setAttribute("code", msg.data.codeString);
// Need to do this here (which is not exactly at load but a few ticks later),
// because this is the first time we have access to the error code.
this.recordLoadEvent(doc);
switch (msg.data.code) {
case SSL_ERROR_BAD_CERT_DOMAIN:
case SEC_ERROR_OCSP_INVALID_SIGNING_CERT:
@ -556,11 +565,13 @@ class NetErrorChild extends ActorChild {
case "click":
if (aEvent.button == 0) {
if (this.isAboutCertError(doc)) {
this.recordClick(aEvent.originalTarget);
this.onCertError(aEvent.originalTarget, doc.defaultView);
} else {
this.onClick(aEvent);
}
}
break;
}
}
@ -722,6 +733,38 @@ class NetErrorChild extends ActorChild {
});
}
getCSSClass(doc) {
let searchParams = new URL(doc.documentURI).searchParams;
return searchParams.get("s");
}
recordLoadEvent(doc) {
let cssClass = this.getCSSClass(doc);
// Telemetry values for events are max. 80 bytes.
let errorCode = doc.body.getAttribute("code").substring(0, 40);
Services.telemetry.recordEvent("security.ui.certerror", "load", "aboutcerterror", errorCode, {
"has_sts": (cssClass == "badStsCert").toString(),
"is_frame": (doc.ownerGlobal.parent != doc.ownerGlobal).toString(),
});
}
recordClick(element) {
let telemetryId = element.dataset.telemetryId;
if (!telemetryId) {
return;
}
let doc = element.ownerDocument;
let cssClass = this.getCSSClass(doc);
// Telemetry values for events are max. 80 bytes.
let errorCode = doc.body.getAttribute("code").substring(0, 40);
let panel = doc.getElementById("badCertAdvancedPanel");
Services.telemetry.recordEvent("security.ui.certerror", "click", telemetryId, errorCode, {
"panel_open": (panel.style.display == "none").toString(),
"has_sts": (cssClass == "badStsCert").toString(),
"is_frame": (doc.ownerGlobal.parent != doc.ownerGlobal).toString(),
});
}
onClick(event) {
let {documentURI} = event.target.ownerDocument;

View File

@ -43,7 +43,6 @@ pref("extensions.getAddons.compatOverides.url", "https://services.addons.mozilla
pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/firefox/search?q=%TERMS%&platform=%OS%&appver=%VERSION%");
pref("extensions.webservice.discoverURL", "https://discovery.addons.mozilla.org/%LOCALE%/firefox/discovery/pane/%VERSION%/%OS%/%COMPATIBILITY_MODE%");
pref("extensions.getAddons.link.url", "https://addons.mozilla.org/%LOCALE%/firefox/");
pref("extensions.getAddons.themes.browseURL", "https://addons.mozilla.org/%LOCALE%/firefox/themes/?src=firefox");
pref("extensions.getAddons.langpacks.url", "https://services.addons.mozilla.org/api/v3/addons/language-tools/?app=firefox&type=language&appversion=%VERSION%");
pref("extensions.update.autoUpdateDefault", true);
@ -953,6 +952,8 @@ pref("browser.security.newcerterrorpage.enabled", true);
pref("browser.security.newcerterrorpage.enabled", false);
#endif
pref("security.certerrors.recordEventTelemetry", true);
// Whether to start the private browsing mode at application startup
pref("browser.privatebrowsing.autostart", false);

View File

@ -171,7 +171,7 @@
<div id="errorLongDesc" />
<div id="learnMoreContainer">
<p><a href="https://support.mozilla.org/kb/what-does-your-connection-is-not-secure-mean" id="learnMoreLink" target="new">&errorReporting.learnMore;</a></p>
<p><a href="https://support.mozilla.org/kb/what-does-your-connection-is-not-secure-mean" id="learnMoreLink" target="new" data-telemetry-id="learn_more_link">&errorReporting.learnMore;</a></p>
</div>
</div>
@ -183,10 +183,10 @@
</div>
<div id="certErrorAndCaptivePortalButtonContainer" class="button-container">
<button id="returnButton" class="primary" autocomplete="off">&returnToPreviousPage1.label;</button>
<button id="returnButton" class="primary" autocomplete="off" data-telemetry-id="return_button_top">&returnToPreviousPage1.label;</button>
<button id="openPortalLoginPageButton" class="primary" autocomplete="off">&openPortalLoginPage.label2;</button>
<button id="errorTryAgain" class="primary" autocomplete="off">&retry.label;</button>
<button id="advancedButton" autocomplete="off">&continue2.label;</button>
<button id="advancedButton" data-telemetry-id="advanced_button" autocomplete="off">&continue2.label;</button>
<button id="moreInformationButton" autocomplete="off">&moreInformation.label;</button>
</div>
</div>
@ -198,26 +198,27 @@
<div id="advancedPanelContainer">
<div id="badCertAdvancedPanel" class="advanced-panel">
<p id="badCertTechnicalInfo"/>
<a id="viewCertificate" href="javascript:void(0)">&viewCertificate.label;</a>
<div id="advancedPanelButtonContainer" class="button-container">
<button id="advancedPanelReturnButton" class="primary" autocomplete="off">&returnToPreviousPage1.label;</button>
<button id="advancedPanelReturnButton" class="primary" autocomplete="off" data-telemetry-id="return_button_adv">&returnToPreviousPage1.label;</button>
<button id="advancedPanelErrorTryAgain" class="primary" autocomplete="off">&retry.label;</button>
<div class="exceptionDialogButtonContainer">
<button id="exceptionDialogButton">&securityOverride.exceptionButton1Label;</button>
<button id="exceptionDialogButton" data-telemetry-id="exception_button">&securityOverride.exceptionButton1Label;</button>
</div>
</div>
</div>
<div id="certificateErrorReporting">
<p class="toggle-container-with-text">
<input type="checkbox" id="automaticallyReportInFuture" role="checkbox" />
<input type="checkbox" id="automaticallyReportInFuture" role="checkbox" data-telemetry-id="auto_report_cb"/>
<label for="automaticallyReportInFuture" id="automaticallyReportInFuture">&errorReporting.automatic2;</label>
</p>
</div>
<div id="certificateErrorDebugInformation">
<button id="copyToClipboard">&certerror.copyToClipboard.label;</button>
<button id="copyToClipboard" data-telemetry-id="clipboard_button_top">&certerror.copyToClipboard.label;</button>
<div id="certificateErrorText"/>
<button id="copyToClipboard">&certerror.copyToClipboard.label;</button>
<button id="copyToClipboard" data-telemetry-id="clipboard_button_bot">&certerror.copyToClipboard.label;</button>
</div>
</div>
</div>

View File

@ -133,7 +133,7 @@
<div id="errorLongDesc" />
<div id="learnMoreContainer">
<p><a href="https://support.mozilla.org/kb/what-does-your-connection-is-not-secure-mean" id="learnMoreLink" target="new">&errorReporting.learnMore;</a></p>
<p><a href="https://support.mozilla.org/kb/what-does-your-connection-is-not-secure-mean" id="learnMoreLink" target="new" data-telemetry-id="learn_more_link">&errorReporting.learnMore;</a></p>
</div>
</div>
@ -141,7 +141,7 @@
init for other error types .-->
<div id="certificateErrorReporting">
<p class="toggle-container-with-text">
<input type="checkbox" id="automaticallyReportInFuture" role="checkbox" />
<input type="checkbox" id="automaticallyReportInFuture" role="checkbox" data-telemetry-id="auto_report_cb"/>
<label for="automaticallyReportInFuture" id="automaticallyReportInFuture">&errorReporting.automatic2;</label>
</p>
</div>
@ -152,9 +152,9 @@
</div>
<div id="certErrorAndCaptivePortalButtonContainer" class="button-container">
<button id="returnButton" class="primary" autocomplete="off">&returnToPreviousPage.label;</button>
<button id="returnButton" class="primary" autocomplete="off" data-telemetry-id="return_button_top">&returnToPreviousPage.label;</button>
<button id="openPortalLoginPageButton" class="primary" autocomplete="off">&openPortalLoginPage.label2;</button>
<button id="advancedButton" autocomplete="off">&advanced.label;</button>
<button id="advancedButton" data-telemetry-id="advanced_button" autocomplete="off">&advanced.label;</button>
<button id="moreInformationButton" autocomplete="off">&moreInformation.label;</button>
</div>
</div>
@ -170,14 +170,14 @@
<button id="advancedPanelErrorTryAgain" class="primary" autocomplete="off">&retry.label;</button>
</div>
<div class="exceptionDialogButtonContainer">
<button id="exceptionDialogButton">&securityOverride.exceptionButtonLabel;</button>
<button id="exceptionDialogButton" data-telemetry-id="exception_button">&securityOverride.exceptionButtonLabel;</button>
</div>
</div>
<div id="certificateErrorDebugInformation">
<button id="copyToClipboard">&certerror.copyToClipboard.label;</button>
<button id="copyToClipboard" data-telemetry-id="clipboard_button_top">&certerror.copyToClipboard.label;</button>
<div id="certificateErrorText"/>
<button id="copyToClipboard">&certerror.copyToClipboard.label;</button>
<button id="copyToClipboard" data-telemetry-id="clipboard_button_bot">&certerror.copyToClipboard.label;</button>
</div>
</div>
</div>

View File

@ -3038,15 +3038,17 @@ var BrowserOnClick = {
},
onCertError(browser, elementId, isTopFrame, location, securityInfoAsString, frameId) {
let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
let securityInfo;
let cert;
switch (elementId) {
case "viewCertificate":
securityInfo = getSecurityInfo(securityInfoAsString);
cert = securityInfo.serverCert;
Services.ww.openWindow(window, "chrome://pippki/content/certViewer.xul",
"_blank", "centerscreen,chrome", cert);
break;
case "exceptionDialogButton":
if (isTopFrame) {
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_CLICK_ADD_EXCEPTION);
}
securityInfo = getSecurityInfo(securityInfoAsString);
let params = { exceptionAdded: false,
securityInfo };
@ -3064,7 +3066,7 @@ var BrowserOnClick = {
flags |= overrideService.ERROR_TIME;
}
let uri = Services.uriFixup.createFixupURI(location, 0);
let cert = securityInfo.serverCert;
cert = securityInfo.serverCert;
overrideService.rememberValidityOverride(
uri.asciiHost, uri.port,
cert,
@ -3095,9 +3097,6 @@ var BrowserOnClick = {
break;
case "returnButton":
if (isTopFrame) {
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_GET_ME_OUT_OF_HERE);
}
goBackFromErrorPage();
break;
@ -3107,10 +3106,6 @@ var BrowserOnClick = {
case "advancedButton":
case "moreInformationButton":
if (isTopFrame) {
secHistogram.add(Ci.nsISecurityUITelemetry.WARNING_BAD_CERT_TOP_UNDERSTAND_RISKS);
}
securityInfo = getSecurityInfo(securityInfoAsString);
let errorInfo = getDetailedCertErrorInfo(location,
securityInfo);

View File

@ -130,7 +130,7 @@ window._gBrowser = {
_browserBindingProperties: [
"canGoBack", "canGoForward", "goBack", "goForward", "permitUnload",
"reload", "reloadWithFlags", "stop", "loadURI",
"gotoIndex", "currentURI", "documentURI",
"gotoIndex", "currentURI", "documentURI", "remoteType",
"preferences", "imageDocument", "isRemoteBrowser", "messageManager",
"getTabBrowser", "finder", "fastFind", "sessionHistory", "contentTitle",
"characterSet", "fullZoom", "textZoom", "webProgress",
@ -1205,7 +1205,12 @@ window._gBrowser = {
};
},
setInitialTabTitle(aTab, aTitle, aOptions) {
setInitialTabTitle(aTab, aTitle, aOptions = {}) {
// Convert some non-content title (actually a url) to human readable title
if (!aOptions.isContentTitle && isBlankPageURL(aTitle)) {
aTitle = this.tabContainer.emptyTabTitle;
}
if (aTitle) {
if (!aTab.getAttribute("label")) {
aTab._labelIsInitialTitle = true;
@ -1990,6 +1995,22 @@ window._gBrowser = {
gBrowser._insertBrowser(aTab);
};
break;
case "remoteType":
getter = () => {
let url = SessionStore.getLazyTabValue(aTab, "url");
// Avoid recreating the same nsIURI object over and over again...
let uri;
if (browser._cachedCurrentURI) {
uri = browser._cachedCurrentURI;
} else {
uri = browser._cachedCurrentURI = Services.io.newURI(url);
}
return E10SUtils.getRemoteTypeForURI(url,
gMultiProcessBrowser,
undefined,
uri);
};
break;
case "userTypedValue":
case "userTypedClear":
getter = () => SessionStore.getLazyTabValue(aTab, name);
@ -3179,7 +3200,10 @@ window._gBrowser = {
var isPending = aOtherTab.hasAttribute("pending");
let otherTabListener = remoteBrowser._tabListeners.get(aOtherTab);
let stateFlags = otherTabListener.mStateFlags;
let stateFlags = 0;
if (otherTabListener) {
stateFlags = otherTabListener.mStateFlags;
}
// Expedite the removal of the icon if it was already scheduled.
if (aOtherTab._soundPlayingAttrRemovalTimer) {
@ -3294,7 +3318,7 @@ window._gBrowser = {
this.setTabTitle(aOurTab);
// If the tab was already selected (this happpens in the scenario
// If the tab was already selected (this happens in the scenario
// of replaceTabWithWindow), notify onLocationChange, etc.
if (aOurTab.selected)
this.updateCurrentBrowser(true);
@ -3575,14 +3599,13 @@ window._gBrowser = {
return this.replaceTabWithWindow(tabs[0], aOptions);
}
// The order of the tabs is reserved.
// To avoid mutliple tab-switch, the active tab is "moved" lastly, if applicable.
// The order of the tabs is preserved.
// To avoid multiple tab-switch, the active tab is "moved" last, if applicable.
// If applicable, the active tab remains active in the new window.
let activeTab = gBrowser.selectedTab;
let inactiveTabs = tabs.filter(t => t != activeTab);
let activeTabNewIndex = tabs.indexOf(activeTab);
// Play the closing animation for all selected tabs to give
// immediate feedback while waiting for the new window to appear.
if (this.animationsEnabled) {
@ -3594,7 +3617,8 @@ window._gBrowser = {
let win;
let firstInactiveTab = inactiveTabs[0];
firstInactiveTab.linkedBrowser.addEventListener("EndSwapDocShells", function() {
let adoptRemainingTabs = () => {
for (let i = 1; i < inactiveTabs.length; i++) {
win.gBrowser.adoptTab(inactiveTabs[i], i);
}
@ -3608,7 +3632,14 @@ window._gBrowser = {
let winTabLength = winVisibleTabs.length;
win.gBrowser.addRangeToMultiSelectedTabs(winVisibleTabs[0],
winVisibleTabs[winTabLength - 1]);
}, { once: true });
};
// Pending tabs don't get their docshell swapped, wait for their TabClose
if (firstInactiveTab.hasAttribute("pending")) {
firstInactiveTab.addEventListener("TabClose", adoptRemainingTabs, {once: true});
} else {
firstInactiveTab.linkedBrowser.addEventListener("EndSwapDocShells", adoptRemainingTabs, {once: true});
}
win = this.replaceTabWithWindow(firstInactiveTab, aOptions);
return win;

View File

@ -5,10 +5,10 @@ support-files =
searchSuggestionEngine.sjs
searchSuggestionEngine.xml
POSTSearchEngine.xml
dummy_page.html
[browser_aboutCertError.js]
support-files =
dummy_page.html
[browser_aboutCertError_telemetry.js]
[browser_aboutHome_search_POST.js]
[browser_aboutHome_search_composing.js]
[browser_aboutHome_search_searchbar.js]

View File

@ -7,47 +7,11 @@
const GOOD_PAGE = "https://example.com/";
const GOOD_PAGE_2 = "https://example.org/";
const DUMMY_PAGE = getRootDirectory(gTestPath).replace("chrome://mochitests/content", GOOD_PAGE) + "dummy_page.html";
const BAD_CERT = "https://expired.example.com/";
const UNKNOWN_ISSUER = "https://self-signed.example.com ";
const BAD_STS_CERT = "https://badchain.include-subdomains.pinning.example.com:443";
const {TabStateFlusher} = ChromeUtils.import("resource:///modules/sessionstore/TabStateFlusher.jsm", {});
function injectErrorPageFrame(tab, src) {
return ContentTask.spawn(tab.linkedBrowser, {frameSrc: src}, async function({frameSrc}) {
let loaded = ContentTaskUtils.waitForEvent(content.wrappedJSObject, "DOMFrameContentLoaded");
let iframe = content.document.createElement("iframe");
iframe.src = frameSrc;
content.document.body.appendChild(iframe);
await loaded;
// We will have race conditions when accessing the frame content after setting a src,
// so we can't wait for AboutNetErrorLoad. Let's wait for the certerror class to
// appear instead (which should happen at the same time as AboutNetErrorLoad).
await ContentTaskUtils.waitForCondition(() =>
iframe.contentDocument.body.classList.contains("certerror"));
});
}
async function openErrorPage(src, useFrame) {
let tab;
if (useFrame) {
info("Loading cert error page in an iframe");
tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, DUMMY_PAGE);
await injectErrorPageFrame(tab, src);
} else {
let certErrorLoaded;
tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, src);
let browser = gBrowser.selectedBrowser;
certErrorLoaded = BrowserTestUtils.waitForErrorPage(browser);
}, false);
info("Loading and waiting for the cert error");
await certErrorLoaded;
}
return tab;
}
add_task(async function checkReturnToAboutHome() {
info("Loading a bad cert page directly and making sure 'return to previous page' goes to about:home");
for (let useFrame of [false, true]) {
@ -518,6 +482,32 @@ add_task(async function checkCautionClass() {
}
});
add_task(async function checkViewCertificate() {
info("Loading a cert error and checking that the certificate can be shown.");
for (let useFrame of [false, true]) {
let tab = await openErrorPage(UNKNOWN_ISSUER, useFrame);
let browser = tab.linkedBrowser;
let dialogOpened = BrowserTestUtils.domWindowOpened();
await ContentTask.spawn(browser, {frame: useFrame}, async function({frame}) {
let doc = frame ? content.document.querySelector("iframe").contentDocument : content.document;
let viewCertificate = doc.getElementById("viewCertificate");
viewCertificate.click();
});
let win = await dialogOpened;
await BrowserTestUtils.waitForEvent(win, "load");
is(win.document.documentURI, "chrome://pippki/content/certViewer.xul",
"Opened the cert viewer dialog");
is(win.document.getElementById("commonname").value, "self-signed.example.com",
"Shows the correct certificate in the dialog");
win.close();
BrowserTestUtils.removeTab(gBrowser.selectedTab);
}
});
function getCertChain(securityInfoAsString) {
let certChain = "";
const serhelper = Cc["@mozilla.org/network/serialization-helper;1"]

View File

@ -0,0 +1,121 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
requestLongerTimeout(2);
const BAD_CERT = "https://expired.example.com/";
const BAD_STS_CERT = "https://badchain.include-subdomains.pinning.example.com:443";
add_task(async function checkTelemetryClickEvents() {
info("Loading a bad cert page and verifying telemetry click events arrive.");
let oldCanRecord = Services.telemetry.canRecordExtended;
Services.telemetry.canRecordExtended = true;
registerCleanupFunction(() => {
Services.telemetry.canRecordExtended = oldCanRecord;
});
// For obvious reasons event telemetry in the content processes updates with
// the main processs asynchronously, so we need to wait for the main process
// to catch up through the entire test.
// There's an arbitrary interval of 2 seconds in which the content
// processes sync their event data with the parent process, we wait
// this out to ensure that we clear everything that is left over from
// previous tests and don't receive random events in the middle of our tests.
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(c => setTimeout(c, 2000));
// Clear everything.
Services.telemetry.clearEvents();
await TestUtils.waitForCondition(() => {
let events = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).content;
return !events || !events.length;
});
// Now enable recording our telemetry. Even if this is disabled, content
// processes will send event telemetry to the parent, thus we needed to ensure
// we waited and cleared first. Sigh.
Services.telemetry.setEventRecordingEnabled("security.ui.certerror", true);
for (let useFrame of [false, true]) {
let recordedObjects = [
"advanced_button",
"learn_more_link",
"auto_report_cb",
"error_code_link",
"clipboard_button_top",
"clipboard_button_bot",
"return_button_top",
"return_button_adv",
];
if (!useFrame) {
recordedObjects.push("exception_button");
}
for (let object of recordedObjects) {
let tab = await openErrorPage(BAD_CERT, useFrame);
let browser = tab.linkedBrowser;
let loadEvents = await TestUtils.waitForCondition(() => {
let events = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).content;
if (events && events.length) {
events = events.filter(e => e[1] == "security.ui.certerror" && e[2] == "load");
if (events.length == 1 && events[0][5].is_frame == useFrame.toString()) {
return events;
}
}
return null;
}, "recorded telemetry for the load");
is(loadEvents.length, 1, `recorded telemetry for the load testing ${object}, useFrame: ${useFrame}`);
await ContentTask.spawn(browser, {frame: useFrame, objectId: object}, async function({frame, objectId}) {
let doc = frame ? content.document.querySelector("iframe").contentDocument : content.document;
await ContentTaskUtils.waitForCondition(() => doc.body.classList.contains("certerror"), "Wait for certerror to be loaded");
let domElement = doc.querySelector(`[data-telemetry-id='${objectId}']`);
domElement.click();
});
let clickEvents = await TestUtils.waitForCondition(() => {
let events = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_RELEASE_CHANNEL_OPTIN, true).content;
if (events && events.length) {
events = events.filter(e => e[1] == "security.ui.certerror" && e[2] == "click" && e[3] == object);
if (events.length == 1 && events[0][5].is_frame == useFrame.toString()) {
return events;
}
}
return null;
}, "Has captured telemetry events.");
is(clickEvents.length, 1, `recorded telemetry for the click on ${object}, useFrame: ${useFrame}`);
// We opened an extra tab for the SUMO page, need to close it.
if (object == "learn_more_link") {
BrowserTestUtils.removeTab(gBrowser.selectedTab);
}
if (object == "exception_button") {
let certOverrideService = Cc["@mozilla.org/security/certoverride;1"]
.getService(Ci.nsICertOverrideService);
certOverrideService.clearValidityOverride("expired.example.com", -1);
}
BrowserTestUtils.removeTab(gBrowser.selectedTab);
}
}
let enableCertErrorUITelemetry =
Services.prefs.getBoolPref("security.certerrors.recordEventTelemetry");
Services.telemetry.setEventRecordingEnabled("security.ui.certerror",
enableCertErrorUITelemetry);
});

View File

@ -1,5 +1,42 @@
/* eslint-env mozilla/frame-script */
function injectErrorPageFrame(tab, src) {
return ContentTask.spawn(tab.linkedBrowser, {frameSrc: src}, async function({frameSrc}) {
let loaded = ContentTaskUtils.waitForEvent(content.wrappedJSObject, "DOMFrameContentLoaded");
let iframe = content.document.createElement("iframe");
iframe.src = frameSrc;
content.document.body.appendChild(iframe);
await loaded;
// We will have race conditions when accessing the frame content after setting a src,
// so we can't wait for AboutNetErrorLoad. Let's wait for the certerror class to
// appear instead (which should happen at the same time as AboutNetErrorLoad).
await ContentTaskUtils.waitForCondition(() =>
iframe.contentDocument.body.classList.contains("certerror"));
});
}
async function openErrorPage(src, useFrame) {
let dummyPage = getRootDirectory(gTestPath).replace("chrome://mochitests/content", "https://example.com") + "dummy_page.html";
let tab;
if (useFrame) {
info("Loading cert error page in an iframe");
tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, dummyPage);
await injectErrorPageFrame(tab, src);
} else {
let certErrorLoaded;
tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, src);
let browser = gBrowser.selectedBrowser;
certErrorLoaded = BrowserTestUtils.waitForErrorPage(browser);
}, false);
info("Loading and waiting for the cert error");
await certErrorLoaded;
}
return tab;
}
function waitForCondition(condition, nextTest, errorMsg, retryTimes) {
retryTimes = typeof retryTimes !== "undefined" ? retryTimes : 30;
var tries = 0;

View File

@ -7,9 +7,11 @@
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gXulStore",
"@mozilla.org/xul/xulstore;1",
"nsIXULStore");
XPCOMUtils.defineLazyServiceGetters(this, {
gCertDB: ["@mozilla.org/security/x509certdb;1", "nsIX509CertDB"],
gXulStore: ["@mozilla.org/xul/xulstore;1", "nsIXULStore"],
});
XPCOMUtils.defineLazyModuleGetters(this, {
AddonManager: "resource://gre/modules/AddonManager.jsm",
@ -19,6 +21,8 @@ XPCOMUtils.defineLazyModuleGetters(this, {
WebsiteFilter: "resource:///modules/policies/WebsiteFilter.jsm",
});
XPCOMUtils.defineLazyGlobalGetters(this, ["File", "FileReader"]);
const PREF_LOGLEVEL = "browser.policies.loglevel";
const BROWSER_DOCUMENT_URL = AppConstants.BROWSER_CHROME_URL;
@ -134,6 +138,56 @@ var Policies = {
if ("ImportEnterpriseRoots" in param) {
setAndLockPref("security.enterprise_roots.enabled", param.ImportEnterpriseRoots);
}
if ("Install" in param) {
(async () => {
let dirs = [];
let platform = AppConstants.platform;
if (platform == "win") {
dirs = [
// Ugly, but there is no official way to get %USERNAME\AppData\Local\Mozilla.
Services.dirsvc.get("XREUSysExt", Ci.nsIFile).parent,
];
} else if (platform == "macosx" || platform == "linux") {
dirs = [
// These two keys are named wrong. They return the Mozilla directory.
Services.dirsvc.get("XREUserNativeManifests", Ci.nsIFile),
Services.dirsvc.get("XRESysNativeManifests", Ci.nsIFile),
];
}
for (let dir of dirs) {
dir.append(platform == "linux" ? "certificates" : "Certificates");
for (let certfilename of param.Install) {
let certfile = dir.clone();
certfile.append(certfilename);
let file;
try {
file = await File.createFromNsIFile(certfile);
} catch (e) {
log.info(`Unable to open certificate - ${certfile.path}`);
continue;
}
let reader = new FileReader();
reader.onloadend = function() {
if (reader.readyState != reader.DONE) {
log.error(`Unable to read certificate - ${certfile.path}`);
return;
}
let cert = reader.result;
try {
if (/-----BEGIN CERTIFICATE-----/.test(cert)) {
gCertDB.addCertFromBase64(pemToBase64(cert), "CTu,CTu,");
} else {
gCertDB.addCert(cert, "CTu,CTu,");
}
} catch (e) {
log.error(`Unable to add certificate - ${certfile.path}`);
}
};
reader.readAsBinaryString(file);
}
}
})();
}
},
},
@ -1062,3 +1116,9 @@ function blockAllChromeURLs() {
ChromeURLBlockPolicy.contractID,
ChromeURLBlockPolicy.contractID, false, true);
}
function pemToBase64(pem) {
return pem.replace(/-----BEGIN CERTIFICATE-----/, "")
.replace(/-----END CERTIFICATE-----/, "")
.replace(/[\r\n]/g, "");
}

View File

@ -235,6 +235,7 @@ function generateDocumentation() {
// existing descriptions
let string_mapping = {
"DisableSetDesktopBackground": "DisableSetAsDesktopBackground",
"Certificates": "CertificatesDescription",
};
for (let policyName in schema.properties) {

View File

@ -95,6 +95,12 @@
"properties": {
"ImportEnterpriseRoots": {
"type": "boolean"
},
"Install": {
"type": "array",
"items": {
"type": "string"
}
}
}
},

View File

@ -95,7 +95,6 @@ skip-if = (verify && (os == 'linux' || os == 'mac'))
[browser_ext_devtools_page.js]
[browser_ext_devtools_panel.js]
[browser_ext_devtools_panels_elements.js]
skip-if = true # Bug 1393760
[browser_ext_devtools_panels_elements_sidebar.js]
support-files =
../../../../../devtools/client/inspector/extensions/test/head_devtools_inspector_sidebar.js

View File

@ -11,9 +11,6 @@ add_task(async function test_devtools_panels_elements_onSelectionChanged() {
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, "http://mochi.test:8888/");
function devtools_page() {
let isReloading = false;
let collectedEvalResults = [];
browser.devtools.panels.elements.onSelectionChanged.addListener(async () => {
const [
evalResult, exceptionInfo,
@ -24,13 +21,7 @@ add_task(async function test_devtools_panels_elements_onSelectionChanged() {
JSON.stringify(exceptionInfo));
}
collectedEvalResults.push(evalResult);
// The eval results that are happening during the reload are going to
// be retrieved all at once using the "collected_devttols_eval_results:request".
if (!isReloading) {
browser.test.sendMessage("devtools_eval_result", evalResult);
}
browser.test.sendMessage("devtools_eval_result", evalResult);
});
browser.test.onMessage.addListener(msg => {
@ -38,18 +29,10 @@ add_task(async function test_devtools_panels_elements_onSelectionChanged() {
case "inspectedWindow_reload": {
// Force a reload to test that the expected onSelectionChanged events are sent
// while the page is navigating and once it has been fully reloaded.
isReloading = true;
collectedEvalResults = [];
browser.devtools.inspectedWindow.eval("window.location.reload();");
break;
}
case "collected_devtools_eval_results:request": {
browser.test.sendMessage("collected_devtools_eval_results:reply",
collectedEvalResults);
break;
}
default: {
browser.test.fail(`Received unexpected test.onMesssage: ${msg}`);
}
@ -90,8 +73,9 @@ add_task(async function test_devtools_panels_elements_onSelectionChanged() {
const inspector = toolbox.getPanel("inspector");
const evalResult = await extension.awaitMessage("devtools_eval_result");
info("Waiting for the first onSelectionChanged event to be fired once the inspector is open");
const evalResult = await extension.awaitMessage("devtools_eval_result");
is(evalResult, "BODY", "Got the expected onSelectionChanged once the inspector is selected");
// Reload the inspected tab and wait for the inspector markup view to have been
@ -100,17 +84,17 @@ add_task(async function test_devtools_panels_elements_onSelectionChanged() {
extension.sendMessage("inspectedWindow_reload");
await onceMarkupReloaded;
// Retrieve the first and last collected eval result (the first is related to the
// page navigating away, the last one is related to the updated inspector markup view
// fully reloaded and the selection updated).
extension.sendMessage("collected_devtools_eval_results:request");
const collectedEvalResults = await extension.awaitMessage("collected_devtools_eval_results:reply");
const evalResultNavigating = collectedEvalResults.shift();
const evalResultOnceMarkupReloaded = collectedEvalResults.pop();
info("Waiting for the two onSelectionChanged events fired before and after the navigation");
// Expect the eval result to be undefined on the first onSelectionChanged event
// (fired when the page is navigating away, and so the current selection is undefined).
const evalResultNavigating = await extension.awaitMessage("devtools_eval_result");
is(evalResultNavigating, undefined,
"Got the expected onSelectionChanged once the tab is navigating");
// Expect the eval result to be related to the body element on the second onSelectionChanged
// event (fired when the page have been navigated to the new page).
const evalResultOnceMarkupReloaded = await extension.awaitMessage("devtools_eval_result");
is(evalResultOnceMarkupReloaded, "BODY",
"Got the expected onSelectionChanged once the tab has been completely reloaded");

View File

@ -1552,6 +1552,13 @@ BrowserGlue.prototype = {
ContextualIdentityService.load();
});
Services.tm.idleDispatchToMainThread(() => {
let enableCertErrorUITelemetry =
Services.prefs.getBoolPref("security.certerrors.recordEventTelemetry", false);
Services.telemetry.setEventRecordingEnabled("security.ui.certerror",
enableCertErrorUITelemetry);
});
// Load the Login Manager data from disk off the main thread, some time
// after startup. If the data is required before this runs, for example
// because a restored page contains a password field, it will be loaded on

View File

@ -1,6 +1,7 @@
[DEFAULT]
head = head.js
prefs =
browser.pagethumbnails.capturing_disabled=true
dom.payments.request.enabled=true
skip-if = !e10s # Bug 1365964 - Payment Request isn't implemented for non-e10s
support-files =

View File

@ -528,9 +528,6 @@ var SaveToPocket = {
},
uninit() {
// For speed sake, we should only do a shutdown if we're being disabled.
// On an app shutdown, just let it fade away...
Services.prefs.removeObserver("extensions.pocket.enabled", prefObserver);
PocketOverlay.shutdown();
},
};

View File

@ -51,8 +51,8 @@
permissions-remove-all.label,
permissions-button-cancel.label,
permissions-button-ok.label,
permissions-exceptions-tracking-protection-window.title,
permissions-exceptions-tracking-protection-desc,
permissions-exceptions-content-blocking-window.title,
permissions-exceptions-content-blocking-desc,
"/>
</hbox>
</vbox>

View File

@ -23,6 +23,6 @@ add_task(async function() {
*/
add_task(async function() {
await openPreferencesViaOpenPreferencesAPI("paneGeneral", {leaveOpen: true});
await evaluateSearchResults("disabled Tracking Protection", "trackingGroup");
await evaluateSearchResults("disabled content blocking", "trackingGroup");
BrowserTestUtils.removeTab(gBrowser.selectedTab);
});

View File

@ -7,8 +7,8 @@ ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
const permissionExceptionsL10n = {
"trackingprotection": {
window: "permissions-exceptions-tracking-protection-window",
description: "permissions-exceptions-tracking-protection-desc",
window: "permissions-exceptions-content-blocking-window",
description: "permissions-exceptions-content-blocking-desc",
},
"cookie": {
window: "permissions-exceptions-cookie-window",

View File

@ -2767,7 +2767,7 @@ var SessionStoreInternal = {
if (activePageData.title &&
activePageData.title != activePageData.url) {
win.gBrowser.setInitialTabTitle(tab, activePageData.title, { isContentTitle: true });
} else if (activePageData.url != "about:blank") {
} else {
win.gBrowser.setInitialTabTitle(tab, activePageData.url);
}
}

View File

@ -252,6 +252,7 @@ skip-if = !e10s
[browser_async_window_flushing.js]
[browser_focus_after_restore.js]
[browser_forget_async_closings.js]
[browser_movePendingTabToNewWindow.js]
[browser_multiple_navigateAndRestore.js]
run-if = e10s
[browser_newtab_userTypedValue.js]

View File

@ -0,0 +1,87 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* This tests the behaviour of moving pending tabs to a new window. These
* pending tabs have yet to be restored and should be restored upon opening
* in the new window. This test covers moving a single pending tab at once
* as well as multiple tabs at the same time (using tab multiselection).
*/
add_task(async function test_movePendingTabToNewWindow() {
const TEST_URIS = [
"http://www.example.com/1",
"http://www.example.com/2",
"http://www.example.com/3",
"http://www.example.com/4",
];
await SpecialPowers.pushPrefEnv({
"set": [
["browser.sessionstore.restore_on_demand", true],
["toolkit.cosmeticAnimations.enabled", false],
],
});
let state = {
windows: [{
tabs: [
{ entries: [{ url: TEST_URIS[0], triggeringPrincipal_base64 }] },
{ entries: [{ url: TEST_URIS[1], triggeringPrincipal_base64 }] },
{ entries: [{ url: TEST_URIS[2], triggeringPrincipal_base64 }] },
{ entries: [{ url: TEST_URIS[3], triggeringPrincipal_base64 }] },
],
selected: 4,
}],
};
await promiseBrowserState(state);
is(gBrowser.visibleTabs.length, 4, "Three tabs are visible to start the test");
let tabToSelect = gBrowser.visibleTabs[1];
ok(tabToSelect.hasAttribute("pending"), "Tab should be pending");
gBrowser.addRangeToMultiSelectedTabs(gBrowser.selectedTab, tabToSelect);
ok(!gBrowser.visibleTabs[0].multiselected, "First tab not multiselected");
ok(gBrowser.visibleTabs[1].multiselected, "Second tab multiselected");
ok(gBrowser.visibleTabs[2].multiselected, "Third tab multiselected");
ok(gBrowser.visibleTabs[3].multiselected, "Fourth tab multiselected");
let promiseNewWindow = BrowserTestUtils.waitForNewWindow();
gBrowser.replaceTabsWithWindow(tabToSelect);
info("Waiting for new window");
let newWindow = await promiseNewWindow;
isnot(newWindow, gBrowser.ownerGlobal, "Tab moved to new window");
let newWindowTabs = newWindow.gBrowser.visibleTabs;
await TestUtils.waitForCondition(() => {
return newWindowTabs.length == 3 &&
newWindowTabs[0].linkedBrowser.currentURI.spec == TEST_URIS[1] &&
newWindowTabs[1].linkedBrowser.currentURI.spec == TEST_URIS[2] &&
newWindowTabs[2].linkedBrowser.currentURI.spec == TEST_URIS[3];
}, "Wait for all three tabs to move to new window and load");
is(newWindowTabs.length, 3, "Three tabs should be in new window");
is(newWindowTabs[0].linkedBrowser.currentURI.spec, TEST_URIS[1], "Second tab moved");
is(newWindowTabs[1].linkedBrowser.currentURI.spec, TEST_URIS[2], "Third tab moved");
is(newWindowTabs[2].linkedBrowser.currentURI.spec, TEST_URIS[3], "Fourth tab moved");
ok(newWindowTabs[0].hasAttribute("pending"), "First tab in new window should still be pending");
ok(newWindowTabs[1].hasAttribute("pending"), "Second tab in new window should still be pending");
newWindow.gBrowser.clearMultiSelectedTabs(true);
ok(newWindowTabs.every(t => !t.multiselected), "No multiselection should be present");
promiseNewWindow = BrowserTestUtils.waitForNewWindow();
newWindow.gBrowser.replaceTabsWithWindow(newWindowTabs[0]);
info("Waiting for second new window");
let secondNewWindow = await promiseNewWindow;
await TestUtils.waitForCondition(() => secondNewWindow.gBrowser.selectedBrowser.currentURI.spec == TEST_URIS[1],
"Wait until the URI is updated");
is(secondNewWindow.gBrowser.visibleTabs.length, 1, "Only one tab in second new window");
is(secondNewWindow.gBrowser.selectedBrowser.currentURI.spec, TEST_URIS[1], "First tab moved");
await BrowserTestUtils.closeWindow(secondNewWindow);
await BrowserTestUtils.closeWindow(newWindow);
});

View File

@ -20,6 +20,7 @@ add_task(async function() {
const ABOUT_ROBOTS_URI = "about:robots";
const ABOUT_ROBOTS_TITLE = "Gort! Klaatu barada nikto!";
const NO_TITLE_URL = "data:text/plain,foo";
const EMPTY_TAB_TITLE = gBrowser.tabContainer.emptyTabTitle;
function observeLabelChanges(tab, expectedLabels) {
let seenLabels = [tab.label];
@ -44,10 +45,11 @@ add_task(async function() {
{ entries: [{ url: ABOUT_ROBOTS_URI, triggeringPrincipal_base64 }] },
{ entries: [{ url: REMOTE_URL, triggeringPrincipal_base64 }] },
{ entries: [{ url: NO_TITLE_URL, triggeringPrincipal_base64 }] },
{ entries: [{ url: "about:blank", triggeringPrincipal_base64 }] },
],
}],
});
let [tab1, tab2, tab3, tab4] = gBrowser.tabs;
let [tab1, tab2, tab3, tab4, tab5] = gBrowser.tabs;
is(gBrowser.selectedTab, tab1, "first tab is selected");
await browserLoadedPromise;
@ -61,6 +63,7 @@ add_task(async function() {
ok(tab2.hasAttribute("pending"), "second tab is pending");
ok(tab3.hasAttribute("pending"), "third tab is pending");
ok(tab4.hasAttribute("pending"), "fourth tab is pending");
is(tab5.label, EMPTY_TAB_TITLE, "fifth tab dislpays empty tab title");
info("selecting the second tab");
// The fix for bug 1364127 caused about: pages' initial tab titles to show
@ -98,7 +101,7 @@ add_task(async function() {
gBrowser.selectedTab = tab3;
await TabStateFlusher.flushWindow(window);
await promiseBrowserState(SessionStore.getBrowserState());
[tab1, tab2, tab3, tab4] = gBrowser.tabs;
[tab1, tab2, tab3, tab4, tab5] = gBrowser.tabs;
is(tab3, gBrowser.selectedTab, "third tab is selected after restoring");
ok(document.title.startsWith(REMOTE_TITLE), "title bar displays content title");
ok(tab1.hasAttribute("pending"), "first tab is pending after restoring");
@ -108,6 +111,7 @@ add_task(async function() {
is(tab3.label, REMOTE_TITLE, "third tab displays content title in pending state");
ok(tab4.hasAttribute("pending"), "fourth tab is pending after restoring");
is(tab4.label, NO_TITLE_URL, "fourth tab displays URL");
is(tab5.label, EMPTY_TAB_TITLE, "fifth tab still displays empty tab title");
info("selecting the first tab");
finishObservingLabelChanges = observeLabelChanges(tab1, [REMOTE_TITLE]);

View File

@ -255,6 +255,11 @@ class UrlbarInput {
this.inputField.value = val;
this.formatValue();
// Dispatch ValueChange event for accessibility.
let event = this.document.createEvent("Events");
event.initEvent("ValueChange", true, true);
this.inputField.dispatchEvent(event);
return val;
}

View File

@ -23,7 +23,7 @@ policy-BlockAboutSupport = Block access to the about:support page.
policy-Bookmarks = Create bookmarks in the Bookmarks toolbar, Bookmarks menu, or a specified folder inside them.
policy-Certificates = Whether or not to use built-in certificates. This policy is Windows only at this time.
policy-CertificatesDescription = Add certificates or use built-in certificates.
policy-Cookies = Allow or deny websites to set cookies.

View File

@ -63,10 +63,10 @@ permissions-invalid-uri-label = Please enter a valid hostname
## Exceptions - Tracking Protection
permissions-exceptions-tracking-protection-window =
.title = Exceptions - Tracking Protection
permissions-exceptions-content-blocking-window =
.title = Exceptions - Content Blocking
.style = { permissions-window.style }
permissions-exceptions-tracking-protection-desc = You have disabled Tracking Protection on these websites.
permissions-exceptions-content-blocking-desc = You have disabled content blocking on these websites.
## Exceptions - Cookies

View File

@ -12,6 +12,7 @@
<!ENTITY advanced.label "Advanced">
<!ENTITY continue2.label "More…">
<!ENTITY moreInformation.label "More Information">
<!ENTITY viewCertificate.label "View Certificate">
<!-- Specific error messages -->

View File

@ -64,6 +64,7 @@ button:disabled {
display: flex;
justify-content: end;
padding: 5px;
margin-top: 2em;
}
body:not(.neterror) #certErrorAndCaptivePortalButtonContainer {
@ -158,8 +159,12 @@ span#hostname {
white-space: nowrap;
}
#viewCertificate {
margin: 0 3em;
}
#badCertTechnicalInfo {
margin: 3em;
margin: 3em 3em 1em;
overflow: auto;
white-space: pre-wrap;
}

View File

@ -289,7 +289,7 @@ var TestRunner = {
this.mochitestScope.info(
`\tSkipped configuration ` +
`[ ${combo.map((e) => e.name).join(", ")} ] ` +
`for "${reason}" in ${config.name}.${func}`);
`for "${reason}" in ${config.name}.${func}`);
}
},

View File

@ -26,7 +26,11 @@ const MIXED_PASSIVE_CONTENT_URL = `https://example.com/${RESOURCE_PATH}/mixed_pa
const TRACKING_PAGE = `http://tracking.example.org/${RESOURCE_PATH}/tracking.html`;
var ControlCenter = {
init(libDir) { },
init(libDir) {
// Disable the FTU tours.
Services.prefs.setIntPref("privacy.trackingprotection.introCount", 20);
Services.prefs.setIntPref("browser.contentblocking.introCount", 20);
},
configurations: {
about: {
@ -218,7 +222,6 @@ var ControlCenter = {
selectors: ["#identity-popup"],
async applyConfig() {
Services.prefs.setBoolPref("privacy.trackingprotection.enabled", true);
Services.prefs.setIntPref("privacy.trackingprotection.introCount", 20);
await UrlClassifierTestUtils.addTestTrackers();
await loadPage(TRACKING_PAGE);
@ -232,7 +235,6 @@ var ControlCenter = {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let gBrowser = browserWindow.gBrowser;
Services.prefs.setBoolPref("privacy.trackingprotection.enabled", true);
Services.prefs.setIntPref("privacy.trackingprotection.introCount", 20);
await UrlClassifierTestUtils.addTestTrackers();
await loadPage(TRACKING_PAGE);

View File

@ -14,10 +14,12 @@ mozilla.pth:third_party/python/compare-locales
mozilla.pth:third_party/python/configobj
mozilla.pth:third_party/python/cram
mozilla.pth:third_party/python/dlmanager
mozilla.pth:third_party/python/enum34
mozilla.pth:third_party/python/fluent
mozilla.pth:third_party/python/funcsigs
mozilla.pth:third_party/python/futures
mozilla.pth:third_party/python/more-itertools
mozilla.pth:third_party/python/mozilla-version
mozilla.pth:third_party/python/gyp/pylib
mozilla.pth:third_party/python/python-hglib
mozilla.pth:third_party/python/pluggy

View File

@ -34,6 +34,8 @@ const {
removeUSBRuntimesObserver,
} = require("./src/modules/usb-runtimes");
loader.lazyRequireGetter(this, "adbAddon", "devtools/shared/adb/adb-addon", true);
const App = createFactory(require("./src/components/App"));
const { PAGES, RUNTIMES } = require("./src/constants");
@ -46,6 +48,7 @@ const AboutDebugging = {
return;
}
this.onAdbAddonUpdated = this.onAdbAddonUpdated.bind(this);
this.onNetworkLocationsUpdated = this.onNetworkLocationsUpdated.bind(this);
this.onUSBRuntimesUpdated = this.onUSBRuntimesUpdated.bind(this);
@ -65,6 +68,9 @@ const AboutDebugging = {
addNetworkLocationsObserver(this.onNetworkLocationsUpdated);
addUSBRuntimesObserver(this.onUSBRuntimesUpdated);
await enableUSBRuntimes();
adbAddon.on("update", this.onAdbAddonUpdated);
this.onAdbAddonUpdated();
},
async createMessageContexts() {
@ -92,6 +98,10 @@ const AboutDebugging = {
return contexts;
},
onAdbAddonUpdated() {
this.actions.updateAdbAddonStatus(adbAddon.status);
},
onNetworkLocationsUpdated() {
this.actions.updateNetworkLocations(getNetworkLocations());
},
@ -113,6 +123,7 @@ const AboutDebugging = {
removeNetworkLocationsObserver(this.onNetworkLocationsUpdated);
removeUSBRuntimesObserver(this.onUSBRuntimesUpdated);
disableUSBRuntimes();
adbAddon.off("update", this.onAdbAddonUpdated);
setDebugTargetCollapsibilities(state.ui.debugTargetCollapsibilities);
unmountComponentAtNode(this.mount);
},

View File

@ -5,6 +5,7 @@
"use strict";
const {
ADB_ADDON_STATUS_UPDATED,
DEBUG_TARGET_COLLAPSIBILITY_UPDATED,
NETWORK_LOCATIONS_UPDATED,
PAGE_SELECTED,
@ -60,6 +61,10 @@ function removeNetworkLocation(location) {
};
}
function updateAdbAddonStatus(adbAddonStatus) {
return { type: ADB_ADDON_STATUS_UPDATED, adbAddonStatus };
}
function updateNetworkLocations(locations) {
return { type: NETWORK_LOCATIONS_UPDATED, locations };
}
@ -68,6 +73,7 @@ module.exports = {
addNetworkLocation,
removeNetworkLocation,
selectPage,
updateAdbAddonStatus,
updateDebugTargetCollapsibility,
updateNetworkLocations,
};

View File

@ -21,6 +21,7 @@ const Sidebar = createFactory(require("./sidebar/Sidebar"));
class App extends PureComponent {
static get propTypes() {
return {
adbAddonStatus: PropTypes.string,
// The "dispatch" helper is forwarded to the App component via connect.
// From that point, components are responsible for forwarding the dispatch
// property to all components who need to dispatch actions.
@ -51,6 +52,7 @@ class App extends PureComponent {
render() {
const {
adbAddonStatus,
dispatch,
messageContexts,
runtimes,
@ -61,7 +63,15 @@ class App extends PureComponent {
{ messages: messageContexts },
dom.div(
{ className: "app" },
Sidebar({ className: "app__sidebar", dispatch, runtimes, selectedPage }),
Sidebar(
{
adbAddonStatus,
className: "app__sidebar",
dispatch,
runtimes,
selectedPage
}
),
dom.main(
{ className: "app__content" },
this.getSelectedPageComponent()
@ -73,6 +83,7 @@ class App extends PureComponent {
const mapStateToProps = state => {
return {
adbAddonStatus: state.ui.adbAddonStatus,
runtimes: state.runtimes,
networkLocations: state.ui.networkLocations,
selectedPage: state.ui.selectedPage,

View File

@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
.sidebar__devices__no-devices-message {
.sidebar__devices__message {
color: var(--grey-40);
display: inline-block;
padding: 12px 0;

View File

@ -12,6 +12,7 @@ const FluentReact = require("devtools/client/shared/vendor/fluent-react");
const Localized = createFactory(FluentReact.Localized);
const { PAGES, RUNTIMES } = require("../../constants");
loader.lazyRequireGetter(this, "ADB_ADDON_STATES", "devtools/shared/adb/adb-addon", true);
const SidebarFixedItem = createFactory(require("./SidebarFixedItem"));
const SidebarRuntimeItem = createFactory(require("./SidebarRuntimeItem"));
@ -23,6 +24,7 @@ const USB_ICON = "chrome://devtools/skin/images/aboutdebugging-connect-icon.svg"
class Sidebar extends PureComponent {
static get propTypes() {
return {
adbAddonStatus: PropTypes.string,
className: PropTypes.string,
dispatch: PropTypes.func.isRequired,
runtimes: PropTypes.object.isRequired,
@ -30,15 +32,31 @@ class Sidebar extends PureComponent {
};
}
renderAdbAddonStatus() {
const isAddonInstalled = this.props.adbAddonStatus === ADB_ADDON_STATES.INSTALLED;
const localizationId = isAddonInstalled ? "about-debugging-sidebar-usb-enabled" :
"about-debugging-sidebar-usb-disabled";
return Localized(
{
id: localizationId
}, dom.aside(
{
className: "sidebar__devices__message js-sidebar-usb-status"
},
localizationId
)
);
}
renderDevices() {
const { runtimes } = this.props;
if (!runtimes.networkRuntimes.length && !runtimes.usbRuntimes.length) {
return Localized(
{
id: "about-debugging-sidebar-no-devices"
}, dom.span(
}, dom.aside(
{
className: "sidebar__devices__no-devices-message js-sidebar-no-devices"
className: "sidebar__devices__message js-sidebar-no-devices"
},
"No devices discovered"
)
@ -103,6 +121,7 @@ class Sidebar extends PureComponent {
})
),
dom.hr(),
this.renderAdbAddonStatus(),
this.renderDevices()
)
);

View File

@ -5,6 +5,7 @@
"use strict";
const actionTypes = {
ADB_ADDON_STATUS_UPDATED: "ADB_ADDON_STATUS_UPDATED",
CONNECT_RUNTIME_FAILURE: "CONNECT_RUNTIME_FAILURE",
CONNECT_RUNTIME_START: "CONNECT_RUNTIME_START",
CONNECT_RUNTIME_SUCCESS: "CONNECT_RUNTIME_SUCCESS",

View File

@ -5,6 +5,7 @@
"use strict";
const {
ADB_ADDON_STATUS_UPDATED,
DEBUG_TARGET_COLLAPSIBILITY_UPDATED,
NETWORK_LOCATIONS_UPDATED,
PAGE_SELECTED,
@ -12,6 +13,7 @@ const {
function UiState(locations = [], debugTargetCollapsibilities = {}) {
return {
adbAddonStatus: null,
debugTargetCollapsibilities,
networkLocations: locations,
selectedPage: null,
@ -20,6 +22,11 @@ function UiState(locations = [], debugTargetCollapsibilities = {}) {
function uiReducer(state = UiState(), action) {
switch (action.type) {
case ADB_ADDON_STATUS_UPDATED: {
const { adbAddonStatus } = action;
return Object.assign({}, state, { adbAddonStatus });
}
case DEBUG_TARGET_COLLAPSIBILITY_UPDATED: {
const { isCollapsed, key } = action;
const debugTargetCollapsibilities = new Map(state.debugTargetCollapsibilities);

View File

@ -5,6 +5,7 @@ support-files =
debug-target-pane_collapsibilities_head.js
head-addons-script.js
head.js
resources/test-adb-extension/*
resources/test-temporary-extension/*
!/devtools/client/shared/test/shared-head.js
!/devtools/client/shared/test/telemetry-test-helpers.js
@ -15,4 +16,6 @@ support-files =
[browser_aboutdebugging_debug-target-pane_empty.js]
[browser_aboutdebugging_navigate.js]
[browser_aboutdebugging_sidebar_network_runtimes.js]
[browser_aboutdebugging_sidebar_usb_status.js]
skip-if = (os == 'linux' && bits == 32) # ADB start() fails on linux 32, see Bug 1499638
[browser_aboutdebugging_thisfirefox.js]

View File

@ -0,0 +1,51 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const { adbAddon } = require("devtools/shared/adb/adb-addon");
const { ADB } = require("devtools/shared/adb/adb");
/**
* This test asserts that the sidebar shows a message describing the status of the USB
* devices scanning.
*/
add_task(async function() {
// Make sure the ADB addon is removed and ADB is stopped when the test ends.
registerCleanupFunction(async function() {
try {
await adbAddon.uninstall();
} catch (e) {
// Will throw if the addon is already uninstalled, ignore exceptions here.
}
await ADB.kill();
});
await pushPref("devtools.remote.adb.extensionURL",
CHROME_URL_ROOT + "resources/test-adb-extension/adb-extension-#OS#.xpi");
const { document, tab } = await openAboutDebugging();
const usbStatusElement = document.querySelector(".js-sidebar-usb-status");
ok(usbStatusElement, "Sidebar shows the USB status element");
ok(usbStatusElement.textContent.includes("USB devices disabled"),
"USB status element has the expected content");
info("Install the adb extension and wait for the message to udpate");
adbAddon.install();
await waitUntil(() => usbStatusElement.textContent.includes("USB devices enabled"));
// Right now we are resuming as soon as "USB devices enabled" is displayed, but ADB
// might still be starting up. If we move to uninstall directly, the ADB startup will
// fail and we will have an unhandled promise rejection.
// See Bug 1498469.
info("Wait until ADB has started.");
await waitUntil(() => ADB.ready);
info("Uninstall the adb extension and wait for the message to udpate");
adbAddon.uninstall();
await waitUntil(() => usbStatusElement.textContent.includes("USB devices disabled"));
await removeTab(tab);
});

View File

@ -13,6 +13,13 @@ about-debugging-sidebar-this-firefox =
about-debugging-sidebar-connect =
.name = Connect
# Text displayed in the about:debugging sidebar when USB devices discovery is enabled.
about-debugging-sidebar-usb-enabled = USB devices enabled
# Text displayed in the about:debugging sidebar when USB devices discovery is disabled
# (for instance because the mandatory ADB extension is not installed).
about-debugging-sidebar-usb-disabled = USB devices disabled
# Connection status (connected) for runtime items in the sidebar
aboutdebugging-sidebar-runtime-connection-status-connected = Connected
# Connection status (disconnected) for runtime items in the sidebar

View File

@ -140,8 +140,16 @@ Selection.prototype = {
nodeFront = parentNode;
}
if (this._nodeFront == null && nodeFront == null) {
// Avoid to notify multiple "unselected" events with a null/undefined nodeFront
// (e.g. once when the webpage start to navigate away from the current webpage,
// and then again while the new page is being loaded).
return;
}
this._isSlotted = isSlotted;
this._nodeFront = nodeFront;
this.emit("new-node-front", nodeFront, this.reason);
},

View File

@ -3,15 +3,21 @@ tags = devtools
subsuite = devtools
support-files =
doc_flexbox_simple.html
doc_flexbox_pseudos.html
head.js
!/devtools/client/inspector/test/head.js
!/devtools/client/inspector/test/shared-head.js
!/devtools/client/shared/test/shared-head.js
!/devtools/client/shared/test/telemetry-test-helpers.js
!/devtools/client/shared/test/test-actor.js
!/devtools/client/shared/test/test-actor-registry.js
[browser_flexbox_highlighter_color_picker_on_ESC.js]
[browser_flexbox_highlighter_color_picker_on_RETURN.js]
[browser_flexbox_item_outline_exists.js]
[browser_flexbox_item_outline_has_correct_layout.js]
[browser_flexbox_item_outline_rotates_for_column.js]
[browser_flexbox_pseudo_elements_are_listed.js]
[browser_flexbox_sizing_info_exists.js]
[browser_flexbox_sizing_info_for_pseudos.js]
[browser_flexbox_sizing_info_has_correct_sections.js]

View File

@ -0,0 +1,27 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that pseudo-elements that are flex items do appear in the list of items.
const TEST_URI = URL_ROOT + "doc_flexbox_pseudos.html";
add_task(async function() {
await addTab(TEST_URI);
const { inspector, flexboxInspector } = await openLayoutView();
const { document: doc } = flexboxInspector;
// Select the flex container in the inspector.
const onItemsListRendered = waitForDOM(doc,
"#layout-flexbox-container .flex-item-list");
await selectNode(".container", inspector);
const [flexItemList] = await onItemsListRendered;
const items = [...flexItemList.querySelectorAll("li")];
is(items.length, 2, "There are 2 items displayed in the list");
is(items[0].textContent, "::before", "The first item is ::before");
is(items[1].textContent, "::after", "The second item is ::after");
});

View File

@ -0,0 +1,38 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test that the flex item sizing UI also appears for pseudo elements.
const TEST_URI = URL_ROOT + "doc_flexbox_pseudos.html";
add_task(async function() {
await addTab(TEST_URI);
const { inspector, flexboxInspector } = await openLayoutView();
const { document: doc } = flexboxInspector;
info("Select the ::before pseudo-element in the inspector");
const containerNode = await getNodeFront(".container", inspector);
const { nodes } = await inspector.walker.children(containerNode);
const beforeNode = nodes[0];
const onFlexItemSizingRendered = waitForDOM(doc, "ul.flex-item-sizing");
const onFlexItemOutlineRendered = waitForDOM(doc, ".flex-outline-container");
await selectNode(beforeNode, inspector);
const [flexSizingContainer] = await onFlexItemSizingRendered;
const [flexOutlineContainer] = await onFlexItemOutlineRendered;
ok(flexSizingContainer, "The flex sizing exists in the DOM");
ok(flexOutlineContainer, "The flex outline exists in the DOM");
info("Check that the various sizing sections are displayed");
const allSections = [...flexSizingContainer.querySelectorAll(".section")];
ok(allSections.length, "Sizing sections are displayed");
info("Check that the various parts of the outline are displayed");
const [basis, final] = [...flexOutlineContainer.querySelectorAll(
".flex-outline-basis, .flex-outline-final")];
ok(basis && final, "The final and basis parts of the outline exist");
});

View File

@ -0,0 +1,27 @@
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.container {
width: 300px;
height: 150px;
margin: 10px;
display: flex;
}
.container::before,
.container::after {
color: #f06;
border: 1px solid #f06;
background: gold;
padding: 1em;
}
.container::before {
content: "::before pseudo-element item";
}
.container::after {
content: "::after pseudo-element item";
}
</style>
<div class="container"></div>

View File

@ -157,6 +157,7 @@ devtools.jar:
skin/images/command-chevron.svg (themes/images/command-chevron.svg)
skin/markup.css (themes/markup.css)
skin/images/editor-error.png (themes/images/editor-error.png)
skin/images/webconsole/globe.svg (themes/images/webconsole/globe.svg)
skin/images/breakpoint.svg (themes/images/breakpoint.svg)
skin/webconsole.css (themes/webconsole.css)
skin/images/webconsole/alert.svg (themes/images/webconsole/alert.svg)

View File

@ -5,7 +5,6 @@
"use strict";
const EventEmitter = require("devtools/shared/event-emitter");
const { MemoryFront } = require("devtools/shared/fronts/memory");
const { Cu } = require("chrome");
const HeapAnalysesClient = require("devtools/shared/heapsnapshot/HeapAnalysesClient");
@ -31,11 +30,7 @@ MemoryPanel.prototype = {
this.panelWin.gToolbox = this._toolbox;
this.panelWin.gTarget = this.target;
const rootForm = await this.target.root;
this.panelWin.gFront = new MemoryFront(this.target.client,
this.target.form,
rootForm);
this.panelWin.gFront = this.target.getFront("memory");
this.panelWin.gHeapAnalysesClient = new HeapAnalysesClient();
await this.panelWin.gFront.attach();

View File

@ -0,0 +1,4 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg viewBox="0 0 24 24" fill="context-fill #0b0b0b" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M4.062 11a8.009 8.009 0 0 1 5.14-6.497c-.05.137-.1.28-.15.43C8.577 6.356 8.113 8.379 8.017 11H4.062zm6.887-5.434c.234-.702.465-1.22.632-1.555a8.138 8.138 0 0 1 .838 0c.167.335.398.853.632 1.555.412 1.237.835 3.047.93 5.434H10.02c.094-2.387.517-4.197.929-5.434zM13.98 13h-3.96c.094 2.387.517 4.197.929 5.434.234.701.465 1.22.632 1.555a8.07 8.07 0 0 0 .838 0c.167-.335.398-.854.632-1.555.412-1.237.835-3.047.93-5.434zm.819 6.497c.05-.137.1-.28.15-.43.473-1.422.937-3.444 1.033-6.067h3.956a8.009 8.009 0 0 1-5.14 6.497zM15.982 11c-.096-2.622-.56-4.645-1.033-6.066-.05-.15-.1-.294-.15-.43A8.009 8.009 0 0 1 19.939 11h-3.957zm-11.92 2h3.956c.096 2.623.56 4.645 1.033 6.066a15.91 15.91 0 0 0 .15.43A8.009 8.009 0 0 1 4.062 13zM12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2z"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -218,6 +218,7 @@
--theme-pane-collapse-image: url(chrome://devtools/skin/images/pane-collapse.svg);
--theme-pane-expand-image: url(chrome://devtools/skin/images/pane-expand.svg);
--theme-console-alert-image: url(chrome://devtools/skin/images/webconsole/alert.svg);
--theme-console-navigation-image: url(chrome://devtools/skin/images/webconsole/globe.svg);
--theme-console-info-image: url(chrome://devtools/skin/images/webconsole/info.svg);
--theme-console-input-image: url(chrome://devtools/skin/images/webconsole/input.svg);
--theme-console-return-image: url(chrome://devtools/skin/images/webconsole/return.svg);

View File

@ -102,6 +102,11 @@ a {
background-color: var(--error-background-color);
}
.message.navigationMarker {
border-top: 1px solid var(--theme-emphasized-splitter-color);
color: var(--object-color);
}
.message.warn {
color: var(--warning-color);
background-color: var(--warning-background-color);
@ -206,6 +211,11 @@ a {
background-image: var(--theme-console-alert-image);
}
.message.navigationMarker > .icon {
color: var(--object-color);
background-image: var(--theme-console-navigation-image);
}
.message > span.icon[title="Jump"] {
background-image:var(--theme-console-jump-image);
@ -319,7 +329,7 @@ a {
flex: none;
}
.message.network:not(.navigation-marker) .url {
.message.network .url {
flex: 1 1 auto;
/* Make sure the URL is very small initially, let flex change width as needed. */
width: 100px;
@ -452,25 +462,6 @@ textarea.jsterm-input-node:focus {
/* Security styles */
.navigation-marker {
color: #aaa;
background: linear-gradient(#aaa, #aaa) no-repeat left 50%;
background-size: 100% 2px;
margin-block-start: 6px;
margin-block-end: 6px;
font-size: 0.9em;
}
.navigation-marker .url {
padding-inline-end: 9px;
text-decoration: none;
background: var(--theme-body-background);
}
.theme-light .navigation-marker .url {
background: #fff;
}
.stacktrace {
display: none;
overflow-y: auto;
@ -723,7 +714,7 @@ a.learn-more-link.webconsole-learn-more-link {
line-height: inherit;
}
.webconsole-output-wrapper .message.network:not(.navigation-marker) .url {
.webconsole-output-wrapper .message.network .url {
color: var(--theme-comment);
font-style: inherit;
}

View File

@ -134,6 +134,7 @@ const chromeRDPEnums = {
// Undocumented in Chrome RDP, but is used for messages that should not
// output anything (e.g. `console.time()` calls).
NULL_MESSAGE: "nullMessage",
NAVIGATION_MARKER: "navigationMarker"
},
MESSAGE_LEVEL: {
LOG: "log",

View File

@ -197,7 +197,7 @@ function transformNavigationMessagePacket(packet) {
const { message } = packet;
return new ConsoleMessage({
source: MESSAGE_SOURCE.CONSOLE_API,
type: MESSAGE_TYPE.LOG,
type: MESSAGE_TYPE.NAVIGATION_MARKER,
level: MESSAGE_LEVEL.LOG,
messageText: l10n.getFormatStr("webconsole.navigated", [message.url]),
timeStamp: message.timeStamp,

View File

@ -223,9 +223,7 @@ const NodeActor = protocol.ActorClassWithSpec(nodeSpec, {
get displayType() {
// Consider all non-element nodes as displayed.
if (InspectorActorUtils.isNodeDead(this) ||
this.rawNode.nodeType !== Node.ELEMENT_NODE ||
isAfterPseudoElement(this.rawNode) ||
isBeforePseudoElement(this.rawNode)) {
this.rawNode.nodeType !== Node.ELEMENT_NODE) {
return null;
}

View File

@ -171,7 +171,8 @@ const FlexItemActor = ActorClassWithSpec(flexItemSpec, {
for (const name in properties) {
let value = "";
// Look first on the element style.
if (this.element.style[name] && this.element.style[name] !== "auto") {
if (this.element.style &&
this.element.style[name] && this.element.style[name] !== "auto") {
value = this.element.style[name];
} else {
// And then on the rules that apply to the element.

View File

@ -4,10 +4,7 @@
const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
const Services = require("Services");
const { DebuggerClient } = require("devtools/shared/client/debugger-client");
const { DebuggerServer } = require("devtools/server/main");
const { MemoryFront } = require("devtools/shared/fronts/memory");
const { TargetFactory } = require("devtools/client/framework/target");
// Always log packets when running tests.
Services.prefs.setBoolPref("devtools.debugger.log", true);
@ -18,26 +15,21 @@ SimpleTest.registerCleanupFunction(function() {
Services.prefs.setBoolPref("privacy.reduceTimerPrecision", gReduceTimePrecision);
});
function startServerAndGetSelectedTabMemory() {
DebuggerServer.init();
DebuggerServer.registerAllActors();
const client = new DebuggerClient(DebuggerServer.connectPipe());
return client.connect()
.then(() => client.listTabs())
.then(response => {
const form = response.tabs[response.selected];
const memory = MemoryFront(client, form, response);
return { memory, client };
});
async function getTargetForSelectedTab() {
const browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
const target = await TargetFactory.forTab(browserWindow.gBrowser.selectedTab);
return target;
}
function destroyServerAndFinish(client) {
client.close().then(() => {
DebuggerServer.destroy();
SimpleTest.finish();
});
async function startServerAndGetSelectedTabMemory() {
const target = await getTargetForSelectedTab();
const memory = target.getFront("memory");
return {memory, target};
}
async function destroyServerAndFinish(target) {
await target.destroy();
SimpleTest.finish();
}
function waitForTime(ms) {

View File

@ -19,7 +19,7 @@ window.onload = function() {
SimpleTest.waitForExplicitFinish();
(async function() {
const { memory, client } = await startServerAndGetSelectedTabMemory();
const { memory, target } = await startServerAndGetSelectedTabMemory();
const measurement = await memory.measure();
ok(measurement.total > 0, "total memory is valid");
ok(measurement.domSize > 0, "domSize is valid");
@ -30,7 +30,7 @@ window.onload = function() {
ok(measurement.otherSize > 0, "otherSize is valid");
ok(measurement.jsMilliseconds, "jsMilliseconds is valid");
ok(measurement.nonJSMilliseconds, "nonJSMilliseconds is valid");
destroyServerAndFinish(client);
await destroyServerAndFinish(target);
})();
};
</script>

View File

@ -19,7 +19,7 @@ window.onload = function() {
SimpleTest.waitForExplicitFinish();
(async function() {
const { memory, client } = await startServerAndGetSelectedTabMemory();
const { memory, target } = await startServerAndGetSelectedTabMemory();
await memory.attach();
await memory.startRecordingAllocations();
@ -95,7 +95,7 @@ window.onload = function() {
"Should have found all the expected lines");
await memory.detach();
destroyServerAndFinish(client);
destroyServerAndFinish(target);
})();
};
</script>

View File

@ -19,7 +19,7 @@ window.onload = function() {
SimpleTest.waitForExplicitFinish();
(async function() {
const { memory, client } = await startServerAndGetSelectedTabMemory();
const { memory, target } = await startServerAndGetSelectedTabMemory();
await memory.attach();
const allocs = [];
@ -71,7 +71,7 @@ window.onload = function() {
memory.off("allocations", onAlloc);
await memory.detach();
destroyServerAndFinish(client);
destroyServerAndFinish(target);
})();
};
</script>

View File

@ -19,7 +19,7 @@ window.onload = function() {
SimpleTest.waitForExplicitFinish();
(async function() {
const { memory, client } = await startServerAndGetSelectedTabMemory();
const { memory, target } = await startServerAndGetSelectedTabMemory();
await memory.attach();
await memory.startRecordingAllocations();
@ -71,7 +71,7 @@ window.onload = function() {
}
await memory.detach();
destroyServerAndFinish(client);
destroyServerAndFinish(target);
})();
};
</script>

View File

@ -19,7 +19,7 @@ window.onload = function() {
SimpleTest.waitForExplicitFinish();
(async function() {
const { memory, client } = await startServerAndGetSelectedTabMemory();
const { memory, target } = await startServerAndGetSelectedTabMemory();
await memory.attach();
const allocs = [];
@ -53,7 +53,7 @@ window.onload = function() {
// (js/src/jit-test/tests/debug/Memory-allocationsSamplingProbability-*.js).
await memory.detach();
destroyServerAndFinish(client);
destroyServerAndFinish(target);
})();
};
</script>

View File

@ -19,7 +19,7 @@ window.onload = function() {
SimpleTest.waitForExplicitFinish();
(async function() {
const { memory, client } = await startServerAndGetSelectedTabMemory();
const { memory, target } = await startServerAndGetSelectedTabMemory();
await memory.attach();
const allocs = [];
@ -84,7 +84,7 @@ window.onload = function() {
}
await memory.detach();
destroyServerAndFinish(client);
destroyServerAndFinish(target);
})();
};
</script>

View File

@ -19,7 +19,7 @@ window.onload = function() {
SimpleTest.waitForExplicitFinish();
(async function() {
const { memory, client } = await startServerAndGetSelectedTabMemory();
const { memory, target } = await startServerAndGetSelectedTabMemory();
await memory.attach();
const allocs = [];
@ -42,7 +42,7 @@ window.onload = function() {
"There should only be one entry in the allocations log.");
await memory.detach();
destroyServerAndFinish(client);
destroyServerAndFinish(target);
})();
};
</script>

View File

@ -19,7 +19,7 @@ window.onload = function() {
SimpleTest.waitForExplicitFinish();
(async function() {
const { memory, client } = await startServerAndGetSelectedTabMemory();
const { memory, target } = await startServerAndGetSelectedTabMemory();
await memory.attach();
const allocs = [];
@ -45,7 +45,7 @@ window.onload = function() {
"every bytesize is a positive number");
await memory.detach();
destroyServerAndFinish(client);
destroyServerAndFinish(target);
})();
};

View File

@ -19,12 +19,12 @@ window.onload = function() {
SimpleTest.waitForExplicitFinish();
(async function() {
const { memory, client } = await startServerAndGetSelectedTabMemory();
const { memory, target } = await startServerAndGetSelectedTabMemory();
await memory.attach();
ok(true, "Shouldn't have gotten an error attaching.");
await memory.detach();
ok(true, "Shouldn't have gotten an error detaching.");
destroyServerAndFinish(client);
destroyServerAndFinish(target);
})();
};
</script>

View File

@ -19,7 +19,7 @@ window.onload = function() {
SimpleTest.waitForExplicitFinish();
(async function() {
const { memory, client } = await startServerAndGetSelectedTabMemory();
const { memory, target } = await startServerAndGetSelectedTabMemory();
let e = null;
try {
@ -40,7 +40,7 @@ window.onload = function() {
ok(e, "Should have hit the wrongState error");
await memory.detach();
destroyServerAndFinish(client);
destroyServerAndFinish(target);
})();
};
</script>

View File

@ -19,14 +19,14 @@ window.onload = function() {
SimpleTest.waitForExplicitFinish();
(async function() {
const { memory, client } = await startServerAndGetSelectedTabMemory();
const { memory, target } = await startServerAndGetSelectedTabMemory();
await memory.attach();
const census = await memory.takeCensus();
is(typeof census, "object");
await memory.detach();
destroyServerAndFinish(client);
destroyServerAndFinish(target);
})();
};
</script>

View File

@ -19,7 +19,7 @@ window.onload = function() {
SimpleTest.waitForExplicitFinish();
(async function() {
const { memory, client } = await startServerAndGetSelectedTabMemory();
const { memory, target } = await startServerAndGetSelectedTabMemory();
let beforeGC, afterGC;
@ -41,7 +41,7 @@ window.onload = function() {
ok(true, "The amount of memory after GC should eventually decrease");
destroyServerAndFinish(client);
destroyServerAndFinish(target);
})();
};
</script>

View File

@ -21,7 +21,7 @@ window.onload = function() {
const EventEmitter = require("devtools/shared/event-emitter");
(async function() {
const { memory, client } = await startServerAndGetSelectedTabMemory();
const { memory, target } = await startServerAndGetSelectedTabMemory();
await memory.attach();
const gotGcEvent = new Promise(resolve => {
@ -35,7 +35,7 @@ window.onload = function() {
await gotGcEvent;
await memory.detach();
destroyServerAndFinish(client);
destroyServerAndFinish(target);
})();
};
</script>

View File

@ -8,8 +8,8 @@ const {AddonManager} = require("resource://gre/modules/AddonManager.jsm");
const Services = require("Services");
const EventEmitter = require("devtools/shared/event-emitter");
const ADB_LINK = Services.prefs.getCharPref("devtools.remote.adb.extensionURL");
const ADB_ADDON_ID = Services.prefs.getCharPref("devtools.remote.adb.extensionID");
const PREF_ADB_EXTENSION_URL = "devtools.remote.adb.extensionURL";
const PREF_ADB_EXTENSION_ID = "devtools.remote.adb.extensionID";
// Extension ID for adb helper extension that might be installed on Firefox 63 or older.
const OLD_ADB_ADDON_ID = "adbhelper@mozilla.org";
@ -65,8 +65,13 @@ class ADBAddon extends EventEmitter {
return this._status;
}
async _getAddon() {
const addonId = Services.prefs.getCharPref(PREF_ADB_EXTENSION_ID);
return AddonManager.getAddonByID(addonId);
}
async updateInstallStatus() {
const addon = await AddonManager.getAddonByID(ADB_ADDON_ID);
const addon = await this._getAddon();
if (addon && !addon.userDisabled) {
this.status = ADB_ADDON_STATES.INSTALLED;
} else {
@ -92,7 +97,8 @@ class ADBAddon extends EventEmitter {
}
}
return ADB_LINK.replace(/#OS#/g, OS);
const xpiLink = Services.prefs.getCharPref(PREF_ADB_EXTENSION_URL);
return xpiLink.replace(/#OS#/g, OS);
}
/**
@ -103,7 +109,7 @@ class ADBAddon extends EventEmitter {
* String passed to the AddonManager for telemetry.
*/
async install(source) {
const addon = await AddonManager.getAddonByID(ADB_ADDON_ID);
const addon = await this._getAddon();
if (addon && !addon.userDisabled) {
this.status = ADB_ADDON_STATES.INSTALLED;
return;
@ -124,7 +130,7 @@ class ADBAddon extends EventEmitter {
}
async uninstall() {
const addon = await AddonManager.getAddonByID(ADB_ADDON_ID);
const addon = await this._getAddon();
addon.uninstall();
}

View File

@ -12,13 +12,11 @@ loader.lazyRequireGetter(this, "HeapSnapshotFileUtils",
"devtools/shared/heapsnapshot/HeapSnapshotFileUtils");
const MemoryFront = protocol.FrontClassWithSpec(memorySpec, {
initialize: function(client, form, rootForm = null) {
initialize: function(client, form) {
protocol.Front.prototype.initialize.call(this, client, form);
this._client = client;
this.actorID = form.memoryActor;
this.heapSnapshotFileActorID = rootForm
? rootForm.heapSnapshotFileActor
: null;
this.heapSnapshotFileActorID = null;
this.manage(this);
},
@ -64,7 +62,8 @@ const MemoryFront = protocol.FrontClassWithSpec(memorySpec, {
*/
transferHeapSnapshot: protocol.custom(async function(snapshotId) {
if (!this.heapSnapshotFileActorID) {
throw new Error("MemoryFront initialized without a rootForm");
const form = await this._client.mainRoot.rootForm;
this.heapSnapshotFileActorID = form.heapSnapshotFileActor;
}
try {

View File

@ -32,6 +32,8 @@ const OPEN_CLOSE_BODY = {
"(": ")",
};
const NO_AUTOCOMPLETE_PREFIXES = ["var", "const", "let", "function", "class"];
function hasArrayIndex(str) {
return /\[\d+\]$/.test(str);
}
@ -66,6 +68,24 @@ function analyzeInputString(str) {
// Use an array in order to handle character with a length > 2 (e.g. 😎).
const characters = Array.from(str);
const buildReturnObject = () => {
let isElementAccess = false;
if (bodyStack.length === 1 && bodyStack[0].token === "[") {
start = bodyStack[0].start;
isElementAccess = true;
if ([STATE_DQUOTE, STATE_QUOTE, STATE_TEMPLATE_LITERAL].includes(state)) {
state = STATE_NORMAL;
}
}
return {
state,
lastStatement: characters.slice(start).join(""),
isElementAccess,
};
};
for (let i = 0; i < characters.length; i++) {
c = characters[i];
@ -78,9 +98,11 @@ function analyzeInputString(str) {
state = STATE_QUOTE;
} else if (c == "`") {
state = STATE_TEMPLATE_LITERAL;
} else if (c == ";") {
} else if (";,:=<>+-*/%|&^~?!".split("").includes(c)) {
// If the character is an operator, we need to update the start position.
start = i + 1;
} else if (c == " ") {
const currentLastStatement = characters.slice(start, i).join("");
const before = characters.slice(0, i);
const after = characters.slice(i + 1);
const trimmedBefore = Array.from(before.join("").trimRight());
@ -90,24 +112,23 @@ function analyzeInputString(str) {
const nextNonSpaceCharIndex = after.indexOf(nextNonSpaceChar);
const previousNonSpaceChar = trimmedBefore[trimmedBefore.length - 1];
// If the previous meaningful char was a dot and there is no meaningful char
// after, we can break out of the loop.
if (previousNonSpaceChar === "." && !nextNonSpaceChar) {
break;
// There's only spaces after that, so we can return.
if (!nextNonSpaceChar) {
return buildReturnObject();
}
if (nextNonSpaceChar) {
// If the previous char wasn't a dot, and the next one isn't a dot either,
// update the start pos.
if (previousNonSpaceChar !== "." && nextNonSpaceChar !== ".") {
start = i + nextNonSpaceCharIndex;
}
// Let's jump to handle the next non-space char.
i = i + nextNonSpaceCharIndex;
} else {
// There's only spaces after that, so we can break out of the loop.
break;
// If the previous char in't a dot, and the next one isn't a dot either,
// and the current computed statement is not a variable/function/class
// declaration, update the start position.
if (
previousNonSpaceChar !== "." && nextNonSpaceChar !== "."
&& !NO_AUTOCOMPLETE_PREFIXES.includes(currentLastStatement)
) {
start = i + nextNonSpaceCharIndex;
}
// Let's jump to handle the next non-space char.
i = i + nextNonSpaceCharIndex;
} else if (OPEN_BODY.includes(c)) {
bodyStack.push({
token: c,
@ -166,20 +187,7 @@ function analyzeInputString(str) {
}
}
let isElementAccess = false;
if (bodyStack.length === 1 && bodyStack[0].token === "[") {
start = bodyStack[0].start;
isElementAccess = true;
if ([STATE_DQUOTE, STATE_QUOTE, STATE_TEMPLATE_LITERAL].includes(state)) {
state = STATE_NORMAL;
}
}
return {
state,
lastStatement: characters.slice(start).join(""),
isElementAccess,
};
return buildReturnObject();
}
/**
@ -237,16 +245,22 @@ function JSPropertyProvider(dbgObject, anEnvironment, inputValue, cursor) {
if (state != STATE_NORMAL) {
return null;
}
// Don't complete on just an empty string.
if (lastStatement.trim() == "") {
return null;
}
if (NO_AUTOCOMPLETE_PREFIXES.some(prefix => lastStatement.startsWith(prefix + " "))) {
return null;
}
const completionPart = lastStatement;
const lastDotIndex = completionPart.lastIndexOf(".");
const lastOpeningBracketIndex = isElementAccess ? completionPart.lastIndexOf("[") : -1;
const lastCompletionCharIndex = Math.max(lastDotIndex, lastOpeningBracketIndex);
const startQuoteRegex = /^('|"|`)/;
// Don't complete on just an empty string.
if (completionPart.trim() == "") {
return null;
}
// Catch literals like [1,2,3] or "foo" and return the matches from
// their prototypes.
// Don't run this is a worker, migrating to acorn should allow this

View File

@ -85,6 +85,8 @@
'da\`ta\`test': "",
"da'ta'test": "",
}));
window.varify = true;
`;
await state.client.evaluateJSAsync(script);
@ -101,6 +103,8 @@
doAutocompleteAfterOr,
doInsensitiveAutocomplete,
doElementAccessAutocomplete,
doAutocompleteAfterOperator,
dontAutocompleteAfterDeclaration,
];
if (!isWorker) {
@ -448,6 +452,74 @@
matches = (await client.autocomplete(`window[;c`)).matches;
ok(!matches.includes("cd") && !matches.includes("clear"), "commands are not returned");
}
async function doAutocompleteAfterOperator(client) {
const inputs = [
"true;foob",
"true,foob",
"({key:foob",
"a=foob",
"if(a<foob",
"if(a>foob",
"1+foob",
"1-foob",
"++foob",
"--foob",
"1*foob",
"2**foob",
"1/foob",
"1%foob",
"1|foob",
"1&foob",
"1^foob",
"~foob",
"1<<foob",
"1>>foob",
"1>>>foob",
"false||foob",
"false&&foob",
"x=true?foob",
"x=false?1:foob",
"!foob",
];
for (const input of inputs) {
info(`test autocomplete for "${input}"`);
let matches = (await client.autocomplete(input)).matches;
ok(matches.includes("foobarObject"), `Expected autocomplete result for ${input}"`);
}
}
async function dontAutocompleteAfterDeclaration(client) {
info("test autocomplete for 'var win'");
let matches = (await client.autocomplete("var win")).matches;
is(matches.length, 0, "no autocompletion on a var declaration");
info("test autocomplete for 'const win'");
matches = (await client.autocomplete("const win")).matches;
is(matches.length, 0, "no autocompletion on a const declaration");
info("test autocomplete for 'let win'");
matches = (await client.autocomplete("let win")).matches;
is(matches.length, 0, "no autocompletion on a let declaration");
info("test autocomplete for 'function win'");
matches = (await client.autocomplete("function win")).matches;
is(matches.length, 0, "no autocompletion on a function declaration");
info("test autocomplete for 'class win'");
matches = (await client.autocomplete("class win")).matches;
is(matches.length, 0, "no autocompletion on a class declaration");
info("test autocomplete for 'const win = win'");
matches = (await client.autocomplete("const win = win")).matches;
ok(matches.includes("window"), "autocompletion still happens after the `=` sign");
info("test autocomplete for 'in var'");
matches = (await client.autocomplete("in var")).matches;
ok(matches.includes("varify"),
"autocompletion still happens with a property name starting with 'var'");
}
</script>
</body>
</html>

View File

@ -4545,15 +4545,6 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
cssClass.AssignLiteral("badStsCert");
}
uint32_t bucketId;
if (isStsHost) {
// measuring STS separately allows us to measure click through
// rates easily
bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP_STS;
} else {
bucketId = nsISecurityUITelemetry::WARNING_BAD_CERT_TOP;
}
// See if an alternate cert error page is registered
nsAutoCString alternateErrorPage;
nsresult rv =
@ -4562,10 +4553,6 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
if (NS_SUCCEEDED(rv)) {
errorPage.Assign(alternateErrorPage);
}
if (!IsFrame() && errorPage.EqualsIgnoreCase("certerror")) {
Telemetry::Accumulate(mozilla::Telemetry::SECURITY_UI, bucketId);
}
} else {
error = "nssFailure2";
}

View File

@ -622,7 +622,7 @@ Element::WrapObject(JSContext *aCx, JS::Handle<JSObject*> aGivenProto)
if (bindingURL) {
nsCOMPtr<nsIURI> uri = bindingURL->GetURI();
nsCOMPtr<nsIPrincipal> principal = bindingURL->mExtraData->Principal();
nsCOMPtr<nsIPrincipal> principal = bindingURL->ExtraData()->Principal();
// We have a binding that must be installed.
bool dummy;

View File

@ -10794,33 +10794,10 @@ nsContentUtils::GetEventTargetByLoadInfo(nsILoadInfo* aLoadInfo, TaskCategory aC
return target.forget();
}
namespace {
template<class T>
bool IsLocalRefURL(const T& aString) {
// Find the first non-"C0 controls + space" character.
const typename T::char_type* current = aString.BeginReading();
for (; current != aString.EndReading(); current++) {
if (*current > 0x20) {
// if the first non-"C0 controls + space" character is '#', this is a
// local-ref URL.
return *current == '#';
}
}
return false;
}
}
/* static */ bool
nsContentUtils::IsLocalRefURL(const nsString& aString)
{
return ::IsLocalRefURL(aString);
}
/* static */ bool
nsContentUtils::IsLocalRefURL(const nsACString& aString)
{
return ::IsLocalRefURL(aString);
return !aString.IsEmpty() && aString[0] == '#';
}
static const uint64_t kIdProcessBits = 32;

View File

@ -3231,13 +3231,6 @@ public:
static bool
IsLocalRefURL(const nsString& aString);
/**
* Detect whether a string is a local-url.
* https://drafts.csswg.org/css-values/#local-urls
*/
static bool
IsLocalRefURL(const nsACString& aString);
static bool
IsCustomElementsEnabled() { return sIsCustomElementsEnabled; }

View File

@ -13786,8 +13786,13 @@ nsIDocument::RequestStorageAccess(mozilla::ErrorResult& aRv)
// Note: If this has returned true, the top-level document is guaranteed
// to not be on the Content Blocking allow list.
DebugOnly<bool> isOnAllowList = false;
// If we have a parent document, it has to be non-private since we verified
// earlier that our own document is non-private and a private document can
// never have a non-private document as its child.
MOZ_ASSERT_IF(parent, !nsContentUtils::IsInPrivateBrowsing(parent));
MOZ_ASSERT_IF(NS_SUCCEEDED(AntiTrackingCommon::IsOnContentBlockingAllowList(
parent->GetDocumentURI(),
false,
AntiTrackingCommon::eStorageChecks,
isOnAllowList)),
!isOnAllowList);

View File

@ -54,6 +54,11 @@ public:
bool mFakeDeviceChangeEventOn;
int32_t mChannels;
bool operator ==(const MediaEnginePrefs& aRhs)
{
return memcmp(this, &aRhs, sizeof(MediaEnginePrefs)) == 0;
};
// mWidth and/or mHeight may be zero (=adaptive default), so use functions.
int32_t GetWidth(bool aHD = false) const {

File diff suppressed because it is too large Load Diff

View File

@ -35,15 +35,12 @@ public:
bool aDelayAgnostic,
bool aExtendedFilter);
bool RequiresSharing() const override
{
return false;
}
bool RequiresSharing() const override { return false; }
nsString GetName() const override;
nsCString GetUUID() const override;
nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const ipc::PrincipalInfo& aPrincipalInfo,
@ -95,45 +92,32 @@ protected:
private:
/**
* Reevaluates the aggregated constraints of all allocations and restarts the
* underlying device if necessary.
* From a set of constraints and about:config preferences, output the correct
* set of preferences that can be sent to AudioInputProcessing.
*
* If the given AllocationHandle was already registered, its constraints will
* be updated before reevaluation. If not, they will be added before
* reevaluation.
* This can fail if the number of channels requested is zero, negative, or
* more than the device supports.
*/
nsresult ReevaluateAllocation(const RefPtr<AllocationHandle>& aHandle,
const NormalizedConstraints* aConstraintsUpdate,
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const char** aOutBadConstraint);
nsresult EvaluateSettings(const NormalizedConstraints& aConstraintsUpdate,
const MediaEnginePrefs& aInPrefs,
MediaEnginePrefs* aOutPrefs,
const char** aOutBadConstraint);
/**
* From settings output by EvaluateSettings, send those settings to the
* AudioInputProcessing instance and the main thread (for use in GetSettings).
*/
void ApplySettings(const MediaEnginePrefs& aPrefs);
/**
* Updates the underlying (single) device with the aggregated constraints
* aNetConstraints. If the chosen settings for the device changes based on
* these new constraints, and capture is active, the device will be restarted.
* Sent the AudioProcessingModule parameter for a given processing algorithm.
*/
nsresult UpdateSingleSource(const RefPtr<const AllocationHandle>& aHandle,
const NormalizedConstraints& aNetConstraints,
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const char** aOutBadConstraint);
// These methods send a message to the AudioInputProcessing instance.
void UpdateAECSettingsIfNeeded(bool aEnable, webrtc::EcModes aMode);
void UpdateAGCSettingsIfNeeded(bool aEnable, webrtc::AgcModes aMode);
void UpdateNSSettingsIfNeeded(bool aEnable, webrtc::NsModes aMode);
void UpdateAPMExtraOptions(bool aExtendedFilter, bool aDelayAgnostic);
void ApplySettings(const MediaEnginePrefs& aPrefs,
RefPtr<MediaStreamGraphImpl> aGraph);
bool HasEnabledTrack() const;
RefPtr<AllocationHandle> mHandle;
TrackID mTrackID = TRACK_NONE;
PrincipalHandle mPrincipal = PRINCIPAL_HANDLE_NONE;
bool mEnabled = false;
const RefPtr<AudioDeviceInfo> mDeviceInfo;
const bool mDelayAgnostic;
@ -146,11 +130,8 @@ private:
// The current settings for the underlying device.
// Constructed on the MediaManager thread, and then only ever accessed on the
// main thread.
const nsMainThreadPtrHandle<media::Refcountable<dom::MediaTrackSettings>> mSettings;
// To only update microphone when needed, we keep track of the prefs
// representing the currently applied settings for this source. This is the
// net result of the prefs across all allocations.
MediaEnginePrefs mNetPrefs;
const nsMainThreadPtrHandle<media::Refcountable<dom::MediaTrackSettings>>
mSettings;
// Current state of the resource for this source.
MediaEngineSourceState mState;
@ -174,8 +155,7 @@ public:
TrackID aTrackID,
const PrincipalHandle& aPrincipalHandle);
void Pull(const RefPtr<const AllocationHandle>& aHandle,
const RefPtr<SourceMediaStream>& aStream,
void Pull(const RefPtr<SourceMediaStream>& aStream,
TrackID aTrackID,
StreamTime aDesiredTime,
const PrincipalHandle& aPrincipalHandle);
@ -283,17 +263,14 @@ private:
bool mEnded;
};
class MediaEngineWebRTCAudioCaptureSource : public MediaEngineSource
{
public:
explicit MediaEngineWebRTCAudioCaptureSource(const char* aUuid)
{
}
explicit MediaEngineWebRTCAudioCaptureSource(const char* aUuid) {}
nsString GetName() const override;
nsCString GetUUID() const override;
nsresult Allocate(const dom::MediaTrackConstraints &aConstraints,
const MediaEnginePrefs &aPrefs,
nsresult Allocate(const dom::MediaTrackConstraints& aConstraints,
const MediaEnginePrefs& aPrefs,
const nsString& aDeviceId,
const ipc::PrincipalInfo& aPrincipalInfo,
AllocationHandle** aOutHandle,

View File

@ -312,73 +312,6 @@ NormalizedConstraints::NormalizedConstraints(
}
}
// Merge constructor. Create net constraints out of merging a set of others.
// This is only used to resolve competing constraints from concurrent requests,
// something the spec doesn't cover.
NormalizedConstraints::NormalizedConstraints(
const nsTArray<const NormalizedConstraints*>& aOthers)
: NormalizedConstraintSet(*aOthers[0])
, mBadConstraint(nullptr)
{
for (auto& entry : aOthers[0]->mAdvanced) {
mAdvanced.push_back(entry);
}
// Create a list of member pointers.
nsTArray<MemberPtrType> list;
NormalizedConstraints dummy(dom::MediaTrackConstraints(), &list);
// Do intersection of all required constraints, and average of ideals,
for (uint32_t i = 1; i < aOthers.Length(); i++) {
auto& other = *aOthers[i];
for (auto& memberPtr : list) {
auto& member = this->*memberPtr;
auto& otherMember = other.*memberPtr;
if (!member.Merge(otherMember)) {
mBadConstraint = member.mName;
return;
}
}
for (auto& entry : other.mAdvanced) {
mAdvanced.push_back(entry);
}
}
for (auto& memberPtr : list) {
(this->*memberPtr).FinalizeMerge();
}
// ...except for resolution and frame rate where we take the highest ideal.
// This is a bit of a hack based on the perception that people would be more
// surprised if they were to get lower resolution than they ideally requested.
//
// The spec gives browsers leeway here, saying they "SHOULD use the one with
// the smallest fitness distance", and also does not directly address the
// problem of competing constraints at all. There is no real web interop issue
// here since this is more about interop with other tabs on the same browser.
//
// We should revisit this logic once we support downscaling of resolutions and
// decimating of frame rates, per track.
for (auto& other : aOthers) {
mWidth.TakeHighestIdeal(other->mWidth);
mHeight.TakeHighestIdeal(other->mHeight);
// Consider implicit 30 fps default in comparison of competing constraints.
// Avoids 160x90x10 and 640x480 becoming 1024x768x10 (fitness distance flaw)
// This pretty much locks in 30 fps or higher, except for single-tab use.
auto frameRate = other->mFrameRate;
if (frameRate.mIdeal.isNothing()) {
frameRate.mIdeal.emplace(30);
}
mFrameRate.TakeHighestIdeal(frameRate);
}
}
FlattenedConstraints::FlattenedConstraints(const NormalizedConstraints& aOther)
: NormalizedConstraintSet(aOther)
{

View File

@ -283,10 +283,6 @@ struct NormalizedConstraints : public NormalizedConstraintSet
explicit NormalizedConstraints(const dom::MediaTrackConstraints& aOther,
nsTArray<MemberPtrType>* aList = nullptr);
// Merge constructor
explicit NormalizedConstraints(
const nsTArray<const NormalizedConstraints*>& aOthers);
std::vector<NormalizedConstraintSet> mAdvanced;
const char* mBadConstraint;
};

View File

@ -105,32 +105,6 @@ OSFileConstantsService::Paths
nsString tmpDir;
nsString profileDir;
nsString localProfileDir;
/**
* The user's home directory
*/
nsString homeDir;
/**
* The user's 'application data' directory.
* Windows:
* HOME = Documents and Settings\$USER\Application Data
* UAppData = $HOME[\$vendor]\$name
*
* Unix:
* HOME = ~
* UAppData = $HOME/.[$vendor/]$name
*
* Mac:
* HOME = ~
* UAppData = $HOME/Library/Application Support/$name
*/
nsString userApplicationDataDir;
#if defined(XP_MACOSX)
/**
* The user's Library directory.
*/
nsString macUserLibDir;
#endif // defined(XP_MACOSX)
Paths()
{
@ -138,12 +112,6 @@ OSFileConstantsService::Paths
tmpDir.SetIsVoid(true);
profileDir.SetIsVoid(true);
localProfileDir.SetIsVoid(true);
homeDir.SetIsVoid(true);
userApplicationDataDir.SetIsVoid(true);
#if defined(XP_MACOSX)
macUserLibDir.SetIsVoid(true);
#endif // defined(XP_MACOSX)
}
};
@ -251,16 +219,7 @@ OSFileConstantsService::InitOSFileConstants()
}
}
// For other directories, ignore errors (they may be undefined on
// some platforms or in non-Firefox embeddings of Gecko).
GetPathToSpecialDir(NS_OS_TEMP_DIR, paths->tmpDir);
GetPathToSpecialDir(NS_OS_HOME_DIR, paths->homeDir);
GetPathToSpecialDir(XRE_USER_APP_DATA_DIR, paths->userApplicationDataDir);
#if defined(XP_MACOSX)
GetPathToSpecialDir(NS_MAC_USER_LIB_DIR, paths->macUserLibDir);
#endif // defined(XP_MACOSX)
mPaths = std::move(paths);
@ -935,20 +894,6 @@ OSFileConstantsService::DefineOSFileConstants(JSContext* aCx,
return false;
}
if (!SetStringProperty(aCx, objPath, "homeDir", mPaths->homeDir)) {
return false;
}
if (!SetStringProperty(aCx, objPath, "userApplicationDataDir", mPaths->userApplicationDataDir)) {
return false;
}
#if defined(XP_MACOSX)
if (!SetStringProperty(aCx, objPath, "macUserLibDir", mPaths->macUserLibDir)) {
return false;
}
#endif // defined(XP_MACOSX)
// sqlite3 is linked from different places depending on the platform
nsAutoString libsqlite3;
#if defined(ANDROID)

View File

@ -2607,7 +2607,6 @@ WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent,
, mDebugger(nullptr)
, mJSContext(nullptr)
, mPRThread(nullptr)
, mMainThreadEventTarget(GetMainThreadEventTarget())
, mWorkerControlEventTarget(new WorkerEventTarget(this,
WorkerEventTarget::Behavior::ControlOnly))
, mWorkerHybridEventTarget(new WorkerEventTarget(this,
@ -2716,7 +2715,6 @@ WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent,
// that ThrottledEventQueue can only be created on the main thread at the
// moment.
if (aParent) {
mMainThreadThrottledEventQueue = aParent->mMainThreadThrottledEventQueue;
mMainThreadEventTarget = aParent->mMainThreadEventTarget;
return;
}
@ -2730,17 +2728,8 @@ WorkerPrivate::WorkerPrivate(WorkerPrivate* aParent,
}
// Throttle events to the main thread using a ThrottledEventQueue specific to
// this worker thread. This may return nullptr during shutdown.
mMainThreadThrottledEventQueue = ThrottledEventQueue::Create(target);
// If we were able to creat the throttled event queue, then use it for
// dispatching our main thread runnables. Otherwise use our underlying
// base target.
if (mMainThreadThrottledEventQueue) {
mMainThreadEventTarget = mMainThreadThrottledEventQueue;
} else {
mMainThreadEventTarget = target.forget();
}
// this tree of worker threads.
mMainThreadEventTarget = ThrottledEventQueue::Create(target);
}
WorkerPrivate::~WorkerPrivate()
@ -3316,9 +3305,8 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
// If the worker thread is spamming the main thread faster than it can
// process the work, then pause the worker thread until the MT catches
// up.
if (mMainThreadThrottledEventQueue &&
mMainThreadThrottledEventQueue->Length() > 5000) {
mMainThreadThrottledEventQueue->AwaitIdle();
if (mMainThreadEventTarget->Length() > 5000) {
mMainThreadEventTarget->AwaitIdle();
}
}

View File

@ -1367,8 +1367,7 @@ private:
nsTArray<WorkerPrivate*> mChildWorkers;
nsTObserverArray<WorkerHolder*> mHolders;
nsTArray<nsAutoPtr<TimeoutInfo>> mTimeouts;
RefPtr<ThrottledEventQueue> mMainThreadThrottledEventQueue;
nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
RefPtr<ThrottledEventQueue> mMainThreadEventTarget;
RefPtr<WorkerEventTarget> mWorkerControlEventTarget;
RefPtr<WorkerEventTarget> mWorkerHybridEventTarget;

View File

@ -2426,7 +2426,7 @@ nsCSSFrameConstructor::ConstructDocElementFrame(Element* aDocEle
RefPtr<nsXBLBinding> binding;
rv = xblService->LoadBindings(aDocElement, display->mBinding->GetURI(),
display->mBinding->mExtraData->Principal(),
display->mBinding->ExtraData()->Principal(),
getter_AddRefs(binding), &resolveStyle);
if (NS_FAILED(rv) && rv != NS_ERROR_XBL_BLOCKED) {
// Binding will load asynchronously.
@ -5580,7 +5580,7 @@ nsCSSFrameConstructor::LoadXBLBindingIfNeeded(nsIContent& aContent,
bool resolveStyle;
nsresult rv = xblService->LoadBindings(aContent.AsElement(),
binding->GetURI(),
binding->mExtraData->Principal(),
binding->ExtraData()->Principal(),
getter_AddRefs(newPendingBinding->mBinding),
&resolveStyle);
if (NS_FAILED(rv)) {

View File

@ -0,0 +1,3 @@
<style>
:root { background: green }
</style>

View File

@ -0,0 +1,6 @@
<!doctype html>
<style>
@supports selector(div) {
:root { background: green }
}
</style>

View File

@ -2087,3 +2087,5 @@ fuzzy(0-1,0-625) == 1466638-1.html 1466638-1-ref.html
test-pref(layout.css.contain.enabled,true) == 1483946.html 1483946-ref.html
test-pref(layout.css.visited_links_enabled,false) == 1488155.html 1488155-ref.html
== 1492660-1.html 1492660-1-ref.html
pref(layout.css.supports-selector.enabled,true) == 1499386.html 1499386-ref.html
pref(layout.css.supports-selector.enabled,false) != 1499386.html 1499386-ref.html

View File

@ -1102,10 +1102,11 @@ FontFaceSet::FindOrCreateUserFontEntryFromFontFace(const nsACString& aFamilyName
const URLValue* url = component.url._0;
nsIURI* uri = url->GetURI();
face->mURI = uri ? new gfxFontSrcURI(uri) : nullptr;
face->mReferrer = url->mExtraData->GetReferrer();
face->mReferrerPolicy = url->mExtraData->GetReferrerPolicy();
URLExtraData* extraData = url->ExtraData();
face->mReferrer = extraData->GetReferrer();
face->mReferrerPolicy = extraData->GetReferrerPolicy();
face->mOriginPrincipal =
new gfxFontSrcPrincipal(url->mExtraData->Principal());
new gfxFontSrcPrincipal(extraData->Principal());
// agent and user stylesheets are treated slightly differently,
// the same-site origin check and access control headers are

View File

@ -1381,14 +1381,6 @@ Gecko_CounterStyle_GetAnonymous(const CounterStylePtr* aPtr)
return aPtr->AsAnonymous();
}
already_AddRefed<css::URLValue>
ServoBundledURI::IntoCssUrl(CORSMode aCorsMode)
{
RefPtr<css::URLValue> urlValue =
new css::URLValue(mURLString, do_AddRef(mExtraData), aCorsMode);
return urlValue.forget();
}
void
Gecko_SetNullImageValue(nsStyleImage* aImage)
{
@ -2005,9 +1997,9 @@ Gecko_nsStyleSVG_CopyContextProperties(nsStyleSVG* aDst, const nsStyleSVG* aSrc)
css::URLValue*
Gecko_URLValue_Create(ServoBundledURI aURI, mozilla::CORSMode aCORSMode)
Gecko_URLValue_Create(RawServoCssUrlDataStrong aCssUrl, CORSMode aCORSMode)
{
RefPtr<css::URLValue> url = aURI.IntoCssUrl(aCORSMode);
RefPtr<css::URLValue> url = new css::URLValue(aCssUrl.Consume(), aCORSMode);
return url.forget().take();
}
@ -2575,7 +2567,7 @@ LoadImportSheet(css::Loader* aLoader,
NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING("about:invalid"));
}
emptySheet->SetURIs(uri, uri, uri);
emptySheet->SetPrincipal(aURL->mExtraData->Principal());
emptySheet->SetPrincipal(aURL->ExtraData()->Principal());
emptySheet->SetComplete();
aParent->PrependStyleSheet(emptySheet);
return emptySheet.forget();
@ -2591,28 +2583,29 @@ Gecko_LoadStyleSheet(css::Loader* aLoader,
StyleSheet* aParent,
SheetLoadData* aParentLoadData,
css::LoaderReusableStyleSheets* aReusableSheets,
ServoBundledURI aServoURL,
RawServoCssUrlDataStrong aCssUrl,
RawServoMediaListStrong aMediaList)
{
MOZ_ASSERT(NS_IsMainThread());
// The CORS mode in the URLValue is irrelevant here.
// (CORS_NONE is used for all imported sheets in Load::LoadChildSheet.)
RefPtr<css::URLValue> url = aServoURL.IntoCssUrl(CORS_NONE);
RefPtr<css::URLValue> url = new css::URLValue(aCssUrl.Consume(), CORS_NONE);
return LoadImportSheet(aLoader, aParent, aParentLoadData, aReusableSheets,
url, aMediaList.Consume()).take();
}
void
Gecko_LoadStyleSheetAsync(css::SheetLoadDataHolder* aParentData,
ServoBundledURI aServoURL,
RawServoCssUrlDataStrong aCssUrl,
RawServoMediaListStrong aMediaList,
RawServoImportRuleStrong aImportRule)
{
RefPtr<SheetLoadDataHolder> loadData = aParentData;
// The CORS mode in the URLValue is irrelevant here.
// (CORS_NONE is used for all imported sheets in Load::LoadChildSheet.)
RefPtr<css::URLValue> urlVal = aServoURL.IntoCssUrl(CORS_NONE);
RefPtr<css::URLValue> urlVal =
new css::URLValue(aCssUrl.Consume(), CORS_NONE);
RefPtr<RawServoMediaList> mediaList = aMediaList.Consume();
RefPtr<RawServoImportRule> importRule = aImportRule.Consume();
NS_DispatchToMainThread(NS_NewRunnableFunction(__func__,

View File

@ -61,16 +61,6 @@ const bool GECKO_IS_NIGHTLY = false;
void Gecko_Release##name_##ArbitraryThread(class_* aPtr) \
{ NS_RELEASE(aPtr); }
class ServoBundledURI
{
public:
// NOTE(emilio): Not calling IntoCssUrl will cause to leak the
// string, so don't do that :)
already_AddRefed<mozilla::css::URLValue> IntoCssUrl(mozilla::CORSMode);
mozilla::ServoRawOffsetArc<RustString> mURLString;
mozilla::URLExtraData* mExtraData;
};
extern "C" {
// Debugging stuff.
@ -139,12 +129,12 @@ mozilla::StyleSheet* Gecko_LoadStyleSheet(
mozilla::StyleSheet* parent,
mozilla::css::SheetLoadData* parent_load_data,
mozilla::css::LoaderReusableStyleSheets* reusable_sheets,
ServoBundledURI url,
RawServoCssUrlDataStrong url,
RawServoMediaListStrong media_list);
void Gecko_LoadStyleSheetAsync(
mozilla::css::SheetLoadDataHolder* parent_data,
ServoBundledURI url,
RawServoCssUrlDataStrong url,
RawServoMediaListStrong media_list,
RawServoImportRuleStrong import_rule);
@ -651,7 +641,7 @@ void Gecko_nsStyleSVG_CopyContextProperties(
const nsStyleSVG* src);
mozilla::css::URLValue* Gecko_URLValue_Create(
ServoBundledURI uri,
RawServoCssUrlDataStrong url,
mozilla::CORSMode aCORSMode);
size_t Gecko_URLValue_SizeOfIncludingThis(mozilla::css::URLValue* url);

View File

@ -483,8 +483,7 @@ ImageLoader::LoadImage(URLValue* aImage, nsIDocument* aLoadingDoc)
int32_t loadFlags = nsIRequest::LOAD_NORMAL |
nsContentUtils::CORSModeToLoadImageFlags(aImage->CorsMode());
URLExtraData* data = aImage->mExtraData;
URLExtraData* data = aImage->ExtraData();
RefPtr<imgRequestProxy> request;
nsresult rv = nsContentUtils::LoadImage(uri, aLoadingDoc, aLoadingDoc,

Some files were not shown because too many files have changed in this diff Show More