mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 01:48:05 +00:00
Merge autoland to mozilla-central. a=merge
This commit is contained in:
commit
37bdf96634
@ -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;
|
||||
|
||||
|
@ -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),
|
||||
});
|
||||
},
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
9
browser/base/content/test/about/dummy_page.html
Normal file
9
browser/base/content/test/about/dummy_page.html
Normal 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>
|
@ -1212,6 +1212,10 @@ BrowserGlue.prototype = {
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
LanguagePrompt.init();
|
||||
});
|
||||
|
||||
Services.tm.idleDispatchToMainThread(() => {
|
||||
Services.blocklist.loadBlocklistAsync();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -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.
|
||||
|
@ -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) => ({
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
@ -145,7 +145,6 @@
|
||||
#include "nsQueryObject.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCSSProps.h"
|
||||
#include "nsIDOMFileList.h"
|
||||
#include "nsIURIFixup.h"
|
||||
#ifndef DEBUG
|
||||
#include "nsIAppStartup.h"
|
||||
|
@ -144,7 +144,6 @@
|
||||
#include "nsQueryObject.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCSSProps.h"
|
||||
#include "nsIDOMFileList.h"
|
||||
#include "nsIURIFixup.h"
|
||||
#include "nsIURIMutator.h"
|
||||
#ifndef DEBUG
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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)
|
||||
{}
|
||||
|
@ -11,7 +11,6 @@ DIRS += ['ipc']
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIDOMBlob.idl',
|
||||
'nsIDOMFileList.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'dom_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);
|
||||
};
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -5,9 +5,6 @@
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
interface nsIControllers;
|
||||
interface nsIDOMFileList;
|
||||
|
||||
/**
|
||||
* The nsIDOMHTMLInputElement interface is the interface to a [X]HTML
|
||||
* input element.
|
||||
|
@ -33,7 +33,6 @@
|
||||
|
||||
#include "nsIBFCacheEntry.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDOMFileList.h"
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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: {
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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):
|
||||
|
8
python/mozlint/test/linters/slow.yml
Normal file
8
python/mozlint/test/linters/slow.yml
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
SlowLinter:
|
||||
description: A linter that takes awhile to run
|
||||
include:
|
||||
- files
|
||||
type: external
|
||||
extensions: ['.js', '.jsm']
|
||||
payload: external:slow
|
20
python/mozlint/test/runcli.py
Normal file
20
python/mozlint/test/runcli.py
Normal 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))
|
@ -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):
|
||||
|
@ -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
1
servo/Cargo.lock
generated
@ -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)",
|
||||
]
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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" }
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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>>),
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user