Merge autoland to mozilla-central. a=merge

This commit is contained in:
Margareta Eliza Balazs 2018-03-17 23:50:46 +02:00
commit 37bdf96634
54 changed files with 686 additions and 551 deletions

View File

@ -3022,7 +3022,8 @@ var BrowserOnClick = {
case "Browser:CertExceptionError":
this.onCertError(msg.target, msg.data.elementId,
msg.data.isTopFrame, msg.data.location,
msg.data.securityInfoAsString);
msg.data.securityInfoAsString,
msg.data.frameId);
break;
case "Browser:OpenCaptivePortalPage":
CaptivePortalWatcher.ensureCaptivePortalTab();
@ -3067,7 +3068,7 @@ var BrowserOnClick = {
}
},
onCertError(browser, elementId, isTopFrame, location, securityInfoAsString) {
onCertError(browser, elementId, isTopFrame, location, securityInfoAsString, frameId) {
let secHistogram = Services.telemetry.getHistogramById("SECURITY_UI");
let securityInfo;
@ -3118,9 +3119,10 @@ var BrowserOnClick = {
securityInfo = getSecurityInfo(securityInfoAsString);
let errorInfo = getDetailedCertErrorInfo(location,
securityInfo);
browser.messageManager.sendAsyncMessage( "CertErrorDetails", {
browser.messageManager.sendAsyncMessage("CertErrorDetails", {
code: securityInfo.errorCode,
info: errorInfo
info: errorInfo,
frameId,
});
break;

View File

@ -234,30 +234,35 @@ var AboutNetAndCertErrorListener = {
chromeGlobal.addEventListener("AboutNetErrorResetPreferences", this, false, true);
},
get isAboutNetError() {
return content.document.documentURI.startsWith("about:neterror");
isAboutNetError(doc) {
return doc.documentURI.startsWith("about:neterror");
},
get isAboutCertError() {
return content.document.documentURI.startsWith("about:certerror");
isAboutCertError(doc) {
return doc.documentURI.startsWith("about:certerror");
},
receiveMessage(msg) {
if (!this.isAboutCertError) {
return;
}
if (msg.name == "CertErrorDetails") {
let frameDocShell = WebNavigationFrames.findDocShell(msg.data.frameId, docShell);
// We need nsIWebNavigation to access docShell.document.
frameDocShell && frameDocShell.QueryInterface(Ci.nsIWebNavigation);
if (!frameDocShell || !this.isAboutCertError(frameDocShell.document)) {
return;
}
switch (msg.name) {
case "CertErrorDetails":
this.onCertErrorDetails(msg);
break;
case "Browser:CaptivePortalFreed":
this.onCaptivePortalFreed(msg);
break;
this.onCertErrorDetails(msg, frameDocShell);
} else if (msg.name == "Browser:CaptivePortalFreed") {
// TODO: This check is not correct for frames.
if (!this.isAboutCertError(content.document)) {
return;
}
this.onCaptivePortalFreed(msg);
}
},
_getCertValidityRange() {
_getCertValidityRange(docShell) {
let {securityInfo} = docShell.failedChannel;
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
let certs = securityInfo.failedCertChain.getEnumerator();
@ -275,10 +280,12 @@ var AboutNetAndCertErrorListener = {
return {notBefore, notAfter};
},
onCertErrorDetails(msg) {
let div = content.document.getElementById("certificateErrorText");
onCertErrorDetails(msg, docShell) {
let doc = docShell.document;
let div = doc.getElementById("certificateErrorText");
div.textContent = msg.data.info;
let learnMoreLink = content.document.getElementById("learnMoreLink");
let learnMoreLink = doc.getElementById("learnMoreLink");
let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
switch (msg.data.code) {
@ -301,7 +308,7 @@ var AboutNetAndCertErrorListener = {
let lastFetched = Services.prefs.getIntPref(PREF_BLOCKLIST_LAST_FETCHED, 0) * 1000;
let now = Date.now();
let certRange = this._getCertValidityRange();
let certRange = this._getCertValidityRange(docShell);
let approximateDate = now - difference * 1000;
// If the difference is more than a day, we last fetched the date in the last 5 days,
@ -315,17 +322,12 @@ var AboutNetAndCertErrorListener = {
// negative difference means local time is behind server time
approximateDate = formatter.format(new Date(approximateDate));
content.document.getElementById("wrongSystemTime_URL")
.textContent = content.document.location.hostname;
content.document.getElementById("wrongSystemTime_systemDate")
.textContent = systemDate;
content.document.getElementById("wrongSystemTime_actualDate")
.textContent = approximateDate;
doc.getElementById("wrongSystemTime_URL").textContent = doc.location.hostname;
doc.getElementById("wrongSystemTime_systemDate").textContent = systemDate;
doc.getElementById("wrongSystemTime_actualDate").textContent = approximateDate;
content.document.getElementById("errorShortDesc")
.style.display = "none";
content.document.getElementById("wrongSystemTimePanel")
.style.display = "block";
doc.getElementById("errorShortDesc").style.display = "none";
doc.getElementById("wrongSystemTimePanel").style.display = "block";
// If there is no clock skew with Kinto servers, check against the build date.
// (The Kinto ping could have happened when the time was still right, or not at all)
@ -348,15 +350,13 @@ var AboutNetAndCertErrorListener = {
dateStyle: "short"
});
content.document.getElementById("wrongSystemTimeWithoutReference_URL")
.textContent = content.document.location.hostname;
content.document.getElementById("wrongSystemTimeWithoutReference_systemDate")
doc.getElementById("wrongSystemTimeWithoutReference_URL")
.textContent = doc.location.hostname;
doc.getElementById("wrongSystemTimeWithoutReference_systemDate")
.textContent = formatter.format(systemDate);
content.document.getElementById("errorShortDesc")
.style.display = "none";
content.document.getElementById("wrongSystemTimeWithoutReferencePanel")
.style.display = "block";
doc.getElementById("errorShortDesc").style.display = "none";
doc.getElementById("wrongSystemTimeWithoutReferencePanel").style.display = "block";
}
}
learnMoreLink.href = baseURL + "time-errors";
@ -369,13 +369,20 @@ var AboutNetAndCertErrorListener = {
},
handleEvent(aEvent) {
if (!this.isAboutNetError && !this.isAboutCertError) {
let doc;
if (aEvent.originalTarget instanceof Ci.nsIDOMDocument) {
doc = aEvent.originalTarget;
} else {
doc = aEvent.originalTarget.ownerDocument;
}
if (!this.isAboutNetError(doc) && !this.isAboutCertError(doc)) {
return;
}
switch (aEvent.type) {
case "AboutNetErrorLoad":
this.onPageLoad(aEvent);
this.onPageLoad(aEvent.originalTarget, doc.defaultView);
break;
case "AboutNetErrorOpenCaptivePortal":
this.openCaptivePortalPage(aEvent);
@ -402,18 +409,16 @@ var AboutNetAndCertErrorListener = {
return false;
},
onPageLoad(evt) {
onPageLoad(originalTarget, win) {
// Values for telemtery bins: see TLS_ERROR_REPORT_UI in Histograms.json
const TLS_ERROR_REPORT_TELEMETRY_UI_SHOWN = 0;
if (this.isAboutCertError) {
let originalTarget = evt.originalTarget;
let ownerDoc = originalTarget.ownerDocument;
ClickEventHandler.onCertError(originalTarget, ownerDoc);
if (this.isAboutCertError(win.document)) {
ClickEventHandler.onCertError(originalTarget, win);
}
let automatic = Services.prefs.getBoolPref("security.ssl.errorReporting.automatic");
content.dispatchEvent(new content.CustomEvent("AboutNetErrorOptions", {
win.dispatchEvent(new win.CustomEvent("AboutNetErrorOptions", {
detail: JSON.stringify({
enabled: Services.prefs.getBoolPref("security.ssl.errorReporting.enabled"),
changedCertPrefs: this.changedCertPrefs(),
@ -442,9 +447,7 @@ var AboutNetAndCertErrorListener = {
// If we're enabling reports, send a report for this failure.
if (evt.detail) {
let win = evt.originalTarget.ownerGlobal;
let docShell = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
let docShell = win.document.docShell;
let {securityInfo} = docShell.failedChannel;
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
@ -478,13 +481,13 @@ var ClickEventHandler = {
// Handle click events from about pages
if (event.button == 0) {
if (ownerDoc.documentURI.startsWith("about:certerror")) {
this.onCertError(originalTarget, ownerDoc);
if (AboutNetAndCertErrorListener.isAboutCertError(ownerDoc)) {
this.onCertError(originalTarget, ownerDoc.defaultView);
return;
} else if (ownerDoc.documentURI.startsWith("about:blocked")) {
this.onAboutBlocked(originalTarget, ownerDoc);
return;
} else if (ownerDoc.documentURI.startsWith("about:neterror")) {
} else if (AboutNetAndCertErrorListener.isAboutNetError(ownerDoc)) {
this.onAboutNetError(event, ownerDoc.documentURI);
return;
}
@ -538,9 +541,7 @@ var ClickEventHandler = {
// Only when the owner doc has |mixedContentChannel| and the same origin
// should we allow mixed content.
json.allowMixedContent = false;
let docshell = ownerDoc.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
let docshell = ownerDoc.docShell;
if (docShell.mixedContentChannel) {
const sm = Services.scriptSecurityManager;
try {
@ -562,14 +563,13 @@ var ClickEventHandler = {
}
},
onCertError(targetElement, ownerDoc) {
let docShell = ownerDoc.defaultView.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell);
onCertError(targetElement, win) {
let docShell = win.document.docShell;
sendAsyncMessage("Browser:CertExceptionError", {
location: ownerDoc.location.href,
frameId: WebNavigationFrames.getFrameId(win),
location: win.document.location.href,
elementId: targetElement.getAttribute("id"),
isTopFrame: (ownerDoc.defaultView.parent === ownerDoc.defaultView),
isTopFrame: (win.parent === win),
securityInfoAsString: getSerializedSecurityInfo(docShell),
});
},

View File

@ -9,6 +9,8 @@ support-files =
POSTSearchEngine.xml
[browser_aboutCertError.js]
support-files =
dummy_page.html
[browser_aboutHome_imitate.js]
[browser_aboutHome_input.js]
skip-if = true # Bug 1409054 to remove; previously skipped for intermittents, e.g., Bug 1399648

View File

@ -6,104 +6,150 @@
// This is testing the aboutCertError page (Bug 1207107).
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", {});
const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
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");
let browser;
let certErrorLoaded;
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, BAD_CERT);
browser = gBrowser.selectedBrowser;
certErrorLoaded = BrowserTestUtils.waitForErrorPage(browser);
}, false);
for (let useFrame of [false, true]) {
let tab = await openErrorPage(BAD_CERT, useFrame);
let browser = tab.linkedBrowser;
info("Loading and waiting for the cert error");
await certErrorLoaded;
is(browser.webNavigation.canGoBack, false, "!webNavigation.canGoBack");
is(browser.webNavigation.canGoForward, false, "!webNavigation.canGoForward");
is(browser.webNavigation.canGoBack, false, "!webNavigation.canGoBack");
is(browser.webNavigation.canGoForward, false, "!webNavigation.canGoForward");
// Populate the shistory entries manually, since it happens asynchronously
// and the following tests will be too soon otherwise.
await TabStateFlusher.flush(browser);
let {entries} = JSON.parse(ss.getTabState(tab));
is(entries.length, 1, "there is one shistory entry");
// Populate the shistory entries manually, since it happens asynchronously
// and the following tests will be too soon otherwise.
await TabStateFlusher.flush(browser);
let {entries} = JSON.parse(ss.getTabState(tab));
is(entries.length, 1, "there is one shistory entry");
info("Clicking the go back button on about:certerror");
await ContentTask.spawn(browser, {frame: useFrame}, async function({frame}) {
let doc = frame ? content.document.querySelector("iframe").contentDocument : content.document;
info("Clicking the go back button on about:certerror");
await ContentTask.spawn(browser, null, async function() {
let doc = content.document;
let returnButton = doc.getElementById("returnButton");
is(returnButton.getAttribute("autofocus"), "true", "returnButton has autofocus");
returnButton.click();
let returnButton = doc.getElementById("returnButton");
if (!frame) {
is(returnButton.getAttribute("autofocus"), "true", "returnButton has autofocus");
}
returnButton.click();
await ContentTaskUtils.waitForEvent(this, "pageshow", true);
});
await ContentTaskUtils.waitForEvent(this, "pageshow", true);
});
is(browser.webNavigation.canGoBack, true, "webNavigation.canGoBack");
is(browser.webNavigation.canGoForward, false, "!webNavigation.canGoForward");
is(gBrowser.currentURI.spec, "about:home", "Went back");
is(browser.webNavigation.canGoBack, true, "webNavigation.canGoBack");
is(browser.webNavigation.canGoForward, false, "!webNavigation.canGoForward");
is(gBrowser.currentURI.spec, "about:home", "Went back");
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
}
});
add_task(async function checkReturnToPreviousPage() {
info("Loading a bad cert page and making sure 'return to previous page' goes back");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, GOOD_PAGE);
let browser = gBrowser.selectedBrowser;
for (let useFrame of [false, true]) {
let tab;
let browser;
if (useFrame) {
tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, GOOD_PAGE);
browser = tab.linkedBrowser;
info("Loading and waiting for the cert error");
let certErrorLoaded = BrowserTestUtils.waitForErrorPage(browser);
BrowserTestUtils.loadURI(browser, BAD_CERT);
await certErrorLoaded;
BrowserTestUtils.loadURI(browser, GOOD_PAGE_2);
await BrowserTestUtils.browserLoaded(browser, false, GOOD_PAGE_2);
await injectErrorPageFrame(tab, BAD_CERT);
} else {
tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, GOOD_PAGE);
browser = gBrowser.selectedBrowser;
is(browser.webNavigation.canGoBack, true, "webNavigation.canGoBack");
is(browser.webNavigation.canGoForward, false, "!webNavigation.canGoForward");
info("Loading and waiting for the cert error");
let certErrorLoaded = BrowserTestUtils.waitForErrorPage(browser);
BrowserTestUtils.loadURI(browser, BAD_CERT);
await certErrorLoaded;
}
// Populate the shistory entries manually, since it happens asynchronously
// and the following tests will be too soon otherwise.
await TabStateFlusher.flush(browser);
let {entries} = JSON.parse(ss.getTabState(tab));
is(entries.length, 2, "there are two shistory entries");
is(browser.webNavigation.canGoBack, true, "webNavigation.canGoBack");
is(browser.webNavigation.canGoForward, false, "!webNavigation.canGoForward");
info("Clicking the go back button on about:certerror");
await ContentTask.spawn(browser, null, async function() {
let doc = content.document;
let returnButton = doc.getElementById("returnButton");
returnButton.click();
// Populate the shistory entries manually, since it happens asynchronously
// and the following tests will be too soon otherwise.
await TabStateFlusher.flush(browser);
let {entries} = JSON.parse(ss.getTabState(tab));
is(entries.length, 2, "there are two shistory entries");
await ContentTaskUtils.waitForEvent(this, "pageshow", true);
});
info("Clicking the go back button on about:certerror");
await ContentTask.spawn(browser, {frame: useFrame}, async function({frame}) {
let doc = frame ? content.document.querySelector("iframe").contentDocument : content.document;
let returnButton = doc.getElementById("returnButton");
returnButton.click();
is(browser.webNavigation.canGoBack, false, "!webNavigation.canGoBack");
is(browser.webNavigation.canGoForward, true, "webNavigation.canGoForward");
is(gBrowser.currentURI.spec, GOOD_PAGE, "Went back");
await ContentTaskUtils.waitForEvent(this, "pageshow", true);
});
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
is(browser.webNavigation.canGoBack, false, "!webNavigation.canGoBack");
is(browser.webNavigation.canGoForward, true, "webNavigation.canGoForward");
is(gBrowser.currentURI.spec, GOOD_PAGE, "Went back");
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
}
});
add_task(async function checkBadStsCert() {
info("Loading a badStsCert and making sure exception button doesn't show up");
await BrowserTestUtils.openNewForegroundTab(gBrowser, GOOD_PAGE);
let browser = gBrowser.selectedBrowser;
info("Loading and waiting for the cert error");
let certErrorLoaded = BrowserTestUtils.waitForErrorPage(browser);
BrowserTestUtils.loadURI(browser, BAD_STS_CERT);
await certErrorLoaded;
for (let useFrame of [false, true]) {
let tab = await openErrorPage(BAD_STS_CERT, useFrame);
let browser = tab.linkedBrowser;
let exceptionButtonHidden = await ContentTask.spawn(browser, null, async function() {
let doc = content.document;
let exceptionButton = doc.getElementById("exceptionDialogButton");
return exceptionButton.hidden;
});
ok(exceptionButtonHidden, "Exception button is hidden");
let exceptionButtonHidden = await ContentTask.spawn(browser, {frame: useFrame}, async function({frame}) {
let doc = frame ? content.document.querySelector("iframe").contentDocument : content.document;
let exceptionButton = doc.getElementById("exceptionDialogButton");
return exceptionButton.hidden;
});
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
ok(exceptionButtonHidden, "Exception button is hidden");
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
}
});
// This checks that the appinfo.appBuildID starts with a date string,
@ -221,155 +267,142 @@ add_task(async function checkWrongSystemTimeWarning() {
add_task(async function checkAdvancedDetails() {
info("Loading a bad cert page and verifying the main error and advanced details section");
let browser;
let certErrorLoaded;
await BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, BAD_CERT);
browser = gBrowser.selectedBrowser;
certErrorLoaded = BrowserTestUtils.waitForErrorPage(browser);
}, false);
for (let useFrame of [false, true]) {
let tab = await openErrorPage(BAD_CERT, useFrame);
let browser = tab.linkedBrowser;
info("Loading and waiting for the cert error");
await certErrorLoaded;
let message = await ContentTask.spawn(browser, {frame: useFrame}, async function({frame}) {
let doc = frame ? content.document.querySelector("iframe").contentDocument : content.document;
let message = await ContentTask.spawn(browser, null, async function() {
let doc = content.document;
let shortDescText = doc.getElementById("errorShortDescText");
info("Main error text: " + shortDescText.textContent);
ok(shortDescText.textContent.includes("expired.example.com"),
"Should list hostname in error message.");
let shortDescText = doc.getElementById("errorShortDescText");
info("Main error text: " + shortDescText.textContent);
ok(shortDescText.textContent.includes("expired.example.com"),
"Should list hostname in error message.");
let advancedButton = doc.getElementById("advancedButton");
advancedButton.click();
let el = doc.getElementById("errorCode");
return { textContent: el.textContent, tagName: el.tagName };
});
is(message.textContent, "SEC_ERROR_EXPIRED_CERTIFICATE",
"Correct error message found");
is(message.tagName, "a", "Error message is a link");
let advancedButton = doc.getElementById("advancedButton");
advancedButton.click();
let el = doc.getElementById("errorCode");
return { textContent: el.textContent, tagName: el.tagName };
});
is(message.textContent, "SEC_ERROR_EXPIRED_CERTIFICATE",
"Correct error message found");
is(message.tagName, "a", "Error message is a link");
message = await ContentTask.spawn(browser, null, async function() {
let doc = content.document;
let errorCode = doc.getElementById("errorCode");
errorCode.click();
let div = doc.getElementById("certificateErrorDebugInformation");
let text = doc.getElementById("certificateErrorText");
message = await ContentTask.spawn(browser, {frame: useFrame}, async function({frame}) {
let doc = frame ? content.document.querySelector("iframe").contentDocument : content.document;
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
.getService(Ci.nsISerializationHelper);
let serializable = docShell.failedChannel.securityInfo
.QueryInterface(Ci.nsITransportSecurityInfo)
.QueryInterface(Ci.nsISerializable);
let serializedSecurityInfo = serhelper.serializeToString(serializable);
return {
divDisplay: content.getComputedStyle(div).display,
text: text.textContent,
securityInfoAsString: serializedSecurityInfo
};
});
isnot(message.divDisplay, "none", "Debug information is visible");
ok(message.text.includes(BAD_CERT), "Correct URL found");
ok(message.text.includes("Certificate has expired"),
"Correct error message found");
ok(message.text.includes("HTTP Strict Transport Security: false"),
"Correct HSTS value found");
ok(message.text.includes("HTTP Public Key Pinning: false"),
"Correct HPKP value found");
let certChain = getCertChain(message.securityInfoAsString);
ok(message.text.includes(certChain), "Found certificate chain");
let errorCode = doc.getElementById("errorCode");
errorCode.click();
let div = doc.getElementById("certificateErrorDebugInformation");
let text = doc.getElementById("certificateErrorText");
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
.getService(Ci.nsISerializationHelper);
let serializable = doc.docShell.failedChannel.securityInfo
.QueryInterface(Ci.nsITransportSecurityInfo)
.QueryInterface(Ci.nsISerializable);
let serializedSecurityInfo = serhelper.serializeToString(serializable);
return {
divDisplay: content.getComputedStyle(div).display,
text: text.textContent,
securityInfoAsString: serializedSecurityInfo
};
});
isnot(message.divDisplay, "none", "Debug information is visible");
ok(message.text.includes(BAD_CERT), "Correct URL found");
ok(message.text.includes("Certificate has expired"),
"Correct error message found");
ok(message.text.includes("HTTP Strict Transport Security: false"),
"Correct HSTS value found");
ok(message.text.includes("HTTP Public Key Pinning: false"),
"Correct HPKP value found");
let certChain = getCertChain(message.securityInfoAsString);
ok(message.text.includes(certChain), "Found certificate chain");
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
}
});
add_task(async function checkAdvancedDetailsForHSTS() {
info("Loading a bad STS cert page and verifying the advanced details section");
let browser;
let certErrorLoaded;
await BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, BAD_STS_CERT);
browser = gBrowser.selectedBrowser;
certErrorLoaded = BrowserTestUtils.waitForErrorPage(browser);
}, false);
for (let useFrame of [false, true]) {
let tab = await openErrorPage(BAD_STS_CERT, useFrame);
let browser = tab.linkedBrowser;
info("Loading and waiting for the cert error");
await certErrorLoaded;
let message = await ContentTask.spawn(browser, {frame: useFrame}, async function({frame}) {
let doc = frame ? content.document.querySelector("iframe").contentDocument : content.document;
let message = await ContentTask.spawn(browser, null, async function() {
let doc = content.document;
let advancedButton = doc.getElementById("advancedButton");
advancedButton.click();
let ec = doc.getElementById("errorCode");
let cdl = doc.getElementById("cert_domain_link");
return {
ecTextContent: ec.textContent,
ecTagName: ec.tagName,
cdlTextContent: cdl.textContent,
cdlTagName: cdl.tagName
};
});
let advancedButton = doc.getElementById("advancedButton");
advancedButton.click();
let ec = doc.getElementById("errorCode");
let cdl = doc.getElementById("cert_domain_link");
return {
ecTextContent: ec.textContent,
ecTagName: ec.tagName,
cdlTextContent: cdl.textContent,
cdlTagName: cdl.tagName
};
});
const badStsUri = Services.io.newURI(BAD_STS_CERT);
is(message.ecTextContent, "SSL_ERROR_BAD_CERT_DOMAIN",
"Correct error message found");
is(message.ecTagName, "a", "Error message is a link");
const url = badStsUri.prePath.slice(badStsUri.prePath.indexOf(".") + 1);
is(message.cdlTextContent, url,
"Correct cert_domain_link contents found");
is(message.cdlTagName, "a", "cert_domain_link is a link");
const badStsUri = Services.io.newURI(BAD_STS_CERT);
is(message.ecTextContent, "SSL_ERROR_BAD_CERT_DOMAIN",
"Correct error message found");
is(message.ecTagName, "a", "Error message is a link");
const url = badStsUri.prePath.slice(badStsUri.prePath.indexOf(".") + 1);
is(message.cdlTextContent, url,
"Correct cert_domain_link contents found");
is(message.cdlTagName, "a", "cert_domain_link is a link");
message = await ContentTask.spawn(browser, null, async function() {
let doc = content.document;
let errorCode = doc.getElementById("errorCode");
errorCode.click();
let div = doc.getElementById("certificateErrorDebugInformation");
let text = doc.getElementById("certificateErrorText");
message = await ContentTask.spawn(browser, {frame: useFrame}, async function({frame}) {
let doc = frame ? content.document.querySelector("iframe").contentDocument : content.document;
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
.getService(Ci.nsISerializationHelper);
let serializable = docShell.failedChannel.securityInfo
.QueryInterface(Ci.nsITransportSecurityInfo)
.QueryInterface(Ci.nsISerializable);
let serializedSecurityInfo = serhelper.serializeToString(serializable);
return {
divDisplay: content.getComputedStyle(div).display,
text: text.textContent,
securityInfoAsString: serializedSecurityInfo
};
});
isnot(message.divDisplay, "none", "Debug information is visible");
ok(message.text.includes(badStsUri.spec), "Correct URL found");
ok(message.text.includes("requested domain name does not match the server\u2019s certificate"),
"Correct error message found");
ok(message.text.includes("HTTP Strict Transport Security: false"),
"Correct HSTS value found");
ok(message.text.includes("HTTP Public Key Pinning: true"),
"Correct HPKP value found");
let certChain = getCertChain(message.securityInfoAsString);
ok(message.text.includes(certChain), "Found certificate chain");
let errorCode = doc.getElementById("errorCode");
errorCode.click();
let div = doc.getElementById("certificateErrorDebugInformation");
let text = doc.getElementById("certificateErrorText");
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
let serhelper = Cc["@mozilla.org/network/serialization-helper;1"]
.getService(Ci.nsISerializationHelper);
let serializable = doc.docShell.failedChannel.securityInfo
.QueryInterface(Ci.nsITransportSecurityInfo)
.QueryInterface(Ci.nsISerializable);
let serializedSecurityInfo = serhelper.serializeToString(serializable);
return {
divDisplay: content.getComputedStyle(div).display,
text: text.textContent,
securityInfoAsString: serializedSecurityInfo
};
});
isnot(message.divDisplay, "none", "Debug information is visible");
ok(message.text.includes(badStsUri.spec), "Correct URL found");
ok(message.text.includes("requested domain name does not match the server\u2019s certificate"),
"Correct error message found");
ok(message.text.includes("HTTP Strict Transport Security: false"),
"Correct HSTS value found");
ok(message.text.includes("HTTP Public Key Pinning: true"),
"Correct HPKP value found");
let certChain = getCertChain(message.securityInfoAsString);
ok(message.text.includes(certChain), "Found certificate chain");
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
}
});
add_task(async function checkUnknownIssuerLearnMoreLink() {
info("Loading a cert error for self-signed pages and checking the correct link is shown");
let browser;
let certErrorLoaded;
await BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, UNKNOWN_ISSUER);
browser = gBrowser.selectedBrowser;
certErrorLoaded = BrowserTestUtils.waitForErrorPage(browser);
}, false);
for (let useFrame of [false, true]) {
let tab = await openErrorPage(UNKNOWN_ISSUER, useFrame);
let browser = tab.linkedBrowser;
info("Loading and waiting for the cert error");
await certErrorLoaded;
let href = await ContentTask.spawn(browser, {frame: useFrame}, async function({frame}) {
let doc = frame ? content.document.querySelector("iframe").contentDocument : content.document;
let learnMoreLink = doc.getElementById("learnMoreLink");
return learnMoreLink.href;
});
ok(href.endsWith("security-error"), "security-error in the Learn More URL");
let href = await ContentTask.spawn(browser, null, async function() {
let learnMoreLink = content.document.getElementById("learnMoreLink");
return learnMoreLink.href;
});
ok(href.endsWith("security-error"), "security-error in the Learn More URL");
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
await BrowserTestUtils.removeTab(gBrowser.selectedTab);
}
});
function getCertChain(securityInfoAsString) {

View File

@ -0,0 +1,9 @@
<html>
<head>
<title>Dummy test page</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
</head>
<body>
<p>Dummy test page</p>
</body>
</html>

View File

@ -1212,6 +1212,10 @@ BrowserGlue.prototype = {
Services.tm.idleDispatchToMainThread(() => {
LanguagePrompt.init();
});
Services.tm.idleDispatchToMainThread(() => {
Services.blocklist.loadBlocklistAsync();
});
},
/**

View File

@ -3547,7 +3547,7 @@ var SessionStoreInternal = {
* a tab to speculatively connect on mouse hover.
*/
speculativeConnectOnTabHover(tab) {
if (this._restore_on_demand && !tab.__SS_connectionPrepared && tab.hasAttribute("pending")) {
if (tab.__SS_lazyData && !tab.__SS_connectionPrepared) {
let url = this.getLazyTabValue(tab, "url");
let prepared = this.prepareConnectionToHost(url);
// This is used to test if a connection has been made beforehand.

View File

@ -15,7 +15,6 @@ const { formDataURI } = require("../utils/request-utils");
const {
getDisplayedRequests,
getSelectedRequest,
getSortedRequests,
getWaterfallScale,
} = require("../selectors/index");
@ -65,7 +64,6 @@ class RequestListContent extends Component {
openStatistics: PropTypes.func.isRequired,
scale: PropTypes.number,
selectedRequest: PropTypes.object,
sortedRequests: PropTypes.array.isRequired,
requestFilterTypes: PropTypes.object.isRequired,
};
}
@ -245,8 +243,8 @@ class RequestListContent extends Component {
onContextMenu(evt) {
evt.preventDefault();
let { selectedRequest, sortedRequests } = this.props;
this.contextMenu.open(evt, selectedRequest, sortedRequests);
let { selectedRequest, displayedRequests } = this.props;
this.contextMenu.open(evt, selectedRequest, displayedRequests);
}
/**
@ -317,7 +315,6 @@ module.exports = connect(
firstRequestStartedMillis: state.requests.firstStartedMillis,
selectedRequest: getSelectedRequest(state),
scale: getWaterfallScale(state),
sortedRequests: getSortedRequests(state),
requestFilterTypes: state.filters.requestFilterTypes,
}),
(dispatch, props) => ({

View File

@ -26,7 +26,7 @@ class RequestListContextMenu {
this.props = props;
}
open(event, selectedRequest, sortedRequests) {
open(event, selectedRequest, requests) {
let {
id,
isCustom,
@ -143,8 +143,8 @@ class RequestListContextMenu {
id: "request-list-context-copy-all-as-har",
label: L10N.getStr("netmonitor.context.copyAllAsHar"),
accesskey: L10N.getStr("netmonitor.context.copyAllAsHar.accesskey"),
visible: sortedRequests.size > 0,
click: () => this.copyAllAsHar(sortedRequests),
visible: requests.size > 0,
click: () => this.copyAllAsHar(requests),
});
menu.push({
@ -158,8 +158,8 @@ class RequestListContextMenu {
id: "request-list-context-save-all-as-har",
label: L10N.getStr("netmonitor.context.saveAllAsHar"),
accesskey: L10N.getStr("netmonitor.context.saveAllAsHar.accesskey"),
visible: sortedRequests.size > 0,
click: () => this.saveAllAsHar(sortedRequests),
visible: requests.size > 0,
click: () => this.saveAllAsHar(requests),
});
menu.push({
@ -219,7 +219,7 @@ class RequestListContextMenu {
id: "request-list-context-perf",
label: L10N.getStr("netmonitor.context.perfTools"),
accesskey: L10N.getStr("netmonitor.context.perfTools.accesskey"),
visible: sortedRequests.size > 0,
visible: requests.size > 0,
click: () => openStatistics(true),
});
@ -393,25 +393,25 @@ class RequestListContextMenu {
/**
* Copy HAR from the network panel content to the clipboard.
*/
copyAllAsHar(sortedRequests) {
return HarExporter.copy(this.getDefaultHarOptions(sortedRequests));
copyAllAsHar(requests) {
return HarExporter.copy(this.getDefaultHarOptions(requests));
}
/**
* Save HAR from the network panel content to a file.
*/
saveAllAsHar(sortedRequests) {
saveAllAsHar(requests) {
// This will not work in launchpad
// document.execCommand(cut/copy) was denied because it was not called from
// inside a short running user-generated event handler.
// https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Interact_with_the_clipboard
return HarExporter.save(this.getDefaultHarOptions(sortedRequests));
return HarExporter.save(this.getDefaultHarOptions(requests));
}
getDefaultHarOptions(sortedRequests) {
getDefaultHarOptions(requests) {
return {
connector: this.props.connector,
items: sortedRequests,
items: requests,
};
}
}

View File

@ -1771,8 +1771,8 @@ DebuggerServer.ObjectActorPreviewers.Object = [
obj.class != "StyleSheetList" &&
obj.class != "CSSValueList" &&
obj.class != "NamedNodeMap" &&
!(rawObj instanceof Ci.nsIDOMFileList ||
rawObj instanceof Ci.nsIDOMNodeList)) {
obj.class != "FileList" &&
obj.class != "NodeList") {
return false;
}

View File

@ -32,7 +32,6 @@
#include "mozilla/dom/Element.h"
#include "mozilla/dom/SVGTitleElement.h"
#include "nsIDOMEvent.h"
#include "nsIDOMFileList.h"
#include "nsIDOMMouseEvent.h"
#include "nsIFormControl.h"
#include "nsIImageLoadingContent.h"

View File

@ -145,7 +145,6 @@
#include "nsQueryObject.h"
#include "nsContentUtils.h"
#include "nsCSSProps.h"
#include "nsIDOMFileList.h"
#include "nsIURIFixup.h"
#ifndef DEBUG
#include "nsIAppStartup.h"

View File

@ -144,7 +144,6 @@
#include "nsQueryObject.h"
#include "nsContentUtils.h"
#include "nsCSSProps.h"
#include "nsIDOMFileList.h"
#include "nsIURIFixup.h"
#include "nsIURIMutator.h"
#ifndef DEBUG

View File

@ -16,8 +16,7 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileList, mFiles, mParent)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMFileList)
NS_INTERFACE_MAP_ENTRY(nsIDOMFileList)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(FileList)
@ -29,22 +28,6 @@ FileList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return mozilla::dom::FileListBinding::Wrap(aCx, this, aGivenProto);
}
NS_IMETHODIMP
FileList::GetLength(uint32_t* aLength)
{
*aLength = Length();
return NS_OK;
}
NS_IMETHODIMP
FileList::Item(uint32_t aIndex, nsISupports** aValue)
{
nsCOMPtr<nsIDOMBlob> file = Item(aIndex);
file.forget(aValue);
return NS_OK;
}
File*
FileList::Item(uint32_t aIndex) const
{

View File

@ -10,7 +10,6 @@
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/UnionTypes.h"
#include "nsCycleCollectionParticipant.h"
#include "nsIDOMFileList.h"
#include "nsWrapperCache.h"
namespace mozilla {
@ -19,15 +18,13 @@ namespace dom {
class BlobImpls;
class File;
class FileList final : public nsIDOMFileList,
class FileList final : public nsISupports,
public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FileList)
NS_DECL_NSIDOMFILELIST
explicit FileList(nsISupports* aParent)
: mParent(aParent)
{}

View File

@ -11,7 +11,6 @@ DIRS += ['ipc']
XPIDL_SOURCES += [
'nsIDOMBlob.idl',
'nsIDOMFileList.idl',
]
XPIDL_MODULE = 'dom_file'

View File

@ -1,14 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
#include "nsISupports.idl"
[builtinclass, uuid(57128a85-34de-42db-a252-84dd57724a59)]
interface nsIDOMFileList : nsISupports
{
readonly attribute unsigned long length;
// returns a DOM File object
nsISupports item(in unsigned long index);
};

View File

@ -2755,12 +2755,11 @@ HTMLInputElement::SetFilesOrDirectories(const nsTArray<OwningFileOrDirectory>& a
}
void
HTMLInputElement::SetFiles(nsIDOMFileList* aFiles,
HTMLInputElement::SetFiles(FileList* aFiles,
bool aSetValueChanged)
{
MOZ_ASSERT(mFileData);
RefPtr<FileList> files = static_cast<FileList*>(aFiles);
mFileData->mFilesOrDirectories.Clear();
mFileData->ClearGetFilesHelpers();
@ -2770,12 +2769,11 @@ HTMLInputElement::SetFiles(nsIDOMFileList* aFiles,
}
if (aFiles) {
uint32_t listLength;
aFiles->GetLength(&listLength);
uint32_t listLength = aFiles->Length();
for (uint32_t i = 0; i < listLength; i++) {
OwningFileOrDirectory* element =
mFileData->mFilesOrDirectories.AppendElement();
element->SetAsFile() = files->Item(i);
element->SetAsFile() = aFiles->Item(i);
}
}

View File

@ -274,7 +274,7 @@ public:
void SetFilesOrDirectories(const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories,
bool aSetValueChanged);
void SetFiles(nsIDOMFileList* aFiles, bool aSetValueChanged);
void SetFiles(FileList* aFiles, bool aSetValueChanged);
// This method is used for test only. Onces the data is set, a 'change' event
// is dispatched.

View File

@ -5,9 +5,6 @@
#include "nsISupports.idl"
interface nsIControllers;
interface nsIDOMFileList;
/**
* The nsIDOMHTMLInputElement interface is the interface to a [X]HTML
* input element.

View File

@ -33,7 +33,6 @@
#include "nsIBFCacheEntry.h"
#include "nsIDocument.h"
#include "nsIDOMFileList.h"
#include "nsIPresShell.h"
#include "nsISupportsPrimitives.h"
#include "nsServiceManagerUtils.h"

View File

@ -17,7 +17,6 @@
#include "mozilla/dom/StructuredCloneHolder.h"
#include "nsGlobalWindow.h"
#include "nsJSUtils.h"
#include "nsIDOMFileList.h"
using namespace mozilla;
using namespace mozilla::dom;

View File

@ -31,7 +31,6 @@
#include "mozilla/dom/WindowBinding.h"
#include "mozilla/Scheduler.h"
#include "nsZipArchive.h"
#include "nsIDOMFileList.h"
#include "nsWindowMemoryReporter.h"
#include "nsDOMClassInfo.h"
#include "ShimInterfaceInfo.h"

View File

@ -25,7 +25,6 @@
#include "nsContentCreatorFunctions.h"
#include "nsContentUtils.h"
#include "mozilla/EventStates.h"
#include "nsIDOMFileList.h"
#include "nsTextNode.h"
using namespace mozilla;
@ -342,7 +341,7 @@ nsFileControlFrame::DnDListener::HandleEvent(nsIDOMEvent* aEvent)
}
nsresult
nsFileControlFrame::DnDListener::GetBlobImplForWebkitDirectory(nsIDOMFileList* aFileList,
nsFileControlFrame::DnDListener::GetBlobImplForWebkitDirectory(FileList* aFileList,
BlobImpl** aBlobImpl)
{
*aBlobImpl = nullptr;
@ -360,12 +359,11 @@ nsFileControlFrame::DnDListener::GetBlobImplForWebkitDirectory(nsIDOMFileList* a
return NS_ERROR_FAILURE;
}
FileList* files = static_cast<FileList*>(aFileList);
// webkitdirectory doesn't care about the length of the file list but
// only about the first item on it.
uint32_t len = files->Length();
uint32_t len = aFileList->Length();
if (len) {
File* file = files->Item(0);
File* file = aFileList->Item(0);
if (file) {
BlobImpl* impl = file->Impl();
if (impl && impl->IsDirectory()) {
@ -406,7 +404,7 @@ nsFileControlFrame::DnDListener::CanDropTheseFiles(DataTransfer* aDataTransfer,
uint32_t listLength = 0;
if (fileList) {
fileList->GetLength(&listLength);
listLength = fileList->Length();
}
return listLength <= 1 || aSupportsMultiple;
}

View File

@ -14,9 +14,9 @@
#include "nsIAnonymousContentCreator.h"
#include "nsCOMPtr.h"
class nsIDOMFileList;
namespace mozilla {
namespace dom {
class FileList;
class BlobImpl;
class DataTransfer;
} // namespace dom
@ -119,7 +119,7 @@ protected:
NS_DECL_NSIDOMEVENTLISTENER
nsresult GetBlobImplForWebkitDirectory(nsIDOMFileList* aFileList,
nsresult GetBlobImplForWebkitDirectory(mozilla::dom::FileList* aFileList,
mozilla::dom::BlobImpl** aBlobImpl);
bool IsValidDropData(mozilla::dom::DataTransfer* aDataTransfer);

View File

@ -582,7 +582,11 @@ function WaitForTestEnd(contentRootElement, inPrintMode, spellCheckedElements) {
return;
}
FlushRendering();
// We don't need to flush styles any more when we are in the state
// after reftest-wait has removed.
if (state != STATE_WAITING_TO_FINISH) {
FlushRendering();
}
switch (state) {
case STATE_WAITING_TO_FIRE_INVALIDATE_EVENT: {

View File

@ -175,7 +175,7 @@ def run(paths, linters, fmt, outgoing, workdir, edit,
# Encode output with 'replace' to avoid UnicodeEncodeErrors on
# environments that aren't using utf-8.
out = formatter(results, failed=lint.failed).encode(
out = formatter(results, failed=lint.failed | lint.failed_setup).encode(
sys.stdout.encoding or 'ascii', 'replace')
if out:
print(out)

View File

@ -12,6 +12,7 @@ from collections import defaultdict
from concurrent.futures import ProcessPoolExecutor
from math import ceil
from multiprocessing import cpu_count
from multiprocessing.queues import Queue
from subprocess import CalledProcessError
from mozversioncontrol import get_repository_object, MissingUpstreamRepo, InvalidRepoPath
@ -21,13 +22,27 @@ from .parser import Parser
from .pathutils import findobject
from .types import supported_types
SHUTDOWN = False
orig_sigint = signal.getsignal(signal.SIGINT)
def _run_linters(config, paths, **lintargs):
def _run_worker(config, paths, **lintargs):
results = defaultdict(list)
failed = []
if SHUTDOWN:
return results, failed
func = supported_types[config['type']]
res = func(paths, config, **lintargs) or []
try:
res = func(paths, config, **lintargs) or []
except Exception:
traceback.print_exc()
res = 1
except (KeyboardInterrupt, SystemExit):
return results, failed
finally:
sys.stdout.flush()
if not isinstance(res, (list, tuple)):
if res:
@ -38,16 +53,30 @@ def _run_linters(config, paths, **lintargs):
return results, failed
def _run_worker(*args, **kwargs):
try:
return _run_linters(*args, **kwargs)
except Exception:
# multiprocessing seems to munge worker exceptions, print
# it here so it isn't lost.
traceback.print_exc()
raise
finally:
sys.stdout.flush()
class InterruptableQueue(Queue):
"""A multiprocessing.Queue that catches KeyboardInterrupt when a worker is
blocking on it and returns None.
This is needed to gracefully handle KeyboardInterrupts when a worker is
blocking on ProcessPoolExecutor's call queue.
"""
def get(self, *args, **kwargs):
try:
return Queue.get(self, *args, **kwargs)
except KeyboardInterrupt:
return None
def _worker_sigint_handler(signum, frame):
"""Sigint handler for the worker subprocesses.
Tells workers not to process the extra jobs on the call queue that couldn't
be canceled by the parent process.
"""
global SHUTDOWN
SHUTDOWN = True
orig_sigint(signum, frame)
class LintRoller(object):
@ -71,8 +100,11 @@ class LintRoller(object):
self.lintargs = lintargs
self.lintargs['root'] = root
# linters that return non-zero
self.failed = set()
# result state
self.failed = None
self.failed_setup = None
self.results = None
self.root = root
def read(self, paths):
@ -91,7 +123,7 @@ class LintRoller(object):
if not self.linters:
raise LintersNotConfigured
failed = set()
self.failed_setup = set()
for linter in self.linters:
if 'setup' not in linter:
continue
@ -103,12 +135,12 @@ class LintRoller(object):
res = 1
if res:
failed.add(linter['name'])
self.failed_setup.add(linter['name'])
if failed:
print("error: problem with lint setup, skipping {}".format(', '.join(sorted(failed))))
self.linters = [l for l in self.linters if l['name'] not in failed]
self.failed.update(failed)
if self.failed_setup:
print("error: problem with lint setup, skipping {}".format(
', '.join(sorted(self.failed_setup))))
self.linters = [l for l in self.linters if l['name'] not in self.failed_setup]
return 1
return 0
@ -120,6 +152,16 @@ class LintRoller(object):
yield linter, paths[:chunk_size]
paths = paths[chunk_size:]
def _collect_results(self, future):
if future.cancelled():
return
results, failed = future.result()
if failed:
self.failed.update(set(failed))
for k, v in results.iteritems():
self.results[k].extend(v)
def roll(self, paths=None, outgoing=None, workdir=None, num_procs=None):
"""Run all of the registered linters against the specified file paths.
@ -133,6 +175,10 @@ class LintRoller(object):
if not self.linters:
raise LintersNotConfigured
# reset result state
self.results = defaultdict(list)
self.failed = set()
# Need to use a set in case vcs operations specify the same file
# more than once.
paths = paths or set()
@ -170,19 +216,38 @@ class LintRoller(object):
paths = map(os.path.abspath, paths)
num_procs = num_procs or cpu_count()
all_results = defaultdict(list)
with ProcessPoolExecutor(num_procs) as executor:
futures = [executor.submit(_run_worker, config, p, **self.lintargs)
for config, p in self._generate_jobs(paths, num_procs)]
# ignore SIGINT in parent so we can still get partial results
# from child processes. These should shutdown quickly anyway.
orig_sigint = signal.signal(signal.SIGINT, signal.SIG_IGN)
for future in futures:
results, failed = future.result()
if failed:
self.failed.update(set(failed))
for k, v in results.iteritems():
all_results[k].extend(v)
jobs = list(self._generate_jobs(paths, num_procs))
# Make sure we never spawn more processes than we have jobs.
num_procs = min(len(jobs), num_procs)
signal.signal(signal.SIGINT, _worker_sigint_handler)
executor = ProcessPoolExecutor(num_procs)
executor._call_queue = InterruptableQueue(executor._call_queue._maxsize)
# Submit jobs to the worker pool. The _collect_results method will be
# called when a job is finished. We store the futures so that they can
# be canceled in the event of a KeyboardInterrupt.
futures = []
for job in jobs:
future = executor.submit(_run_worker, *job, **self.lintargs)
future.add_done_callback(self._collect_results)
futures.append(future)
def _parent_sigint_handler(signum, frame):
"""Sigint handler for the parent process.
Cancels all jobs that have not yet been placed on the call queue.
The parent process won't exit until all workers have terminated.
Assuming the linters are implemented properly, this shouldn't take
more than a couple seconds.
"""
[f.cancel() for f in futures]
executor.shutdown(wait=False)
print("\nwarning: not all files were linted")
signal.signal(signal.SIGINT, signal.SIG_IGN)
signal.signal(signal.SIGINT, _parent_sigint_handler)
executor.shutdown()
signal.signal(signal.SIGINT, orig_sigint)
return all_results
return self.results

View File

@ -5,6 +5,7 @@
from __future__ import absolute_import, print_function
import os
import time
from mozlint import result
from mozlint.errors import LintException
@ -36,6 +37,11 @@ def raises(files, config, **lintargs):
raise LintException("Oh no something bad happened!")
def slow(files, config, **lintargs):
time.sleep(2)
return []
def structured(files, config, logger, **kwargs):
for path in files:
if os.path.isdir(path):

View File

@ -0,0 +1,8 @@
---
SlowLinter:
description: A linter that takes awhile to run
include:
- files
type: external
extensions: ['.js', '.jsm']
payload: external:slow

View File

@ -0,0 +1,20 @@
# 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/.
from __future__ import absolute_import
import os
import sys
here = os.path.abspath(os.path.dirname(__file__))
sys.path.insert(0, os.path.join(os.path.dirname(here), 'mozlint'))
from mozlint import cli
cli.SEARCH_PATHS.append(os.path.join(here, 'linters'))
if __name__ == '__main__':
parser = cli.MozlintParser()
args = vars(parser.parse_args(sys.argv[1:]))
args['root'] = here
sys.exit(cli.run(**args))

View File

@ -49,10 +49,11 @@ def test_cli_run_with_edit(run, parser, capfd):
out, err = capfd.readouterr()
out = out.splitlines()
assert ret == 1
assert len(out) == 5
assert out[0].endswith('foobar.js') # from the `echo` editor
assert "foobar.js: line 1, col 1, Error" in out[1]
assert "foobar.js: line 2, col 1, Error" in out[2]
assert "2 problems" in out[-1]
assert len(out) == 5
del os.environ['EDITOR']
with pytest.raises(SystemExit):

View File

@ -6,13 +6,16 @@ from __future__ import absolute_import
import os
import platform
import signal
import subprocess
import sys
import time
import mozunit
import pytest
from mozlint import ResultContainer
from mozlint.errors import LintersNotConfigured, LintException
from mozlint.errors import LintersNotConfigured
here = os.path.abspath(os.path.dirname(__file__))
@ -29,8 +32,10 @@ def test_roll_no_linters_configured(lint, files):
def test_roll_successful(lint, linters, files):
lint.read(linters)
assert lint.results is None
result = lint.roll(files)
assert len(result) == 1
assert lint.results == result
assert lint.failed == set([])
path = result.keys()[0]
@ -45,15 +50,12 @@ def test_roll_successful(lint, linters, files):
assert container.rule == 'no-foobar'
def test_roll_catch_exception(lint, lintdir, files):
def test_roll_catch_exception(lint, lintdir, files, capfd):
lint.read(os.path.join(lintdir, 'raises.yml'))
# suppress printed traceback from test output
old_stderr = sys.stderr
sys.stderr = open(os.devnull, 'w')
with pytest.raises(LintException):
lint.roll(files)
sys.stderr = old_stderr
lint.roll(files) # assert not raises
out, err = capfd.readouterr()
assert 'LintException' in err
def test_roll_with_excluded_path(lint, linters, files):
@ -76,13 +78,13 @@ def test_roll_with_invalid_extension(lint, lintdir, filedir):
def test_roll_with_failure_code(lint, lintdir, files):
lint.read(os.path.join(lintdir, 'badreturncode.yml'))
assert lint.failed == set([])
assert lint.failed is None
result = lint.roll(files, num_procs=1)
assert len(result) == 0
assert lint.failed == set(['BadReturnCodeLinter'])
def fake_run_linters(config, paths, **lintargs):
def fake_run_worker(config, paths, **lintargs):
return {'count': [1]}, []
@ -90,7 +92,7 @@ def fake_run_linters(config, paths, **lintargs):
reason="monkeypatch issues with multiprocessing on Windows")
@pytest.mark.parametrize('num_procs', [1, 4, 8, 16])
def test_number_of_jobs(monkeypatch, lint, linters, files, num_procs):
monkeypatch.setattr(sys.modules[lint.__module__], '_run_linters', fake_run_linters)
monkeypatch.setattr(sys.modules[lint.__module__], '_run_worker', fake_run_worker)
lint.read(linters)
num_jobs = len(lint.roll(files, num_procs=num_procs)['count'])
@ -105,7 +107,7 @@ def test_number_of_jobs(monkeypatch, lint, linters, files, num_procs):
reason="monkeypatch issues with multiprocessing on Windows")
@pytest.mark.parametrize('max_paths,expected_jobs', [(1, 12), (4, 6), (16, 6)])
def test_max_paths_per_job(monkeypatch, lint, linters, files, max_paths, expected_jobs):
monkeypatch.setattr(sys.modules[lint.__module__], '_run_linters', fake_run_linters)
monkeypatch.setattr(sys.modules[lint.__module__], '_run_worker', fake_run_worker)
files = files[:4]
assert len(files) == 4
@ -119,6 +121,23 @@ def test_max_paths_per_job(monkeypatch, lint, linters, files, max_paths, expecte
assert num_jobs == expected_jobs
@pytest.mark.skipif(platform.system() == 'Windows',
reason="signal.CTRL_C_EVENT isn't causing a KeyboardInterrupt on Windows")
def test_keyboard_interrupt():
# We use two linters so we'll have two jobs. One (string.yml) will complete
# quickly. The other (slow.yml) will run slowly. This way the first worker
# will be be stuck blocking on the ProcessPoolExecutor._call_queue when the
# signal arrives and the other still be doing work.
cmd = [sys.executable, 'runcli.py', '-l=string', '-l=slow']
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=here)
time.sleep(1)
proc.send_signal(signal.SIGINT)
out = proc.communicate()[0]
assert 'warning: not all files were linted' in out
assert 'Traceback' not in out
linters = ('setup.yml', 'setupfailed.yml', 'setupraised.yml')
@ -133,7 +152,7 @@ def test_setup(lint, linters, filedir, capfd):
assert 'setup failed' in out
assert 'setup raised' in out
assert 'error: problem with lint setup, skipping' in out
assert lint.failed == set(['SetupFailedLinter', 'SetupRaisedLinter'])
assert lint.failed_setup == set(['SetupFailedLinter', 'SetupRaisedLinter'])
if __name__ == '__main__':

1
servo/Cargo.lock generated
View File

@ -2815,6 +2815,7 @@ dependencies = [
"euclid 0.17.2 (registry+https://github.com/rust-lang/crates.io-index)",
"malloc_size_of 0.0.1",
"malloc_size_of_derive 0.0.1",
"style_traits 0.0.1",
"webrender_api 0.57.0 (git+https://github.com/servo/webrender)",
]

View File

@ -21,7 +21,7 @@ use script_traits::{MouseButton, MouseEventType, ScrollState, TouchEventType, To
use script_traits::{UntrustedNodeAddress, WindowSizeData, WindowSizeType};
use script_traits::CompositorEvent::{MouseMoveEvent, MouseButtonEvent, TouchEvent};
use servo_config::opts;
use servo_geometry::DeviceIndependentPixel;
use servo_geometry::{DeviceIndependentPixel, DeviceUintLength};
use std::collections::HashMap;
use std::env;
use std::fs::File;
@ -34,7 +34,7 @@ use style_traits::viewport::ViewportConstraints;
use time::{now, precise_time_ns, precise_time_s};
use touch::{TouchHandler, TouchAction};
use webrender;
use webrender_api::{self, DeviceUintRect, DeviceUintSize, HitTestFlags, HitTestResult};
use webrender_api::{self, DeviceIntPoint, DevicePoint, DeviceUintRect, DeviceUintSize, HitTestFlags, HitTestResult};
use webrender_api::{LayoutVector2D, ScrollEventPhase, ScrollLocation};
use windowing::{self, MouseWindowEvent, WebRenderDebugOption, WindowMethods};
@ -202,7 +202,7 @@ struct ScrollZoomEvent {
/// Scroll by this offset, or to Start or End
scroll_location: ScrollLocation,
/// Apply changes to the frame at this location
cursor: TypedPoint2D<i32, DevicePixel>,
cursor: DeviceIntPoint,
/// The scroll event phase.
phase: ScrollEventPhase,
/// The number of OS events that have been coalesced together into this one event.
@ -275,15 +275,15 @@ impl RenderTargetInfo {
}
}
fn initialize_png(gl: &gl::Gl, width: usize, height: usize) -> RenderTargetInfo {
fn initialize_png(gl: &gl::Gl, width: DeviceUintLength, height: DeviceUintLength) -> RenderTargetInfo {
let framebuffer_ids = gl.gen_framebuffers(1);
gl.bind_framebuffer(gl::FRAMEBUFFER, framebuffer_ids[0]);
let texture_ids = gl.gen_textures(1);
gl.bind_texture(gl::TEXTURE_2D, texture_ids[0]);
gl.tex_image_2d(gl::TEXTURE_2D, 0, gl::RGB as gl::GLint, width as gl::GLsizei,
height as gl::GLsizei, 0, gl::RGB, gl::UNSIGNED_BYTE, None);
gl.tex_image_2d(gl::TEXTURE_2D, 0, gl::RGB as gl::GLint, width.get() as gl::GLsizei,
height.get() as gl::GLsizei, 0, gl::RGB, gl::UNSIGNED_BYTE, None);
gl.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as gl::GLint);
gl.tex_parameter_i(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as gl::GLint);
@ -297,8 +297,8 @@ fn initialize_png(gl: &gl::Gl, width: usize, height: usize) -> RenderTargetInfo
gl.bind_renderbuffer(gl::RENDERBUFFER, depth_rb);
gl.renderbuffer_storage(gl::RENDERBUFFER,
gl::DEPTH_COMPONENT24,
width as gl::GLsizei,
height as gl::GLsizei);
width.get() as gl::GLsizei,
height.get() as gl::GLsizei);
gl.framebuffer_renderbuffer(gl::FRAMEBUFFER,
gl::DEPTH_ATTACHMENT,
gl::RENDERBUFFER,
@ -647,9 +647,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
device_pixel_ratio: dppx,
initial_viewport: initial_viewport,
};
let top_level_browsing_context_id = self.root_pipeline.as_ref().map(|pipeline| {
pipeline.top_level_browsing_context_id
});
let msg = ConstellationMsg::WindowSize(top_level_browsing_context_id, data, size_type);
if let Err(e) = self.constellation_chan.send(msg) {
@ -728,7 +730,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
}
fn hit_test_at_point(&self, point: TypedPoint2D<f32, DevicePixel>) -> HitTestResult {
fn hit_test_at_point(&self, point: DevicePoint) -> HitTestResult {
let dppx = self.page_zoom * self.hidpi_factor();
let scaled_point = (point / dppx).to_untyped();
@ -742,7 +744,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
pub fn on_mouse_window_move_event_class(&mut self, cursor: TypedPoint2D<f32, DevicePixel>) {
pub fn on_mouse_window_move_event_class(&mut self, cursor: DevicePoint) {
if opts::get().convert_mouse_to_touch {
self.on_touch_move(TouchId(0), cursor);
return
@ -751,7 +753,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
self.dispatch_mouse_window_move_event_class(cursor);
}
fn dispatch_mouse_window_move_event_class(&mut self, cursor: TypedPoint2D<f32, DevicePixel>) {
fn dispatch_mouse_window_move_event_class(&mut self, cursor: DevicePoint) {
let root_pipeline_id = match self.get_root_pipeline_id() {
Some(root_pipeline_id) => root_pipeline_id,
None => return,
@ -783,7 +785,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
&self,
event_type: TouchEventType,
identifier: TouchId,
point: TypedPoint2D<f32, DevicePixel>)
point: DevicePoint)
{
let results = self.hit_test_at_point(point);
if let Some(item) = results.items.first() {
@ -804,7 +806,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
pub fn on_touch_event(&mut self,
event_type: TouchEventType,
identifier: TouchId,
location: TypedPoint2D<f32, DevicePixel>) {
location: DevicePoint) {
match event_type {
TouchEventType::Down => self.on_touch_down(identifier, location),
TouchEventType::Move => self.on_touch_move(identifier, location),
@ -813,12 +815,12 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
}
fn on_touch_down(&mut self, identifier: TouchId, point: TypedPoint2D<f32, DevicePixel>) {
fn on_touch_down(&mut self, identifier: TouchId, point: DevicePoint) {
self.touch_handler.on_touch_down(identifier, point);
self.send_touch_event(TouchEventType::Down, identifier, point);
}
fn on_touch_move(&mut self, identifier: TouchId, point: TypedPoint2D<f32, DevicePixel>) {
fn on_touch_move(&mut self, identifier: TouchId, point: DevicePoint) {
match self.touch_handler.on_touch_move(identifier, point) {
TouchAction::Scroll(delta) => {
match point.cast() {
@ -849,7 +851,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
}
fn on_touch_up(&mut self, identifier: TouchId, point: TypedPoint2D<f32, DevicePixel>) {
fn on_touch_up(&mut self, identifier: TouchId, point: DevicePoint) {
self.send_touch_event(TouchEventType::Up, identifier, point);
if let TouchAction::Click = self.touch_handler.on_touch_up(identifier, point) {
@ -857,14 +859,14 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}
}
fn on_touch_cancel(&mut self, identifier: TouchId, point: TypedPoint2D<f32, DevicePixel>) {
fn on_touch_cancel(&mut self, identifier: TouchId, point: DevicePoint) {
// Send the event to script.
self.touch_handler.on_touch_cancel(identifier, point);
self.send_touch_event(TouchEventType::Cancel, identifier, point);
}
/// <http://w3c.github.io/touch-events/#mouse-events>
fn simulate_mouse_click(&mut self, p: TypedPoint2D<f32, DevicePixel>) {
fn simulate_mouse_click(&mut self, p: DevicePoint) {
let button = MouseButton::Left;
self.dispatch_mouse_window_move_event_class(p);
self.dispatch_mouse_window_event_class(MouseWindowEvent::MouseDown(button, p));
@ -874,7 +876,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
pub fn on_scroll_event(&mut self,
delta: ScrollLocation,
cursor: TypedPoint2D<i32, DevicePixel>,
cursor: DeviceIntPoint,
phase: TouchEventType) {
match phase {
TouchEventType::Move => self.on_scroll_window_event(delta, cursor),
@ -889,7 +891,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
fn on_scroll_window_event(&mut self,
scroll_location: ScrollLocation,
cursor: TypedPoint2D<i32, DevicePixel>) {
cursor: DeviceIntPoint) {
let event_phase = match (self.scroll_in_progress, self.in_scroll_transaction) {
(false, None) => ScrollEventPhase::Start,
(false, Some(last_scroll)) if last_scroll.elapsed() > Duration::from_millis(80) =>
@ -908,7 +910,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
fn on_scroll_start_window_event(&mut self,
scroll_location: ScrollLocation,
cursor: TypedPoint2D<i32, DevicePixel>) {
cursor: DeviceIntPoint) {
self.scroll_in_progress = true;
self.pending_scroll_zoom_events.push(ScrollZoomEvent {
magnification: 1.0,
@ -921,7 +923,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
fn on_scroll_end_window_event(&mut self,
scroll_location: ScrollLocation,
cursor: TypedPoint2D<i32, DevicePixel>) {
cursor: DeviceIntPoint) {
self.scroll_in_progress = false;
self.pending_scroll_zoom_events.push(ScrollZoomEvent {
magnification: 1.0,
@ -1254,8 +1256,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
fn composite_specific_target(&mut self,
target: CompositeTarget)
-> Result<Option<Image>, UnableToComposite> {
let (width, height) =
(self.frame_size.width as usize, self.frame_size.height as usize);
let (width, height) = (self.frame_size.width_typed(), self.frame_size.height_typed());
if !self.window.prepare_for_composite(width, height) {
return Err(UnableToComposite::WindowUnprepared)
}
@ -1375,9 +1376,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
fn draw_img(&self,
render_target_info: RenderTargetInfo,
width: usize,
height: usize)
width: DeviceUintLength,
height: DeviceUintLength)
-> RgbImage {
let width = width.get() as usize;
let height = height.get() as usize;
// For some reason, OSMesa fails to render on the 3rd
// attempt in headless mode, under some conditions.
// I think this can only be some kind of synchronization

View File

@ -6,7 +6,6 @@
use SendableFrameTree;
use compositor::CompositingReason;
use euclid::{Point2D, Size2D};
use gfx_traits::Epoch;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::{Key, KeyModifiers, KeyState, PipelineId, TopLevelBrowsingContextId};
@ -20,7 +19,7 @@ use std::sync::mpsc::{Receiver, Sender};
use style_traits::cursor::CursorKind;
use style_traits::viewport::ViewportConstraints;
use webrender;
use webrender_api;
use webrender_api::{self, DeviceIntPoint, DeviceUintSize};
/// Used to wake up the event loop, provided by the servo port/embedder.
@ -119,15 +118,16 @@ pub enum EmbedderMsg {
/// Alerts the embedder that the current page has changed its title.
ChangePageTitle(TopLevelBrowsingContextId, Option<String>),
/// Move the window to a point
MoveTo(TopLevelBrowsingContextId, Point2D<i32>),
MoveTo(TopLevelBrowsingContextId, DeviceIntPoint),
/// Resize the window to size
ResizeTo(TopLevelBrowsingContextId, Size2D<u32>),
ResizeTo(TopLevelBrowsingContextId, DeviceUintSize),
/// Get Window Informations size and position
GetClientWindow(TopLevelBrowsingContextId, IpcSender<(Size2D<u32>, Point2D<i32>)>),
GetClientWindow(TopLevelBrowsingContextId,
IpcSender<(DeviceUintSize, DeviceIntPoint)>),
/// Get screen size (pixel)
GetScreenSize(TopLevelBrowsingContextId, IpcSender<(Size2D<u32>)>),
GetScreenSize(TopLevelBrowsingContextId, IpcSender<(DeviceUintSize)>),
/// Get screen available size (pixel)
GetScreenAvailSize(TopLevelBrowsingContextId, IpcSender<(Size2D<u32>)>),
GetScreenAvailSize(TopLevelBrowsingContextId, IpcSender<(DeviceUintSize)>),
/// Wether or not to follow a link
AllowNavigation(TopLevelBrowsingContextId, ServoUrl, IpcSender<bool>),
/// Sends an unconsumed key event back to the embedder.

View File

@ -5,26 +5,25 @@
//! Abstract windowing methods. The concrete implementations of these can be found in `platform/`.
use compositor_thread::EventLoopWaker;
use euclid::{Point2D, Size2D};
use euclid::{TypedScale, TypedPoint2D, TypedSize2D};
use euclid::TypedScale;
use gleam::gl;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::{Key, KeyModifiers, KeyState, TopLevelBrowsingContextId, TraversalDirection};
use net_traits::net_error_list::NetError;
use script_traits::{LoadData, MouseButton, TouchEventType, TouchId};
use servo_geometry::DeviceIndependentPixel;
use servo_geometry::{DeviceIndependentPixel, DeviceUintLength};
use servo_url::ServoUrl;
use std::fmt::{Debug, Error, Formatter};
use std::rc::Rc;
use style_traits::DevicePixel;
use style_traits::cursor::CursorKind;
use webrender_api::{DeviceUintSize, DeviceUintRect, ScrollLocation};
use webrender_api::{DeviceIntPoint, DevicePoint, DeviceUintSize, DeviceUintRect, ScrollLocation};
#[derive(Clone)]
pub enum MouseWindowEvent {
Click(MouseButton, TypedPoint2D<f32, DevicePixel>),
MouseDown(MouseButton, TypedPoint2D<f32, DevicePixel>),
MouseUp(MouseButton, TypedPoint2D<f32, DevicePixel>),
Click(MouseButton, DevicePoint),
MouseDown(MouseButton, DevicePoint),
MouseUp(MouseButton, DevicePoint),
}
/// Various debug and profiling flags that WebRender supports.
@ -55,12 +54,12 @@ pub enum WindowEvent {
/// Sent when a mouse hit test is to be performed.
MouseWindowEventClass(MouseWindowEvent),
/// Sent when a mouse move.
MouseWindowMoveEventClass(TypedPoint2D<f32, DevicePixel>),
MouseWindowMoveEventClass(DevicePoint),
/// Touch event: type, identifier, point
Touch(TouchEventType, TouchId, TypedPoint2D<f32, DevicePixel>),
Touch(TouchEventType, TouchId, DevicePoint),
/// Sent when the user scrolls. The first point is the delta and the second point is the
/// origin.
Scroll(ScrollLocation, TypedPoint2D<i32, DevicePixel>, TouchEventType),
Scroll(ScrollLocation, DeviceIntPoint, TouchEventType),
/// Sent when the user zooms.
Zoom(f32),
/// Simulated "pinch zoom" gesture for non-touch platforms (e.g. ctrl-scrollwheel).
@ -126,21 +125,19 @@ pub trait WindowMethods {
fn framebuffer_size(&self) -> DeviceUintSize;
/// Returns the position and size of the window within the rendering area.
fn window_rect(&self) -> DeviceUintRect;
/// Returns the size of the window in density-independent "px" units.
fn size(&self) -> TypedSize2D<f32, DeviceIndependentPixel>;
/// Presents the window to the screen (perhaps by page flipping).
fn present(&self);
/// Return the size of the window with head and borders and position of the window values
fn client_window(&self, ctx: TopLevelBrowsingContextId) -> (Size2D<u32>, Point2D<i32>);
/// Return the size of the screen (pixel)
fn screen_size(&self, ctx: TopLevelBrowsingContextId) -> Size2D<u32>;
/// Return the available size of the screen (pixel)
fn screen_avail_size(&self, ctx: TopLevelBrowsingContextId) -> Size2D<u32>;
fn client_window(&self, ctx: TopLevelBrowsingContextId) -> (DeviceUintSize, DeviceIntPoint);
/// Return the size of the screen.
fn screen_size(&self, ctx: TopLevelBrowsingContextId) -> DeviceUintSize;
/// Return the available size of the screen.
fn screen_avail_size(&self, ctx: TopLevelBrowsingContextId) -> DeviceUintSize;
/// Set the size inside of borders and head
fn set_inner_size(&self, ctx: TopLevelBrowsingContextId, size: Size2D<u32>);
fn set_inner_size(&self, ctx: TopLevelBrowsingContextId, size: DeviceUintSize);
/// Set the window position
fn set_position(&self, ctx: TopLevelBrowsingContextId, point: Point2D<i32>);
fn set_position(&self, ctx: TopLevelBrowsingContextId, point: DeviceIntPoint);
/// Set fullscreen state
fn set_fullscreen_state(&self, ctx: TopLevelBrowsingContextId, state: bool);
@ -170,7 +167,7 @@ pub trait WindowMethods {
/// Requests that the window system prepare a composite. Typically this will involve making
/// some type of platform-specific graphics context current. Returns true if the composite may
/// proceed and false if it should not.
fn prepare_for_composite(&self, width: usize, height: usize) -> bool;
fn prepare_for_composite(&self, width: DeviceUintLength, height: DeviceUintLength) -> bool;
/// Sets the cursor to be used in the window.
fn set_cursor(&self, cursor: CursorKind);

View File

@ -14,4 +14,5 @@ app_units = "0.6"
euclid = "0.17"
malloc_size_of = { path = "../malloc_size_of" }
malloc_size_of_derive = { path = "../malloc_size_of_derive" }
style_traits = { path = "../style_traits" }
webrender_api = { git = "https://github.com/servo/webrender" }

View File

@ -5,16 +5,20 @@
extern crate app_units;
extern crate euclid;
extern crate malloc_size_of;
extern crate style_traits;
#[macro_use] extern crate malloc_size_of_derive;
extern crate webrender_api;
use app_units::{Au, MAX_AU, MIN_AU};
use euclid::{Point2D, Rect, Size2D};
use euclid::{Length, Point2D, Rect, Size2D};
use std::f32;
use style_traits::DevicePixel;
use webrender_api::{LayoutPoint, LayoutRect, LayoutSize};
// Units for use with euclid::length and euclid::scale_factor.
pub type DeviceUintLength = Length<u32, DevicePixel>;
/// A normalized "pixel" at the default resolution for the display.
///
/// Like the CSS "px" unit, the exact physical size of this unit may vary between devices, but it

View File

@ -11,9 +11,11 @@ use dom::bindings::root::{Dom, DomRoot};
use dom::globalscope::GlobalScope;
use dom::window::Window;
use dom_struct::dom_struct;
use euclid::Size2D;
use euclid::TypedSize2D;
use ipc_channel::ipc;
use script_traits::ScriptMsg;
use style_traits::CSSPixel;
use webrender_api::DeviceUintSize;
#[dom_struct]
pub struct Screen {
@ -35,18 +37,22 @@ impl Screen {
ScreenBinding::Wrap)
}
fn screen_size(&self) -> Size2D<u32> {
let (send, recv) = ipc::channel::<(Size2D<u32>)>().unwrap();
fn screen_size(&self) -> TypedSize2D<u32, CSSPixel> {
let (send, recv) = ipc::channel::<DeviceUintSize>().unwrap();
self.window.upcast::<GlobalScope>()
.script_to_constellation_chan().send(ScriptMsg::GetScreenSize(send)).unwrap();
recv.recv().unwrap_or(Size2D::zero())
let dpr = self.window.device_pixel_ratio();
let screen = recv.recv().unwrap_or(TypedSize2D::zero());
(screen.to_f32() / dpr).to_u32()
}
fn screen_avail_size(&self) -> Size2D<u32> {
let (send, recv) = ipc::channel::<(Size2D<u32>)>().unwrap();
fn screen_avail_size(&self) -> TypedSize2D<u32, CSSPixel> {
let (send, recv) = ipc::channel::<DeviceUintSize>().unwrap();
self.window.upcast::<GlobalScope>()
.script_to_constellation_chan().send(ScriptMsg::GetScreenAvailSize(send)).unwrap();
recv.recv().unwrap_or(Size2D::zero())
let dpr = self.window.device_pixel_ratio();
let screen = recv.recv().unwrap_or(TypedSize2D::zero());
(screen.to_f32() / dpr).to_u32()
}
}

View File

@ -48,7 +48,7 @@ use dom::windowproxy::WindowProxy;
use dom::worklet::Worklet;
use dom::workletglobalscope::WorkletGlobalScopeType;
use dom_struct::dom_struct;
use euclid::{Point2D, Vector2D, Rect, Size2D};
use euclid::{Point2D, Vector2D, Rect, Size2D, TypedPoint2D, TypedScale, TypedSize2D};
use fetch;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
@ -102,7 +102,7 @@ use style::properties::{ComputedValues, PropertyId};
use style::selector_parser::PseudoElement;
use style::str::HTML_SPACE_CHARACTERS;
use style::stylesheets::CssRuleType;
use style_traits::ParsingMode;
use style_traits::{CSSPixel, DevicePixel, ParsingMode};
use task::TaskCanceller;
use task_source::dom_manipulation::DOMManipulationTaskSource;
use task_source::file_reading::FileReadingTaskSource;
@ -116,7 +116,7 @@ use timers::{IsInterval, TimerCallback};
use tinyfiledialogs::{self, MessageBoxIcon};
use url::Position;
use webdriver_handlers::jsval_to_webdriver;
use webrender_api::{ExternalScrollId, DocumentId};
use webrender_api::{ExternalScrollId, DeviceIntPoint, DeviceUintSize, DocumentId};
use webvr_traits::WebVRMsg;
/// Current state of the window object
@ -930,11 +930,12 @@ impl WindowMethods for Window {
}
// https://drafts.csswg.org/cssom-view/#dom-window-resizeto
fn ResizeTo(&self, x: i32, y: i32) {
fn ResizeTo(&self, width: i32, height: i32) {
// Step 1
//TODO determine if this operation is allowed
let size = Size2D::new(x.to_u32().unwrap_or(1), y.to_u32().unwrap_or(1));
self.send_to_constellation(ScriptMsg::ResizeTo(size));
let dpr = self.device_pixel_ratio();
let size = TypedSize2D::new(width, height).to_f32() * dpr;
self.send_to_constellation(ScriptMsg::ResizeTo(size.to_u32()));
}
// https://drafts.csswg.org/cssom-view/#dom-window-resizeby
@ -948,8 +949,9 @@ impl WindowMethods for Window {
fn MoveTo(&self, x: i32, y: i32) {
// Step 1
//TODO determine if this operation is allowed
let point = Point2D::new(x, y);
self.send_to_constellation(ScriptMsg::MoveTo(point));
let dpr = self.device_pixel_ratio();
let point = TypedPoint2D::new(x, y).to_f32() * dpr;
self.send_to_constellation(ScriptMsg::MoveTo(point.to_i32()));
}
// https://drafts.csswg.org/cssom-view/#dom-window-moveby
@ -985,8 +987,7 @@ impl WindowMethods for Window {
// https://drafts.csswg.org/cssom-view/#dom-window-devicepixelratio
fn DevicePixelRatio(&self) -> Finite<f64> {
let dpr = self.window_size.get().map_or(1.0f32, |data| data.device_pixel_ratio.get());
Finite::wrap(dpr as f64)
Finite::wrap(self.device_pixel_ratio().get() as f64)
}
// https://html.spec.whatwg.org/multipage/#dom-window-status
@ -1174,10 +1175,16 @@ impl Window {
self.current_viewport.set(new_viewport)
}
pub fn client_window(&self) -> (Size2D<u32>, Point2D<i32>) {
let (send, recv) = ipc::channel::<(Size2D<u32>, Point2D<i32>)>().unwrap();
pub fn device_pixel_ratio(&self) -> TypedScale<f32, CSSPixel, DevicePixel> {
self.window_size.get().map_or(TypedScale::new(1.0), |data| data.device_pixel_ratio)
}
fn client_window(&self) -> (TypedSize2D<u32, CSSPixel>, TypedPoint2D<i32, CSSPixel>) {
let (send, recv) = ipc::channel::<(DeviceUintSize, DeviceIntPoint)>().unwrap();
self.send_to_constellation(ScriptMsg::GetClientWindow(send));
recv.recv().unwrap_or((Size2D::zero(), Point2D::zero()))
let (size, point) = recv.recv().unwrap_or((TypedSize2D::zero(), TypedPoint2D::zero()));
let dpr = self.device_pixel_ratio();
((size.to_f32() / dpr).to_u32(), (point.to_f32() / dpr).to_i32())
}
/// Advances the layout animation clock by `delta` milliseconds, and then

View File

@ -41,7 +41,7 @@ pub mod webdriver_msg;
use bluetooth_traits::BluetoothRequest;
use canvas_traits::webgl::WebGLPipeline;
use devtools_traits::{DevtoolScriptControlMsg, ScriptToDevtoolsControlMsg, WorkerId};
use euclid::{Size2D, Length, Point2D, Vector2D, Rect, TypedScale, TypedSize2D};
use euclid::{Length, Point2D, Vector2D, Rect, TypedSize2D, TypedScale};
use gfx_traits::Epoch;
use hyper::header::Headers;
use hyper::method::Method;
@ -69,7 +69,7 @@ use style_traits::CSSPixel;
use style_traits::SpeculativePainter;
use style_traits::cursor::CursorKind;
use webdriver_msg::{LoadStatus, WebDriverScriptCommand};
use webrender_api::{ExternalScrollId, DevicePixel, DocumentId, ImageKey};
use webrender_api::{ExternalScrollId, DevicePixel, DeviceUintSize, DocumentId, ImageKey};
use webvr_traits::{WebVREvent, WebVRMsg};
pub use script_msg::{LayoutMsg, ScriptMsg, EventResult, LogEntry};
@ -650,7 +650,7 @@ pub enum WebDriverCommandMsg {
/// Act as if keys were pressed in the browsing context with the given ID.
SendKeys(BrowsingContextId, Vec<(Key, KeyModifiers, KeyState)>),
/// Set the window size.
SetWindowSize(TopLevelBrowsingContextId, Size2D<u32>, IpcSender<WindowSizeData>),
SetWindowSize(TopLevelBrowsingContextId, DeviceUintSize, IpcSender<WindowSizeData>),
/// Take a screenshot of the window.
TakeScreenshot(TopLevelBrowsingContextId, IpcSender<Option<Image>>),
}

View File

@ -13,7 +13,7 @@ use WorkerGlobalScopeInit;
use WorkerScriptLoadOrigin;
use canvas_traits::canvas::CanvasMsg;
use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
use euclid::{Point2D, Size2D, TypedSize2D};
use euclid::{Size2D, TypedSize2D};
use gfx_traits::Epoch;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use msg::constellation_msg::{BrowsingContextId, PipelineId, TraversalDirection};
@ -26,6 +26,7 @@ use servo_url::ServoUrl;
use style_traits::CSSPixel;
use style_traits::cursor::CursorKind;
use style_traits::viewport::ViewportConstraints;
use webrender_api::{DeviceIntPoint, DeviceUintSize};
/// Messages from the layout to the constellation.
#[derive(Deserialize, Serialize)]
@ -136,11 +137,11 @@ pub enum ScriptMsg {
/// Send a key event
SendKeyEvent(Option<char>, Key, KeyState, KeyModifiers),
/// Get Window Informations size and position
GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>),
GetClientWindow(IpcSender<(DeviceUintSize, DeviceIntPoint)>),
/// Move the window to a point
MoveTo(Point2D<i32>),
MoveTo(DeviceIntPoint),
/// Resize the window to size
ResizeTo(Size2D<u32>),
ResizeTo(DeviceUintSize),
/// Script has handled a touch event, and either prevented or allowed default actions.
TouchEventProcessed(EventResult),
/// A log entry, with the top-level browsing context id and thread name
@ -155,9 +156,9 @@ pub enum ScriptMsg {
/// Enter or exit fullscreen
SetFullscreenState(bool),
/// Get the screen size (pixel)
GetScreenSize(IpcSender<(Size2D<u32>)>),
GetScreenSize(IpcSender<(DeviceUintSize)>),
/// Get the available screen size (pixel)
GetScreenAvailSize(IpcSender<(Size2D<u32>)>),
GetScreenAvailSize(IpcSender<(DeviceUintSize)>),
/// Requests that the compositor shut down.
Exit,
}

View File

@ -81,6 +81,7 @@ use constellation::{FromCompositorLogger, FromScriptLogger};
#[cfg(all(not(target_os = "windows"), not(target_os = "ios")))]
use constellation::content_process_sandbox_profile;
use env_logger::Logger as EnvLogger;
use euclid::Length;
#[cfg(all(not(target_os = "windows"), not(target_os = "ios")))]
use gaol::sandbox::{ChildSandbox, ChildSandboxMethods};
use gfx::font_cache_thread::FontCacheThread;
@ -133,7 +134,7 @@ impl<Window> Servo<Window> where Window: WindowMethods + 'static {
let opts = opts::get();
// Make sure the gl context is made current.
window.prepare_for_composite(0, 0);
window.prepare_for_composite(Length::new(0), Length::new(0));
// Get both endpoints of a special channel for communication between
// the client window and the compositor. This channel is unique because

View File

@ -27,7 +27,7 @@ extern crate webdriver;
mod keys;
use euclid::Size2D;
use euclid::TypedSize2D;
use hyper::method::Method::{self, Post};
use image::{DynamicImage, ImageFormat, RgbImage};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
@ -418,7 +418,7 @@ impl Handler {
Nullable::Value(v) => v,
Nullable::Null => 0,
};
let size = Size2D::new(width as u32, height as u32);
let size = TypedSize2D::new(width as u32, height as u32);
let top_level_browsing_context_id = self.session()?.top_level_browsing_context_id;
let cmd_msg = WebDriverCommandMsg::SetWindowSize(top_level_browsing_context_id, size, sender.clone());

View File

@ -41,7 +41,7 @@ function unsafe_pull_from_upstream() {
fi
# Update the manifest to include the new changes.
./mach update-manifest --release || return 3
./mach update-manifest || return 3
# Amend the existing commit with the new changes from updating the manifest.
git commit -a --amend --no-edit || return 4

View File

@ -7,7 +7,7 @@
use compositing::compositor_thread::EventLoopWaker;
use compositing::windowing::{AnimationState, MouseWindowEvent, WindowEvent};
use compositing::windowing::{WebRenderDebugOption, WindowMethods};
use euclid::{Point2D, Size2D, TypedPoint2D, TypedVector2D, TypedScale, TypedSize2D};
use euclid::{Length, TypedPoint2D, TypedVector2D, TypedScale, TypedSize2D};
#[cfg(target_os = "windows")]
use gdi32;
use gleam::gl;
@ -40,7 +40,7 @@ use style_traits::cursor::CursorKind;
use tinyfiledialogs;
#[cfg(target_os = "windows")]
use user32;
use webrender_api::{DeviceUintRect, DeviceUintSize, ScrollLocation};
use webrender_api::{DeviceIntPoint, DeviceUintRect, DeviceUintSize, ScrollLocation};
#[cfg(target_os = "windows")]
use winapi;
use winit;
@ -177,18 +177,18 @@ enum WindowKind {
/// The type of a window.
pub struct Window {
kind: WindowKind,
screen_size: Size2D<u32>,
screen_size: TypedSize2D<u32, DeviceIndependentPixel>,
inner_size: Cell<TypedSize2D<u32, DeviceIndependentPixel>>,
mouse_down_button: Cell<Option<winit::MouseButton>>,
mouse_down_point: Cell<Point2D<i32>>,
mouse_down_point: Cell<TypedPoint2D<i32, DeviceIndependentPixel>>,
event_queue: RefCell<Vec<WindowEvent>>,
/// id of the top level browsing context. It is unique as tabs
/// are not supported yet. None until created.
browser_id: Cell<Option<BrowserId>>,
mouse_pos: Cell<Point2D<i32>>,
mouse_pos: Cell<TypedPoint2D<i32, DeviceIndependentPixel>>,
key_modifiers: Cell<GlutinKeyModifiers>,
current_url: RefCell<Option<ServoUrl>>,
@ -222,9 +222,7 @@ impl Window {
pub fn new(is_foreground: bool,
window_size: TypedSize2D<u32, DeviceIndependentPixel>) -> Rc<Window> {
let win_size: TypedSize2D<u32, DevicePixel> =
(window_size.to_f32() * window_creation_scale_factor())
.to_usize().cast().expect("Window size should fit in u32");
let win_size: DeviceUintSize = (window_size.to_f32() * window_creation_scale_factor()).to_u32();
let width = win_size.to_untyped().width;
let height = win_size.to_untyped().height;
@ -237,7 +235,7 @@ impl Window {
let screen_size;
let inner_size;
let window_kind = if opts::get().headless {
screen_size = Size2D::new(width, height);
screen_size = TypedSize2D::new(width, height);
inner_size = TypedSize2D::new(width, height);
WindowKind::Headless(HeadlessContext::new(width, height))
} else {
@ -268,7 +266,7 @@ impl Window {
}
let (screen_width, screen_height) = events_loop.get_primary_monitor().get_dimensions();
screen_size = Size2D::new(screen_width, screen_height);
screen_size = TypedSize2D::new(screen_width, screen_height);
// TODO(ajeffrey): can this fail?
let (width, height) = glutin_window.get_inner_size().expect("Failed to get window inner size.");
inner_size = TypedSize2D::new(width, height);
@ -316,11 +314,11 @@ impl Window {
kind: window_kind,
event_queue: RefCell::new(vec!()),
mouse_down_button: Cell::new(None),
mouse_down_point: Cell::new(Point2D::new(0, 0)),
mouse_down_point: Cell::new(TypedPoint2D::new(0, 0)),
browser_id: Cell::new(None),
mouse_pos: Cell::new(Point2D::new(0, 0)),
mouse_pos: Cell::new(TypedPoint2D::new(0, 0)),
key_modifiers: Cell::new(GlutinKeyModifiers::empty()),
current_url: RefCell::new(None),
@ -422,8 +420,7 @@ impl Window {
}, ..
} => {
if button == MouseButton::Left || button == MouseButton::Right {
let mouse_pos = self.mouse_pos.get();
self.handle_mouse(button, state, mouse_pos.x, mouse_pos.y);
self.handle_mouse(button, state, self.mouse_pos.get());
}
},
Event::WindowEvent {
@ -433,7 +430,7 @@ impl Window {
},
..
} => {
self.mouse_pos.set(Point2D::new(x as i32, y as i32));
self.mouse_pos.set(TypedPoint2D::new(x as i32, y as i32));
self.event_queue.borrow_mut().push(
WindowEvent::MouseWindowMoveEventClass(TypedPoint2D::new(x as f32, y as f32)));
}
@ -481,7 +478,7 @@ impl Window {
}
// window.set_inner_size() takes DeviceIndependentPixel.
let new_size = TypedSize2D::new(width as f32, height as f32);
let new_size = (new_size / self.hidpi_factor()).cast().expect("Window size should fit in u32");
let new_size = (new_size / self.hidpi_factor()).to_u32();
if self.inner_size.get() != new_size {
self.inner_size.set(new_size);
self.event_queue.borrow_mut().push(WindowEvent::Resize);
@ -518,37 +515,37 @@ impl Window {
}
}
let mouse_pos = self.mouse_pos.get();
let event = WindowEvent::Scroll(scroll_location,
TypedPoint2D::new(mouse_pos.x as i32, mouse_pos.y as i32),
phase);
let pos = self.mouse_pos.get().to_f32() * self.hidpi_factor();
let event = WindowEvent::Scroll(scroll_location, pos.to_i32(), phase);
self.event_queue.borrow_mut().push(event);
}
/// Helper function to handle a click
fn handle_mouse(&self, button: winit::MouseButton, action: winit::ElementState, x: i32, y: i32) {
fn handle_mouse(&self, button: winit::MouseButton,
action: winit::ElementState,
coords: TypedPoint2D<i32, DeviceIndependentPixel>) {
use script_traits::MouseButton;
// FIXME(tkuehn): max pixel dist should be based on pixel density
let max_pixel_dist = 10f64;
let scaled_coords = coords.to_f32() * self.hidpi_factor();
let event = match action {
ElementState::Pressed => {
self.mouse_down_point.set(Point2D::new(x, y));
self.mouse_down_point.set(coords);
self.mouse_down_button.set(Some(button));
MouseWindowEvent::MouseDown(MouseButton::Left, TypedPoint2D::new(x as f32, y as f32))
MouseWindowEvent::MouseDown(MouseButton::Left, scaled_coords)
}
ElementState::Released => {
let mouse_up_event = MouseWindowEvent::MouseUp(MouseButton::Left,
TypedPoint2D::new(x as f32, y as f32));
let mouse_up_event = MouseWindowEvent::MouseUp(MouseButton::Left, scaled_coords);
match self.mouse_down_button.get() {
None => mouse_up_event,
Some(but) if button == but => {
let pixel_dist = self.mouse_down_point.get() - Point2D::new(x, y);
let pixel_dist = self.mouse_down_point.get() - coords;
let pixel_dist = ((pixel_dist.x * pixel_dist.x +
pixel_dist.y * pixel_dist.y) as f64).sqrt();
if pixel_dist < max_pixel_dist {
self.event_queue.borrow_mut().push(WindowEvent::MouseWindowEventClass(mouse_up_event));
MouseWindowEvent::Click(MouseButton::Left, TypedPoint2D::new(x as f32, y as f32))
MouseWindowEvent::Click(MouseButton::Left, scaled_coords)
} else {
mouse_up_event
}
@ -871,7 +868,7 @@ impl WindowMethods for Window {
}
fn framebuffer_size(&self) -> DeviceUintSize {
(self.inner_size.get().to_f32() * self.hidpi_factor()).to_usize().cast().expect("Window size should fit in u32")
(self.inner_size.get().to_f32() * self.hidpi_factor()).to_u32()
}
fn window_rect(&self) -> DeviceUintRect {
@ -880,34 +877,32 @@ impl WindowMethods for Window {
DeviceUintRect::new(origin, size)
}
fn size(&self) -> TypedSize2D<f32, DeviceIndependentPixel> {
self.inner_size.get().to_f32()
}
fn client_window(&self, _: BrowserId) -> (Size2D<u32>, Point2D<i32>) {
match self.kind {
fn client_window(&self, _: BrowserId) -> (DeviceUintSize, DeviceIntPoint) {
let (size, point) = match self.kind {
WindowKind::Window(ref window, ..) => {
// TODO(ajeffrey): can this fail?
let (width, height) = window.get_outer_size().expect("Failed to get window outer size.");
let size = Size2D::new(width, height);
let size = TypedSize2D::new(width as f32, height as f32);
// TODO(ajeffrey): can this fail?
let (x, y) = window.get_position().expect("Failed to get window position.");
let origin = Point2D::new(x as i32, y as i32);
let origin = TypedPoint2D::new(x as f32, y as f32);
(size, origin)
}
WindowKind::Headless(ref context) => {
let size = TypedSize2D::new(context.width, context.height);
(size, Point2D::zero())
let size = TypedSize2D::new(context.width as f32, context.height as f32);
let origin = TypedPoint2D::zero();
(size, origin)
}
}
};
let dpr = self.hidpi_factor();
((size * dpr).to_u32(), (point * dpr).to_i32())
}
fn screen_size(&self, _: BrowserId) -> Size2D<u32> {
self.screen_size
fn screen_size(&self, _: BrowserId) -> DeviceUintSize {
(self.screen_size.to_f32() * self.hidpi_factor()).to_u32()
}
fn screen_avail_size(&self, browser_id: BrowserId) -> Size2D<u32> {
fn screen_avail_size(&self, browser_id: BrowserId) -> DeviceUintSize {
// FIXME: Glutin doesn't have API for available size. Fallback to screen size
self.screen_size(browser_id)
}
@ -916,19 +911,21 @@ impl WindowMethods for Window {
self.animation_state.set(state);
}
fn set_inner_size(&self, _: BrowserId, size: Size2D<u32>) {
fn set_inner_size(&self, _: BrowserId, size: DeviceUintSize) {
match self.kind {
WindowKind::Window(ref window, ..) => {
let size = size.to_f32() / self.hidpi_factor();
window.set_inner_size(size.width as u32, size.height as u32)
}
WindowKind::Headless(..) => {}
}
}
fn set_position(&self, _: BrowserId, point: Point2D<i32>) {
fn set_position(&self, _: BrowserId, point: DeviceIntPoint) {
match self.kind {
WindowKind::Window(ref window, ..) => {
window.set_position(point.x, point.y)
let point = point.to_f32() / self.hidpi_factor();
window.set_position(point.x as i32, point.y as i32)
}
WindowKind::Headless(..) => {}
}
@ -1112,7 +1109,7 @@ impl WindowMethods for Window {
fn set_favicon(&self, _: BrowserId, _: ServoUrl) {
}
fn prepare_for_composite(&self, _width: usize, _height: usize) -> bool {
fn prepare_for_composite(&self, _width: Length<u32, DevicePixel>, _height: Length<u32, DevicePixel>) -> bool {
true
}

View File

@ -1,6 +1,8 @@
component {66354bc9-7ed1-4692-ae1d-8da97d6b205e} nsBlocklistService.js process=main
contract @mozilla.org/extensions/blocklist;1 {66354bc9-7ed1-4692-ae1d-8da97d6b205e} process=main
category profile-after-change nsBlocklistService @mozilla.org/extensions/blocklist;1 process=main
#ifndef MOZ_BUILD_APP_IS_BROWSER
category profile-after-change nsBlocklistService @mozilla.org/extensions/blocklist;1 process=main
#endif
category update-timer nsBlocklistService @mozilla.org/extensions/blocklist;1,getService,blocklist-background-update-timer,extensions.blocklist.interval,86400
component {4399533d-08d1-458c-a87a-235f74451cfa} addonManager.js

View File

@ -9,6 +9,9 @@ SPHINX_TREES['addon-manager'] = 'docs'
with Files('docs/**'):
SCHEDULES.exclusive = ['docs']
if CONFIG['MOZ_BUILD_APP'] == 'browser':
DEFINES['MOZ_BUILD_APP_IS_BROWSER'] = True
if CONFIG['MOZ_BUILD_APP'] == 'mobile/android':
DEFINES['MOZ_FENNEC'] = True

View File

@ -221,7 +221,6 @@ function parseRegExp(aStr) {
function Blocklist() {
Services.obs.addObserver(this, "xpcom-shutdown");
Services.obs.addObserver(this, "sessionstore-windows-restored");
gLoggingEnabled = Services.prefs.getBoolPref(PREF_EM_LOGGING_ENABLED, false);
gBlocklistEnabled = Services.prefs.getBoolPref(PREF_BLOCKLIST_ENABLED, true);
gBlocklistLevel = Math.min(Services.prefs.getIntPref(PREF_BLOCKLIST_LEVEL, DEFAULT_LEVEL),
@ -229,8 +228,6 @@ function Blocklist() {
Services.prefs.addObserver("extensions.blocklist.", this);
Services.prefs.addObserver(PREF_EM_LOGGING_ENABLED, this);
this.wrappedJSObject = this;
// requests from child processes come in here, see receiveMessage.
Services.ppmm.addMessageListener("Blocklist:content-blocklist-updated", this);
}
Blocklist.prototype = {
@ -255,7 +252,6 @@ Blocklist.prototype = {
shutdown() {
Services.obs.removeObserver(this, "xpcom-shutdown");
Services.ppmm.removeMessageListener("Blocklist:content-blocklist-updated", this);
Services.prefs.removeObserver("extensions.blocklist.", this);
Services.prefs.removeObserver(PREF_EM_LOGGING_ENABLED, this);
},
@ -265,6 +261,12 @@ Blocklist.prototype = {
case "xpcom-shutdown":
this.shutdown();
break;
case "profile-after-change":
// We're only called here on non-Desktop-Firefox, and use this opportunity to try to
// load the blocklist asynchronously. On desktop Firefox, we load the list from
// nsBrowserGlue after sessionstore-windows-restored.
this.loadBlocklistAsync();
break;
case "nsPref:changed":
switch (aData) {
case PREF_EM_LOGGING_ENABLED:
@ -282,25 +284,9 @@ Blocklist.prototype = {
break;
}
break;
case "sessionstore-windows-restored":
Services.obs.removeObserver(this, "sessionstore-windows-restored");
this._preloadBlocklist();
break;
}
},
// Message manager message handlers
receiveMessage(aMsg) {
switch (aMsg.name) {
case "Blocklist:content-blocklist-updated":
Services.obs.notifyObservers(null, "content-blocklist-updated");
break;
default:
throw new Error("Unknown blocklist message received from content: " + aMsg.name);
}
return undefined;
},
/* See nsIBlocklistService */
isAddonBlocklisted(addon, appVersion, toolkitVersion) {
return this.getAddonBlocklistState(addon, appVersion, toolkitVersion) ==
@ -797,13 +783,13 @@ Blocklist.prototype = {
this._pluginEntries = null;
},
async _preloadBlocklist() {
async loadBlocklistAsync() {
let profPath = OS.Path.join(OS.Constants.Path.profileDir, FILE_BLOCKLIST);
try {
await this._preloadBlocklistFile(profPath);
return;
} catch (e) {
LOG("Blocklist::_preloadBlocklist: Failed to load XML file " + e);
LOG("Blocklist::loadBlocklistAsync: Failed to load XML file " + e);
}
var appFile = FileUtils.getFile(KEY_APPDIR, [FILE_BLOCKLIST]);
@ -811,10 +797,10 @@ Blocklist.prototype = {
await this._preloadBlocklistFile(appFile.path);
return;
} catch (e) {
LOG("Blocklist::_preloadBlocklist: Failed to load XML file " + e);
LOG("Blocklist::loadBlocklistAsync: Failed to load XML file " + e);
}
LOG("Blocklist::_preloadBlocklist: no XML File found");
LOG("Blocklist::loadBlocklistAsync: no XML File found");
},
async _preloadBlocklistFile(path) {

View File

@ -14,7 +14,7 @@ add_task(async function() {
scope.OS.File.read = () => triedToRead = true;
blocklist._loadBlocklist();
Assert.ok(blocklist.isLoaded);
await blocklist._preloadBlocklist();
await blocklist.loadBlocklistAsync();
Assert.ok(!triedToRead);
scope.OS.File.read = read;
blocklist._clear();
@ -22,7 +22,7 @@ add_task(async function() {
info("sync -> async complete");
// async first. Check that once we preload the content, that is sufficient.
await blocklist._preloadBlocklist();
await blocklist.loadBlocklistAsync();
Assert.ok(blocklist.isLoaded);
// Calling _loadBlocklist now would just re-load the list sync.
@ -40,7 +40,7 @@ add_task(async function() {
});
};
await blocklist._preloadBlocklist();
await blocklist.loadBlocklistAsync();
// We're mostly just checking this doesn't error out.
Assert.ok(blocklist.isLoaded);
info("mixed async/sync test complete");

View File

@ -131,6 +131,7 @@ def run_process(config, cmd):
proc.wait()
except KeyboardInterrupt:
proc.kill()
return 1
def setup(root):
@ -163,6 +164,7 @@ def lint(paths, config, **lintargs):
cmd.extend(['--append-config={}'.format(c) for c in configs])
cmd.extend(paths)
run_process(config, cmd)
if run_process(config, cmd):
break
return results

View File

@ -21,7 +21,6 @@
#include "nsIDOMElement.h"
#include "nsIDOMEvent.h"
#include "nsIDOMEventTarget.h"
#include "nsIDOMFileList.h"
#include "nsIDOMFocusEvent.h"
#include "nsIDOMGeoPositionError.h"
#include "nsIDOMHTMLInputElement.h"
@ -67,7 +66,6 @@
#include "mozilla/dom/ElementBinding.h"
#include "mozilla/dom/EventBinding.h"
#include "mozilla/dom/EventTargetBinding.h"
#include "mozilla/dom/FileListBinding.h"
#include "mozilla/dom/FocusEventBinding.h"
#include "mozilla/dom/FrameLoaderBinding.h"
#include "mozilla/dom/HTMLAnchorElementBinding.h"
@ -176,7 +174,6 @@ const ComponentsInterfaceShimEntry kComponentsInterfaceShimMap[] =
DEFINE_SHIM(Element),
DEFINE_SHIM(Event),
DEFINE_SHIM(EventTarget),
DEFINE_SHIM(FileList),
DEFINE_SHIM(FocusEvent),
DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIFrameLoader, FrameLoader),
DEFINE_SHIM_WITH_CUSTOM_INTERFACE(nsIDOMGeoPositionError, PositionError),

View File

@ -133,6 +133,11 @@ interface nsIBlocklistService : nsISupports
* Whether or not we've finished loading the blocklist.
*/
readonly attribute boolean isLoaded;
/**
* Trigger loading the blocklist content asynchronously.
*/
void loadBlocklistAsync();
};
/**