зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
17a7053b0d
|
@ -0,0 +1,377 @@
|
|||
// The following parameters are parsed from the error URL:
|
||||
// e - the error code
|
||||
// s - custom CSS class to allow alternate styling/favicons
|
||||
// d - error description
|
||||
// captive - "true" to indicate we're behind a captive portal.
|
||||
// Any other value is ignored.
|
||||
|
||||
// Note that this file uses document.documentURI to get
|
||||
// the URL (with the format from above). This is because
|
||||
// document.location.href gets the current URI off the docshell,
|
||||
// which is the URL displayed in the location bar, i.e.
|
||||
// the URI that the user attempted to load.
|
||||
|
||||
let searchParams = new URLSearchParams(document.documentURI.split("?")[1]);
|
||||
|
||||
// Set to true on init if the error code is nssBadCert.
|
||||
let gIsCertError;
|
||||
|
||||
function getErrorCode() {
|
||||
return searchParams.get("e");
|
||||
}
|
||||
|
||||
function getCSSClass() {
|
||||
return searchParams.get("s");
|
||||
}
|
||||
|
||||
function getDescription() {
|
||||
return searchParams.get("d");
|
||||
}
|
||||
|
||||
function isCaptive() {
|
||||
return searchParams.get("captive") == "true";
|
||||
}
|
||||
|
||||
function retryThis(buttonEl) {
|
||||
// Note: The application may wish to handle switching off "offline mode"
|
||||
// before this event handler runs, but using a capturing event handler.
|
||||
|
||||
// Session history has the URL of the page that failed
|
||||
// to load, not the one of the error page. So, just call
|
||||
// reload(), which will also repost POST data correctly.
|
||||
try {
|
||||
location.reload();
|
||||
} catch (e) {
|
||||
// We probably tried to reload a URI that caused an exception to
|
||||
// occur; e.g. a nonexistent file.
|
||||
}
|
||||
|
||||
buttonEl.disabled = true;
|
||||
}
|
||||
|
||||
function toggleDisplay(node) {
|
||||
const toggle = {
|
||||
"": "block",
|
||||
"none": "block",
|
||||
"block": "none"
|
||||
};
|
||||
return (node.style.display = toggle[node.style.display]);
|
||||
}
|
||||
|
||||
function showCertificateErrorReporting() {
|
||||
// Display error reporting UI
|
||||
document.getElementById("certificateErrorReporting").style.display = "block";
|
||||
}
|
||||
|
||||
function showPrefChangeContainer() {
|
||||
const panel = document.getElementById("prefChangeContainer");
|
||||
panel.style.display = "block";
|
||||
document.getElementById("netErrorButtonContainer").style.display = "none";
|
||||
document.getElementById("prefResetButton").addEventListener("click", function resetPreferences(e) {
|
||||
const event = new CustomEvent("AboutNetErrorResetPreferences", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
addAutofocus("prefResetButton", "beforeend");
|
||||
}
|
||||
|
||||
function setupAdvancedButton() {
|
||||
// Get the hostname and add it to the panel
|
||||
var panel = document.getElementById("badCertAdvancedPanel");
|
||||
for (var span of panel.querySelectorAll("span.hostname")) {
|
||||
span.textContent = document.location.hostname;
|
||||
}
|
||||
|
||||
// Register click handler for the weakCryptoAdvancedPanel
|
||||
document.getElementById("advancedButton")
|
||||
.addEventListener("click", function togglePanelVisibility() {
|
||||
toggleDisplay(panel);
|
||||
if (gIsCertError) {
|
||||
// Toggling the advanced panel must ensure that the debugging
|
||||
// information panel is hidden as well, since it's opened by the
|
||||
// error code link in the advanced panel.
|
||||
var div = document.getElementById("certificateErrorDebugInformation");
|
||||
div.style.display = "none";
|
||||
}
|
||||
|
||||
if (panel.style.display == "block") {
|
||||
// send event to trigger telemetry ping
|
||||
var event = new CustomEvent("AboutNetErrorUIExpanded", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
});
|
||||
|
||||
if (!gIsCertError) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getCSSClass() == "expertBadCert") {
|
||||
toggleDisplay(document.getElementById("badCertAdvancedPanel"));
|
||||
// Toggling the advanced panel must ensure that the debugging
|
||||
// information panel is hidden as well, since it's opened by the
|
||||
// error code link in the advanced panel.
|
||||
var div = document.getElementById("certificateErrorDebugInformation");
|
||||
div.style.display = "none";
|
||||
}
|
||||
|
||||
disallowCertOverridesIfNeeded();
|
||||
}
|
||||
|
||||
function disallowCertOverridesIfNeeded() {
|
||||
var cssClass = getCSSClass();
|
||||
// Disallow overrides if this is a Strict-Transport-Security
|
||||
// host and the cert is bad (STS Spec section 7.3) or if the
|
||||
// certerror is in a frame (bug 633691).
|
||||
if (cssClass == "badStsCert" || window != top) {
|
||||
document.getElementById("exceptionDialogButton").setAttribute("hidden", "true");
|
||||
}
|
||||
if (cssClass == "badStsCert") {
|
||||
document.getElementById("badStsCertExplanation").removeAttribute("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function initPage() {
|
||||
var err = getErrorCode();
|
||||
// List of error pages with an illustration.
|
||||
let illustratedErrors = [
|
||||
"malformedURI", "dnsNotFound", "connectionFailure", "netInterrupt",
|
||||
"netTimeout", "netReset", "netOffline",
|
||||
];
|
||||
if (illustratedErrors.includes(err)) {
|
||||
document.body.classList.add("illustrated", err);
|
||||
}
|
||||
if (err == "blockedByPolicy") {
|
||||
document.body.classList.add("blocked");
|
||||
}
|
||||
|
||||
gIsCertError = (err == "nssBadCert");
|
||||
// Only worry about captive portals if this is a cert error.
|
||||
let showCaptivePortalUI = isCaptive() && gIsCertError;
|
||||
if (showCaptivePortalUI) {
|
||||
err = "captivePortal";
|
||||
}
|
||||
|
||||
let pageTitle = document.getElementById("ept_" + err);
|
||||
if (pageTitle) {
|
||||
document.title = pageTitle.textContent;
|
||||
}
|
||||
|
||||
// if it's an unknown error or there's no title or description
|
||||
// defined, get the generic message
|
||||
var errTitle = document.getElementById("et_" + err);
|
||||
var errDesc = document.getElementById("ed_" + err);
|
||||
if (!errTitle || !errDesc) {
|
||||
errTitle = document.getElementById("et_generic");
|
||||
errDesc = document.getElementById("ed_generic");
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
document.querySelector(".title-text").innerHTML = errTitle.innerHTML;
|
||||
|
||||
var sd = document.getElementById("errorShortDescText");
|
||||
if (sd) {
|
||||
if (gIsCertError) {
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
sd.innerHTML = errDesc.innerHTML;
|
||||
} else {
|
||||
sd.textContent = getDescription();
|
||||
}
|
||||
}
|
||||
if (showCaptivePortalUI) {
|
||||
initPageCaptivePortal();
|
||||
return;
|
||||
}
|
||||
if (gIsCertError) {
|
||||
initPageCertError();
|
||||
return;
|
||||
}
|
||||
addAutofocus("errorTryAgain");
|
||||
|
||||
document.body.classList.add("neterror");
|
||||
|
||||
var ld = document.getElementById("errorLongDesc");
|
||||
if (ld) {
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
ld.innerHTML = errDesc.innerHTML;
|
||||
}
|
||||
|
||||
if (err == "sslv3Used") {
|
||||
document.getElementById("learnMoreContainer").style.display = "block";
|
||||
let learnMoreLink = document.getElementById("learnMoreLink");
|
||||
learnMoreLink.href = "https://support.mozilla.org/kb/how-resolve-sslv3-error-messages-firefox";
|
||||
document.body.className = "certerror";
|
||||
}
|
||||
|
||||
// remove undisplayed errors to avoid bug 39098
|
||||
var errContainer = document.getElementById("errorContainer");
|
||||
errContainer.remove();
|
||||
|
||||
var className = getCSSClass();
|
||||
if (className && className != "expertBadCert") {
|
||||
// Associate a CSS class with the root of the page, if one was passed in,
|
||||
// to allow custom styling.
|
||||
// Not "expertBadCert" though, don't want to deal with the favicon
|
||||
document.documentElement.className = className;
|
||||
|
||||
// Also, if they specified a CSS class, they must supply their own
|
||||
// favicon. In order to trigger the browser to repaint though, we
|
||||
// need to remove/add the link element.
|
||||
var favicon = document.getElementById("favicon");
|
||||
var faviconParent = favicon.parentNode;
|
||||
faviconParent.removeChild(favicon);
|
||||
favicon.setAttribute("href", "chrome://global/skin/icons/" + className + "_favicon.png");
|
||||
faviconParent.appendChild(favicon);
|
||||
}
|
||||
|
||||
if (err == "remoteXUL") {
|
||||
// Remove the "Try again" button for remote XUL errors given that
|
||||
// it is useless.
|
||||
document.getElementById("netErrorButtonContainer").style.display = "none";
|
||||
}
|
||||
|
||||
if (err == "cspBlocked") {
|
||||
// Remove the "Try again" button for CSP violations, since it's
|
||||
// almost certainly useless. (Bug 553180)
|
||||
document.getElementById("netErrorButtonContainer").style.display = "none";
|
||||
}
|
||||
|
||||
window.addEventListener("AboutNetErrorOptions", function(evt) {
|
||||
// Pinning errors are of type nssFailure2
|
||||
if (getErrorCode() == "nssFailure2") {
|
||||
let shortDesc = document.getElementById("errorShortDescText").textContent;
|
||||
document.getElementById("learnMoreContainer").style.display = "block";
|
||||
let learnMoreLink = document.getElementById("learnMoreLink");
|
||||
// nssFailure2 also gets us other non-overrideable errors. Choose
|
||||
// a "learn more" link based on description:
|
||||
if (shortDesc.includes("MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE")) {
|
||||
learnMoreLink.href = "https://support.mozilla.org/kb/certificate-pinning-reports";
|
||||
}
|
||||
|
||||
var options = JSON.parse(evt.detail);
|
||||
if (options && options.enabled) {
|
||||
var checkbox = document.getElementById("automaticallyReportInFuture");
|
||||
showCertificateErrorReporting();
|
||||
if (options.automatic) {
|
||||
// set the checkbox
|
||||
checkbox.checked = true;
|
||||
}
|
||||
|
||||
checkbox.addEventListener("change", function(changeEvt) {
|
||||
var event = new CustomEvent("AboutNetErrorSetAutomatic",
|
||||
{bubbles: true,
|
||||
detail: changeEvt.target.checked});
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
}
|
||||
const hasPrefStyleError = [
|
||||
"interrupted", // This happens with subresources that are above the max tls
|
||||
"SSL_ERROR_PROTOCOL_VERSION_ALERT",
|
||||
"SSL_ERROR_UNSUPPORTED_VERSION",
|
||||
"SSL_ERROR_NO_CYPHER_OVERLAP",
|
||||
"SSL_ERROR_NO_CIPHERS_SUPPORTED"
|
||||
].some((substring) => shortDesc.includes(substring));
|
||||
// If it looks like an error that is user config based
|
||||
if (getErrorCode() == "nssFailure2" && hasPrefStyleError && options && options.changedCertPrefs) {
|
||||
showPrefChangeContainer();
|
||||
}
|
||||
}
|
||||
if (getErrorCode() == "sslv3Used") {
|
||||
document.getElementById("advancedButton").style.display = "none";
|
||||
}
|
||||
}, true, true);
|
||||
|
||||
var event = new CustomEvent("AboutNetErrorLoad", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
|
||||
if (err == "inadequateSecurityError" || err == "blockedByPolicy") {
|
||||
// Remove the "Try again" button from pages that don't need it.
|
||||
// For HTTP/2 inadequate security or pages blocked by policy, trying
|
||||
// again won't help.
|
||||
document.getElementById("errorTryAgain").style.display = "none";
|
||||
|
||||
var container = document.getElementById("errorLongDesc");
|
||||
for (var span of container.querySelectorAll("span.hostname")) {
|
||||
span.textContent = document.location.hostname;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initPageCaptivePortal() {
|
||||
document.body.className = "captiveportal";
|
||||
document.getElementById("openPortalLoginPageButton")
|
||||
.addEventListener("click", () => {
|
||||
let event = new CustomEvent("AboutNetErrorOpenCaptivePortal", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
|
||||
addAutofocus("openPortalLoginPageButton");
|
||||
setupAdvancedButton();
|
||||
|
||||
// When the portal is freed, an event is generated by the frame script
|
||||
// that we can pick up and attempt to reload the original page.
|
||||
window.addEventListener("AboutNetErrorCaptivePortalFreed", () => {
|
||||
document.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
function initPageCertError() {
|
||||
document.body.className = "certerror";
|
||||
for (let host of document.querySelectorAll(".hostname")) {
|
||||
host.textContent = document.location.hostname;
|
||||
}
|
||||
|
||||
addAutofocus("returnButton");
|
||||
setupAdvancedButton();
|
||||
|
||||
document.getElementById("learnMoreContainer").style.display = "block";
|
||||
|
||||
let checkbox = document.getElementById("automaticallyReportInFuture");
|
||||
checkbox.addEventListener("change", function({target: {checked}}) {
|
||||
document.dispatchEvent(new CustomEvent("AboutNetErrorSetAutomatic", {
|
||||
detail: checked,
|
||||
bubbles: true
|
||||
}));
|
||||
});
|
||||
|
||||
addEventListener("AboutNetErrorOptions", function(event) {
|
||||
var options = JSON.parse(event.detail);
|
||||
if (options && options.enabled) {
|
||||
// Display error reporting UI
|
||||
document.getElementById("certificateErrorReporting").style.display = "block";
|
||||
|
||||
// set the checkbox
|
||||
checkbox.checked = !!options.automatic;
|
||||
}
|
||||
if (options && options.hideAddExceptionButton) {
|
||||
document.querySelector(".exceptionDialogButtonContainer").hidden = true;
|
||||
}
|
||||
}, true, true);
|
||||
|
||||
let event = new CustomEvent("AboutNetErrorLoad", {bubbles: true});
|
||||
document.getElementById("advancedButton").dispatchEvent(event);
|
||||
}
|
||||
|
||||
/* Only do autofocus if we're the toplevel frame; otherwise we
|
||||
don't want to call attention to ourselves! The key part is
|
||||
that autofocus happens on insertion into the tree, so we
|
||||
can remove the button, add @autofocus, and reinsert the
|
||||
button.
|
||||
*/
|
||||
function addAutofocus(buttonId, position = "afterbegin") {
|
||||
if (window.top == window) {
|
||||
var button = document.getElementById(buttonId);
|
||||
var parent = button.parentNode;
|
||||
button.remove();
|
||||
button.setAttribute("autofocus", "true");
|
||||
parent.insertAdjacentElement(position, button);
|
||||
}
|
||||
}
|
||||
|
||||
let errorTryAgain = document.getElementById("errorTryAgain");
|
||||
errorTryAgain.addEventListener("click", function() {
|
||||
retryThis(this);
|
||||
});
|
||||
|
||||
// Note: It is important to run the script this way, instead of using
|
||||
// an onload handler. This is because error pages are loaded as
|
||||
// LOAD_BACKGROUND, which means that onload handlers will not be executed.
|
||||
initPage();
|
|
@ -19,382 +19,12 @@
|
|||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src chrome:" />
|
||||
<title>&loadError.label;</title>
|
||||
<link rel="stylesheet" href="chrome://browser/skin/aboutNetError.css" type="text/css" media="all" />
|
||||
<!-- If the location of the favicon is changed here, the FAVICON_ERRORPAGE_URL symbol in
|
||||
toolkit/components/places/src/nsFaviconService.h should be updated. -->
|
||||
<link rel="icon" type="image/png" id="favicon" href="chrome://global/skin/icons/warning-16.png"/>
|
||||
|
||||
<script type="application/javascript"><![CDATA[
|
||||
// The following parameters are parsed from the error URL:
|
||||
// e - the error code
|
||||
// s - custom CSS class to allow alternate styling/favicons
|
||||
// d - error description
|
||||
// captive - "true" to indicate we're behind a captive portal.
|
||||
// Any other value is ignored.
|
||||
|
||||
// Note that this file uses document.documentURI to get
|
||||
// the URL (with the format from above). This is because
|
||||
// document.location.href gets the current URI off the docshell,
|
||||
// which is the URL displayed in the location bar, i.e.
|
||||
// the URI that the user attempted to load.
|
||||
|
||||
let searchParams = new URLSearchParams(document.documentURI.split("?")[1]);
|
||||
|
||||
// Set to true on init if the error code is nssBadCert.
|
||||
let gIsCertError;
|
||||
|
||||
function getErrorCode() {
|
||||
return searchParams.get("e");
|
||||
}
|
||||
|
||||
function getCSSClass() {
|
||||
return searchParams.get("s");
|
||||
}
|
||||
|
||||
function getDescription() {
|
||||
return searchParams.get("d");
|
||||
}
|
||||
|
||||
function isCaptive() {
|
||||
return searchParams.get("captive") == "true";
|
||||
}
|
||||
|
||||
function retryThis(buttonEl) {
|
||||
// Note: The application may wish to handle switching off "offline mode"
|
||||
// before this event handler runs, but using a capturing event handler.
|
||||
|
||||
// Session history has the URL of the page that failed
|
||||
// to load, not the one of the error page. So, just call
|
||||
// reload(), which will also repost POST data correctly.
|
||||
try {
|
||||
location.reload();
|
||||
} catch (e) {
|
||||
// We probably tried to reload a URI that caused an exception to
|
||||
// occur; e.g. a nonexistent file.
|
||||
}
|
||||
|
||||
buttonEl.disabled = true;
|
||||
}
|
||||
|
||||
function toggleDisplay(node) {
|
||||
const toggle = {
|
||||
"": "block",
|
||||
"none": "block",
|
||||
"block": "none"
|
||||
};
|
||||
return (node.style.display = toggle[node.style.display]);
|
||||
}
|
||||
|
||||
function showCertificateErrorReporting() {
|
||||
// Display error reporting UI
|
||||
document.getElementById("certificateErrorReporting").style.display = "block";
|
||||
}
|
||||
|
||||
function showPrefChangeContainer() {
|
||||
const panel = document.getElementById("prefChangeContainer");
|
||||
panel.style.display = "block";
|
||||
document.getElementById("netErrorButtonContainer").style.display = "none";
|
||||
document.getElementById("prefResetButton").addEventListener("click", function resetPreferences(e) {
|
||||
const event = new CustomEvent("AboutNetErrorResetPreferences", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
addAutofocus("prefResetButton", "beforeend");
|
||||
}
|
||||
|
||||
function setupAdvancedButton() {
|
||||
// Get the hostname and add it to the panel
|
||||
var panel = document.getElementById("badCertAdvancedPanel");
|
||||
for (var span of panel.querySelectorAll("span.hostname")) {
|
||||
span.textContent = document.location.hostname;
|
||||
}
|
||||
|
||||
// Register click handler for the weakCryptoAdvancedPanel
|
||||
document.getElementById("advancedButton")
|
||||
.addEventListener("click", function togglePanelVisibility() {
|
||||
toggleDisplay(panel);
|
||||
if (gIsCertError) {
|
||||
// Toggling the advanced panel must ensure that the debugging
|
||||
// information panel is hidden as well, since it's opened by the
|
||||
// error code link in the advanced panel.
|
||||
var div = document.getElementById("certificateErrorDebugInformation");
|
||||
div.style.display = "none";
|
||||
}
|
||||
|
||||
if (panel.style.display == "block") {
|
||||
// send event to trigger telemetry ping
|
||||
var event = new CustomEvent("AboutNetErrorUIExpanded", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
}
|
||||
});
|
||||
|
||||
if (!gIsCertError) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (getCSSClass() == "expertBadCert") {
|
||||
toggleDisplay(document.getElementById("badCertAdvancedPanel"));
|
||||
// Toggling the advanced panel must ensure that the debugging
|
||||
// information panel is hidden as well, since it's opened by the
|
||||
// error code link in the advanced panel.
|
||||
var div = document.getElementById("certificateErrorDebugInformation");
|
||||
div.style.display = "none";
|
||||
}
|
||||
|
||||
disallowCertOverridesIfNeeded();
|
||||
}
|
||||
|
||||
function disallowCertOverridesIfNeeded() {
|
||||
var cssClass = getCSSClass();
|
||||
// Disallow overrides if this is a Strict-Transport-Security
|
||||
// host and the cert is bad (STS Spec section 7.3) or if the
|
||||
// certerror is in a frame (bug 633691).
|
||||
if (cssClass == "badStsCert" || window != top) {
|
||||
document.getElementById("exceptionDialogButton").setAttribute("hidden", "true");
|
||||
}
|
||||
if (cssClass == "badStsCert") {
|
||||
document.getElementById("badStsCertExplanation").removeAttribute("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function initPage() {
|
||||
var err = getErrorCode();
|
||||
// List of error pages with an illustration.
|
||||
let illustratedErrors = [
|
||||
"malformedURI", "dnsNotFound", "connectionFailure", "netInterrupt",
|
||||
"netTimeout", "netReset", "netOffline",
|
||||
];
|
||||
if (illustratedErrors.includes(err)) {
|
||||
document.body.classList.add("illustrated", err);
|
||||
}
|
||||
if (err == "blockedByPolicy") {
|
||||
document.body.classList.add("blocked");
|
||||
}
|
||||
|
||||
gIsCertError = (err == "nssBadCert");
|
||||
// Only worry about captive portals if this is a cert error.
|
||||
let showCaptivePortalUI = isCaptive() && gIsCertError;
|
||||
if (showCaptivePortalUI) {
|
||||
err = "captivePortal";
|
||||
}
|
||||
|
||||
let pageTitle = document.getElementById("ept_" + err);
|
||||
if (pageTitle) {
|
||||
document.title = pageTitle.textContent;
|
||||
}
|
||||
|
||||
// if it's an unknown error or there's no title or description
|
||||
// defined, get the generic message
|
||||
var errTitle = document.getElementById("et_" + err);
|
||||
var errDesc = document.getElementById("ed_" + err);
|
||||
if (!errTitle || !errDesc) {
|
||||
errTitle = document.getElementById("et_generic");
|
||||
errDesc = document.getElementById("ed_generic");
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
document.querySelector(".title-text").innerHTML = errTitle.innerHTML;
|
||||
|
||||
var sd = document.getElementById("errorShortDescText");
|
||||
if (sd) {
|
||||
if (gIsCertError) {
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
sd.innerHTML = errDesc.innerHTML;
|
||||
} else {
|
||||
sd.textContent = getDescription();
|
||||
}
|
||||
}
|
||||
if (showCaptivePortalUI) {
|
||||
initPageCaptivePortal();
|
||||
return;
|
||||
}
|
||||
if (gIsCertError) {
|
||||
initPageCertError();
|
||||
return;
|
||||
}
|
||||
addAutofocus("errorTryAgain");
|
||||
|
||||
document.body.classList.add("neterror");
|
||||
|
||||
var ld = document.getElementById("errorLongDesc");
|
||||
if (ld) {
|
||||
// eslint-disable-next-line no-unsanitized/property
|
||||
ld.innerHTML = errDesc.innerHTML;
|
||||
}
|
||||
|
||||
if (err == "sslv3Used") {
|
||||
document.getElementById("learnMoreContainer").style.display = "block";
|
||||
let learnMoreLink = document.getElementById("learnMoreLink");
|
||||
learnMoreLink.href = "https://support.mozilla.org/kb/how-resolve-sslv3-error-messages-firefox";
|
||||
document.body.className = "certerror";
|
||||
}
|
||||
|
||||
// remove undisplayed errors to avoid bug 39098
|
||||
var errContainer = document.getElementById("errorContainer");
|
||||
errContainer.remove();
|
||||
|
||||
var className = getCSSClass();
|
||||
if (className && className != "expertBadCert") {
|
||||
// Associate a CSS class with the root of the page, if one was passed in,
|
||||
// to allow custom styling.
|
||||
// Not "expertBadCert" though, don't want to deal with the favicon
|
||||
document.documentElement.className = className;
|
||||
|
||||
// Also, if they specified a CSS class, they must supply their own
|
||||
// favicon. In order to trigger the browser to repaint though, we
|
||||
// need to remove/add the link element.
|
||||
var favicon = document.getElementById("favicon");
|
||||
var faviconParent = favicon.parentNode;
|
||||
faviconParent.removeChild(favicon);
|
||||
favicon.setAttribute("href", "chrome://global/skin/icons/" + className + "_favicon.png");
|
||||
faviconParent.appendChild(favicon);
|
||||
}
|
||||
|
||||
if (err == "remoteXUL") {
|
||||
// Remove the "Try again" button for remote XUL errors given that
|
||||
// it is useless.
|
||||
document.getElementById("netErrorButtonContainer").style.display = "none";
|
||||
}
|
||||
|
||||
if (err == "cspBlocked") {
|
||||
// Remove the "Try again" button for CSP violations, since it's
|
||||
// almost certainly useless. (Bug 553180)
|
||||
document.getElementById("netErrorButtonContainer").style.display = "none";
|
||||
}
|
||||
|
||||
window.addEventListener("AboutNetErrorOptions", function(evt) {
|
||||
// Pinning errors are of type nssFailure2
|
||||
if (getErrorCode() == "nssFailure2") {
|
||||
let shortDesc = document.getElementById("errorShortDescText").textContent;
|
||||
document.getElementById("learnMoreContainer").style.display = "block";
|
||||
let learnMoreLink = document.getElementById("learnMoreLink");
|
||||
// nssFailure2 also gets us other non-overrideable errors. Choose
|
||||
// a "learn more" link based on description:
|
||||
if (shortDesc.includes("MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE")) {
|
||||
learnMoreLink.href = "https://support.mozilla.org/kb/certificate-pinning-reports";
|
||||
}
|
||||
|
||||
var options = JSON.parse(evt.detail);
|
||||
if (options && options.enabled) {
|
||||
var checkbox = document.getElementById("automaticallyReportInFuture");
|
||||
showCertificateErrorReporting();
|
||||
if (options.automatic) {
|
||||
// set the checkbox
|
||||
checkbox.checked = true;
|
||||
}
|
||||
|
||||
checkbox.addEventListener("change", function(changeEvt) {
|
||||
var event = new CustomEvent("AboutNetErrorSetAutomatic",
|
||||
{bubbles: true,
|
||||
detail: changeEvt.target.checked});
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
}
|
||||
const hasPrefStyleError = [
|
||||
"interrupted", // This happens with subresources that are above the max tls
|
||||
"SSL_ERROR_PROTOCOL_VERSION_ALERT",
|
||||
"SSL_ERROR_UNSUPPORTED_VERSION",
|
||||
"SSL_ERROR_NO_CYPHER_OVERLAP",
|
||||
"SSL_ERROR_NO_CIPHERS_SUPPORTED"
|
||||
].some((substring) => shortDesc.includes(substring));
|
||||
// If it looks like an error that is user config based
|
||||
if (getErrorCode() == "nssFailure2" && hasPrefStyleError && options && options.changedCertPrefs) {
|
||||
showPrefChangeContainer();
|
||||
}
|
||||
}
|
||||
if (getErrorCode() == "sslv3Used") {
|
||||
document.getElementById("advancedButton").style.display = "none";
|
||||
}
|
||||
}, true, true);
|
||||
|
||||
var event = new CustomEvent("AboutNetErrorLoad", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
|
||||
if (err == "inadequateSecurityError" || err == "blockedByPolicy") {
|
||||
// Remove the "Try again" button from pages that don't need it.
|
||||
// For HTTP/2 inadequate security or pages blocked by policy, trying
|
||||
// again won't help.
|
||||
document.getElementById("errorTryAgain").style.display = "none";
|
||||
|
||||
var container = document.getElementById("errorLongDesc");
|
||||
for (var span of container.querySelectorAll("span.hostname")) {
|
||||
span.textContent = document.location.hostname;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initPageCaptivePortal() {
|
||||
document.body.className = "captiveportal";
|
||||
document.getElementById("openPortalLoginPageButton")
|
||||
.addEventListener("click", () => {
|
||||
let event = new CustomEvent("AboutNetErrorOpenCaptivePortal", {bubbles: true});
|
||||
document.dispatchEvent(event);
|
||||
});
|
||||
|
||||
addAutofocus("openPortalLoginPageButton");
|
||||
setupAdvancedButton();
|
||||
|
||||
// When the portal is freed, an event is generated by the frame script
|
||||
// that we can pick up and attempt to reload the original page.
|
||||
window.addEventListener("AboutNetErrorCaptivePortalFreed", () => {
|
||||
document.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
function initPageCertError() {
|
||||
document.body.className = "certerror";
|
||||
for (let host of document.querySelectorAll(".hostname")) {
|
||||
host.textContent = document.location.hostname;
|
||||
}
|
||||
|
||||
addAutofocus("returnButton");
|
||||
setupAdvancedButton();
|
||||
|
||||
document.getElementById("learnMoreContainer").style.display = "block";
|
||||
|
||||
let checkbox = document.getElementById("automaticallyReportInFuture");
|
||||
checkbox.addEventListener("change", function({target: {checked}}) {
|
||||
document.dispatchEvent(new CustomEvent("AboutNetErrorSetAutomatic", {
|
||||
detail: checked,
|
||||
bubbles: true
|
||||
}));
|
||||
});
|
||||
|
||||
addEventListener("AboutNetErrorOptions", function(event) {
|
||||
var options = JSON.parse(event.detail);
|
||||
if (options && options.enabled) {
|
||||
// Display error reporting UI
|
||||
document.getElementById("certificateErrorReporting").style.display = "block";
|
||||
|
||||
// set the checkbox
|
||||
checkbox.checked = !!options.automatic;
|
||||
}
|
||||
if (options && options.hideAddExceptionButton) {
|
||||
document.querySelector(".exceptionDialogButtonContainer").hidden = true;
|
||||
}
|
||||
}, true, true);
|
||||
|
||||
let event = new CustomEvent("AboutNetErrorLoad", {bubbles: true});
|
||||
document.getElementById("advancedButton").dispatchEvent(event);
|
||||
}
|
||||
|
||||
/* Only do autofocus if we're the toplevel frame; otherwise we
|
||||
don't want to call attention to ourselves! The key part is
|
||||
that autofocus happens on insertion into the tree, so we
|
||||
can remove the button, add @autofocus, and reinsert the
|
||||
button.
|
||||
*/
|
||||
function addAutofocus(buttonId, position = "afterbegin") {
|
||||
if (window.top == window) {
|
||||
var button = document.getElementById(buttonId);
|
||||
var parent = button.parentNode;
|
||||
button.remove();
|
||||
button.setAttribute("autofocus", "true");
|
||||
parent.insertAdjacentElement(position, button);
|
||||
}
|
||||
}
|
||||
|
||||
]]></script>
|
||||
</head>
|
||||
|
||||
<body dir="&locale.dir;">
|
||||
|
@ -486,11 +116,11 @@
|
|||
</div>
|
||||
<p id="badStsCertExplanation" hidden="true">&certerror.whatShouldIDo.badStsCertExplanation;</p>
|
||||
|
||||
<div id="wrongSystemTimePanel" style="display: none;">
|
||||
<div id="wrongSystemTimePanel">
|
||||
&certerror.wrongSystemTime2;
|
||||
</div>
|
||||
|
||||
<div id="wrongSystemTimeWithoutReferencePanel" style="display: none;">
|
||||
<div id="wrongSystemTimeWithoutReferencePanel">
|
||||
&certerror.wrongSystemTimeWithoutReference;
|
||||
</div>
|
||||
|
||||
|
@ -524,7 +154,7 @@
|
|||
</div>
|
||||
|
||||
<div id="netErrorButtonContainer" class="button-container">
|
||||
<button id="errorTryAgain" class="primary" autocomplete="off" onclick="retryThis(this);">&retry.label;</button>
|
||||
<button id="errorTryAgain" class="primary" autocomplete="off">&retry.label;</button>
|
||||
</div>
|
||||
|
||||
<div id="advancedPanelContainer">
|
||||
|
@ -542,15 +172,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
- Note: It is important to run the script this way, instead of using
|
||||
- an onload handler. This is because error pages are loaded as
|
||||
- LOAD_BACKGROUND, which means that onload handlers will not be executed.
|
||||
-->
|
||||
<script type="application/javascript">
|
||||
initPage();
|
||||
</script>
|
||||
|
||||
</body>
|
||||
<script type="application/javascript" src="chrome://browser/content/aboutNetError.js"/>
|
||||
</html>
|
||||
|
|
|
@ -40,6 +40,7 @@ browser.jar:
|
|||
content/browser/illustrations/error-malformed-url.svg (content/illustrations/error-malformed-url.svg)
|
||||
content/browser/illustrations/under-construction.svg (content/illustrations/under-construction.svg)
|
||||
content/browser/aboutNetError.xhtml (content/aboutNetError.xhtml)
|
||||
content/browser/aboutNetError.js (content/aboutNetError.js)
|
||||
content/browser/aboutRobots-icon.png (content/aboutRobots-icon.png)
|
||||
content/browser/aboutRobots-widget-left.png (content/aboutRobots-widget-left.png)
|
||||
content/browser/aboutTabCrashed.css (content/aboutTabCrashed.css)
|
||||
|
|
|
@ -211,3 +211,11 @@ span#hostname {
|
|||
.malformedURI #errorTryAgain {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#wrongSystemTimePanel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#wrongSystemTimeWithoutReferencePanel {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# 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/.
|
||||
|
||||
import buildconfig
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def main(output, lib_file, *scripts):
|
||||
for script in scripts:
|
||||
retcode = subprocess.call([sys.executable, script], cwd=buildconfig.topsrcdir)
|
||||
if retcode != 0:
|
||||
raise Exception(script + " failed")
|
|
@ -787,7 +787,7 @@ CreateInterfaceObject(JSContext* cx, JS::Handle<JSObject*> global,
|
|||
}
|
||||
|
||||
if (isChrome && !JS_DefineFunction(cx, constructor, "isInstance",
|
||||
InterfaceHasInstance, 1,
|
||||
InterfaceIsInstance, 1,
|
||||
// Don't bother making it enumerable
|
||||
0)) {
|
||||
return nullptr;
|
||||
|
|
|
@ -623,9 +623,7 @@ def InterfacePrototypeObjectProtoGetter(descriptor):
|
|||
protoGetter = "GetNamedPropertiesObject"
|
||||
protoHandleGetter = None
|
||||
elif parentProtoName is None:
|
||||
if descriptor.interface.getExtendedAttribute("ArrayClass"):
|
||||
protoGetter = "JS::GetRealmArrayPrototype"
|
||||
elif descriptor.interface.getExtendedAttribute("ExceptionClass"):
|
||||
if descriptor.interface.getExtendedAttribute("ExceptionClass"):
|
||||
protoGetter = "JS::GetRealmErrorPrototype"
|
||||
elif descriptor.interface.isIteratorInterface():
|
||||
protoGetter = "JS::GetRealmIteratorPrototype"
|
||||
|
|
|
@ -1683,14 +1683,6 @@ class IDLInterface(IDLInterfaceOrNamespace):
|
|||
elif newMethod not in self.namedConstructors:
|
||||
raise WebIDLError("NamedConstructor conflicts with a NamedConstructor of a different interface",
|
||||
[method.location, newMethod.location])
|
||||
elif (identifier == "ArrayClass"):
|
||||
if not attr.noArguments():
|
||||
raise WebIDLError("[ArrayClass] must take no arguments",
|
||||
[attr.location])
|
||||
if self.parent:
|
||||
raise WebIDLError("[ArrayClass] must not be specified on "
|
||||
"an interface with inherited interfaces",
|
||||
[attr.location, self.location])
|
||||
elif (identifier == "ExceptionClass"):
|
||||
if not attr.noArguments():
|
||||
raise WebIDLError("[ExceptionClass] must take no arguments",
|
||||
|
|
|
@ -374,32 +374,3 @@ def WebIDLTest(parser, harness):
|
|||
threw = True
|
||||
harness.ok(threw,
|
||||
"Should not allow unknown extended attributes on interfaces")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
interface B {};
|
||||
[ArrayClass]
|
||||
interface A : B {
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(threw,
|
||||
"Should not allow [ArrayClass] on interfaces with parents")
|
||||
|
||||
parser = parser.reset()
|
||||
threw = False
|
||||
try:
|
||||
parser.parse("""
|
||||
[ArrayClass]
|
||||
interface A {
|
||||
};
|
||||
""")
|
||||
results = parser.finish()
|
||||
except:
|
||||
threw = True
|
||||
harness.ok(not threw,
|
||||
"Should allow [ArrayClass] on interfaces without parents")
|
||||
|
|
|
@ -13,3 +13,4 @@ support-files =
|
|||
[test_bug1123516_maplikesetlikechrome.xul]
|
||||
skip-if = debug == false
|
||||
[test_bug1287912.html]
|
||||
[test_bug1457051.html]
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1457051
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1457051</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1457051 **/
|
||||
ok(Element.isInstance(document.documentElement), "Basic isInstance works");
|
||||
ok(!Element.isInstance(null),
|
||||
"Passing null should return false without throwing");
|
||||
ok(!Element.isInstance(5), "Passing 5 should return false without throwing");
|
||||
var obj = Object.create(Element.prototype);
|
||||
ok(obj instanceof Element, "instanceof should walk the proto chain");
|
||||
ok(!Element.isInstance(obj), "isInstance should be a pure brand check");
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1457051">Mozilla Bug 1457051</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -29,11 +29,8 @@ function doc(id) {
|
|||
function checkElement(id, list, eps, doc) {
|
||||
var e = (doc || document).getElementById(id);
|
||||
var clientRects = e.getClientRects();
|
||||
ok(clientRects instanceof e.ownerDocument.defaultView.Array,
|
||||
"getClientRects retval should have Array.prototype on its proto chain");
|
||||
clientRects.map(function(rect) {
|
||||
ok(rect instanceof DOMRect, "Should have a DOMRect here");
|
||||
});
|
||||
ok(!(clientRects instanceof e.ownerDocument.defaultView.Array),
|
||||
"getClientRects retval should not have Array.prototype on its proto chain");
|
||||
is(clientRects.length, list.length, "getClientRects().length for element '" + id + "'");
|
||||
var bounds = list.length > 0 ? list[0] : [0,0,0,0];
|
||||
for (var i = 0; i < clientRects.length && i < list.length; ++i) {
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
[ArrayClass]
|
||||
interface DOMRectList {
|
||||
readonly attribute unsigned long length;
|
||||
getter DOMRect? item(unsigned long index);
|
||||
|
|
|
@ -101,14 +101,14 @@ NS_IMETHODIMP
|
|||
WorkerEventTarget::Dispatch(already_AddRefed<nsIRunnable> aRunnable,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable(aRunnable);
|
||||
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
if (!mWorkerPrivate) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable(aRunnable);
|
||||
|
||||
if (mBehavior == Behavior::Hybrid) {
|
||||
RefPtr<WorkerRunnable> r =
|
||||
mWorkerPrivate->MaybeWrapAsWorkerRunnable(runnable.forget());
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
52579
|
||||
52616
|
||||
0/nm
|
||||
0th/pt
|
||||
1/n1
|
||||
|
@ -1524,6 +1524,7 @@ Billie/M
|
|||
Billings/M
|
||||
Billy/M
|
||||
Bimini/M
|
||||
Bing/M
|
||||
Bink/M
|
||||
Binky/M
|
||||
Binnie/M
|
||||
|
@ -5775,6 +5776,7 @@ IDE
|
|||
IE
|
||||
IED
|
||||
IEEE
|
||||
IIRC
|
||||
IKEA/M
|
||||
IL
|
||||
IMDb/M
|
||||
|
@ -6965,6 +6967,7 @@ Laocoon/M
|
|||
Laos/M
|
||||
Laotian/SM
|
||||
Laplace/M
|
||||
Laplacian
|
||||
Lapland/MR
|
||||
Lapp/SM
|
||||
Lara/M
|
||||
|
@ -9658,6 +9661,7 @@ Petronella/M
|
|||
Petronilla/M
|
||||
Petty/M
|
||||
Peugeot/M
|
||||
Peyronie's
|
||||
Peyton/M
|
||||
Pfc
|
||||
Pfizer/M
|
||||
|
@ -14712,6 +14716,7 @@ anticyclone/SM
|
|||
anticyclonic
|
||||
antidemocratic
|
||||
antidepressant/MS
|
||||
antiderivative/S
|
||||
antidote/MS
|
||||
antifa
|
||||
antifascist/MS
|
||||
|
@ -15370,6 +15375,7 @@ asymmetric
|
|||
asymmetrical/Y
|
||||
asymmetry/SM
|
||||
asymptomatic
|
||||
asymptote/S
|
||||
asymptotic
|
||||
asymptotically
|
||||
asynchronicity
|
||||
|
@ -15794,6 +15800,7 @@ bacteriologist/SM
|
|||
bacteriology/M
|
||||
bacterium/M
|
||||
bad/MYP
|
||||
badass/S
|
||||
badder
|
||||
baddest
|
||||
baddie/M
|
||||
|
@ -19985,6 +19992,8 @@ collide/DRSZG
|
|||
collie/RSMZ
|
||||
collier/M
|
||||
colliery/SM
|
||||
collinear
|
||||
collinearity
|
||||
collision/SM
|
||||
collocate/MGNDSX
|
||||
collocation/M
|
||||
|
@ -21842,6 +21851,7 @@ cw
|
|||
cwt
|
||||
cyan/M
|
||||
cyanide/M
|
||||
cyanobacteria
|
||||
cyber
|
||||
cyberbully/SM
|
||||
cybercafe/S
|
||||
|
@ -22163,6 +22173,7 @@ decidable/U
|
|||
decide/BZGDRS
|
||||
decided/Y
|
||||
deciduous
|
||||
decile/S
|
||||
deciliter/MS
|
||||
decimal/SM
|
||||
decimalization
|
||||
|
@ -22862,6 +22873,7 @@ differ/DG
|
|||
difference/IM
|
||||
differences
|
||||
different/IY
|
||||
differentiable
|
||||
differential/SM
|
||||
differentiate/DSGN
|
||||
differentiated/U
|
||||
|
@ -23036,7 +23048,7 @@ disappointing/Y
|
|||
disarming/Y
|
||||
disastrous/Y
|
||||
disbandment/M
|
||||
disbarment/M
|
||||
disbarment/MS
|
||||
disbelieving/Y
|
||||
disbursal/M
|
||||
disburse/DSGL
|
||||
|
@ -25135,6 +25147,8 @@ eutectic
|
|||
euthanasia/M
|
||||
euthanize/DSG
|
||||
euthenics/M
|
||||
eutrophic
|
||||
eutrophication
|
||||
evacuate/XDSGN
|
||||
evacuation/M
|
||||
evacuee/MS
|
||||
|
@ -25572,11 +25586,13 @@ extravagance/MS
|
|||
extravagant/Y
|
||||
extravaganza/MS
|
||||
extravehicular
|
||||
extrema
|
||||
extreme/PMYTRS
|
||||
extremeness/M
|
||||
extremism/M
|
||||
extremist/MS
|
||||
extremity/SM
|
||||
extremum/S
|
||||
extricable/I
|
||||
extricate/GNDS
|
||||
extrication/M
|
||||
|
@ -27998,6 +28014,7 @@ globular
|
|||
globule/MS
|
||||
globulin/M
|
||||
glockenspiel/SM
|
||||
glom/SDG
|
||||
gloom/M
|
||||
gloomily
|
||||
gloominess/M
|
||||
|
@ -31316,6 +31333,7 @@ intact
|
|||
intaglio/MS
|
||||
integer/MS
|
||||
integral/SMY
|
||||
integrand
|
||||
integrate/AEVNGSD
|
||||
integration/EAM
|
||||
integrator
|
||||
|
@ -31459,6 +31477,7 @@ interpretation/AMS
|
|||
interpretative
|
||||
interpreted/U
|
||||
interpreter/MS
|
||||
interquartile
|
||||
interracial
|
||||
interred/E
|
||||
interregnum/SM
|
||||
|
@ -31584,6 +31603,7 @@ inventory/DSMG
|
|||
inverse/SMY
|
||||
invert/SMDRZG
|
||||
inverter/M
|
||||
invertible
|
||||
invest/ASDGL
|
||||
investigate/GNVDSX
|
||||
investigation/M
|
||||
|
@ -31748,6 +31768,7 @@ isomerism/M
|
|||
isometric/S
|
||||
isometrically
|
||||
isometrics/M
|
||||
isometry
|
||||
isomorphic
|
||||
isosceles
|
||||
isotherm/SM
|
||||
|
@ -32790,6 +32811,7 @@ lb/S
|
|||
lbw
|
||||
lea/SM
|
||||
leach/DSG
|
||||
leachate/S
|
||||
lead/MDNRSZG
|
||||
leader/M
|
||||
leaderless
|
||||
|
@ -35390,6 +35412,7 @@ monomania/M
|
|||
monomaniac/MS
|
||||
monomaniacal
|
||||
monomer/SM
|
||||
monomial
|
||||
mononucleosis/M
|
||||
monophonic
|
||||
monoplane/SM
|
||||
|
@ -35755,6 +35778,7 @@ multitask/GS
|
|||
multitasking/M
|
||||
multitude/SM
|
||||
multitudinous
|
||||
multivariable
|
||||
multivariate
|
||||
multiverse/SM
|
||||
multivitamin/MS
|
||||
|
@ -36407,6 +36431,7 @@ nitrogen/M
|
|||
nitrogenous
|
||||
nitroglycerin/M
|
||||
nitroglycerine/M
|
||||
nitty-gritty
|
||||
nitwit/MS
|
||||
nix/GMDS
|
||||
no/SM
|
||||
|
@ -36620,6 +36645,7 @@ nonmilitant
|
|||
nonmilitary
|
||||
nonnarcotic/SM
|
||||
nonnative/MS
|
||||
nonnegative
|
||||
nonnegotiable
|
||||
nonnuclear
|
||||
nonnumerical
|
||||
|
@ -36664,6 +36690,7 @@ nonracial
|
|||
nonradioactive
|
||||
nonrandom
|
||||
nonreactive
|
||||
nonreal
|
||||
nonreciprocal/SM
|
||||
nonreciprocating
|
||||
nonrecognition/M
|
||||
|
@ -37140,6 +37167,8 @@ octagon/MS
|
|||
octagonal
|
||||
octal
|
||||
octane/MS
|
||||
octant/S
|
||||
octantal
|
||||
octave/MS
|
||||
octavo/MS
|
||||
octet/SM
|
||||
|
@ -37372,6 +37401,7 @@ opiate/SM
|
|||
opine/GNXDS
|
||||
opinion/M
|
||||
opinionated
|
||||
opioid/S
|
||||
opium/M
|
||||
opossum/MS
|
||||
opp
|
||||
|
@ -37896,6 +37926,7 @@ overreach/GDS
|
|||
overreact/SDG
|
||||
overreaction/SM
|
||||
overrefined
|
||||
overrich/P
|
||||
overridden
|
||||
override/MGS
|
||||
overripe/M
|
||||
|
@ -38295,6 +38326,7 @@ paramedical/MS
|
|||
parameter/MS
|
||||
parameterize/D
|
||||
parametric
|
||||
parametrize/D
|
||||
paramilitary/SM
|
||||
paramount
|
||||
paramountcy
|
||||
|
@ -39256,6 +39288,7 @@ phrenologist/SM
|
|||
phrenology/M
|
||||
phyla
|
||||
phylactery/SM
|
||||
phyllo
|
||||
phylogeny/M
|
||||
phylum/M
|
||||
phys
|
||||
|
@ -39324,6 +39357,7 @@ pie/SM
|
|||
piebald/MS
|
||||
piece/DSMG
|
||||
piecemeal
|
||||
piecewise
|
||||
piecework/MRZ
|
||||
pieceworker/M
|
||||
piecrust/SM
|
||||
|
@ -41332,6 +41366,7 @@ quartermaster/MS
|
|||
quarterstaff/M
|
||||
quarterstaves
|
||||
quartet/SM
|
||||
quartile/S
|
||||
quarto/MS
|
||||
quartz/M
|
||||
quasar/MS
|
||||
|
@ -41832,6 +41867,7 @@ rebrand/DG
|
|||
rebuild/SG
|
||||
rebuke/DSMG
|
||||
rebuking/Y
|
||||
rebuttable
|
||||
rebuttal/MS
|
||||
rec'd
|
||||
rec/M
|
||||
|
@ -42333,6 +42369,7 @@ reprise/SMG
|
|||
reproach/GMDSB
|
||||
reproachful/Y
|
||||
reprobate/MS
|
||||
reproducibility
|
||||
reproductive
|
||||
reprogramming
|
||||
reproving/Y
|
||||
|
|
|
@ -50,9 +50,6 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsCRT.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsRange.h"
|
||||
#include "nsIPlaintextEditor.h"
|
||||
|
@ -60,7 +57,6 @@
|
|||
#include "nsIPrefService.h"
|
||||
#include "nsIRunnable.h"
|
||||
#include "nsISelection.h"
|
||||
#include "nsISelectionPrivate.h"
|
||||
#include "nsISelectionController.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsITextServicesFilter.h"
|
||||
|
@ -366,7 +362,7 @@ mozInlineSpellStatus::FinishNavigationEvent(mozInlineSpellWordUtil& aWordUtil)
|
|||
// find the word on the old caret position, this is the one that we MAY need
|
||||
// to check
|
||||
RefPtr<nsRange> oldWord;
|
||||
nsresult rv = aWordUtil.GetRangeForWord(oldAnchorNode->AsDOMNode(),
|
||||
nsresult rv = aWordUtil.GetRangeForWord(oldAnchorNode,
|
||||
static_cast<int32_t>(oldAnchorOffset),
|
||||
getter_AddRefs(oldWord));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -427,14 +423,14 @@ mozInlineSpellStatus::FillNoCheckRangeFromAnchor(
|
|||
}
|
||||
|
||||
uint32_t anchorOffset = mAnchorRange->StartOffset();
|
||||
return aWordUtil.GetRangeForWord(anchorNode->AsDOMNode(),
|
||||
return aWordUtil.GetRangeForWord(anchorNode,
|
||||
static_cast<int32_t>(anchorOffset),
|
||||
getter_AddRefs(mNoCheckRange));
|
||||
}
|
||||
|
||||
// mozInlineSpellStatus::GetDocument
|
||||
//
|
||||
// Returns the nsIDOMDocument object for the document for the
|
||||
// Returns the nsIDocument object for the document for the
|
||||
// current spellchecker.
|
||||
|
||||
nsIDocument*
|
||||
|
@ -936,7 +932,7 @@ mozInlineSpellChecker::GetMisspelledWord(nsIDOMNode *aNode, int32_t aOffset,
|
|||
if (NS_WARN_IF(!spellCheckSelection)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return IsPointInSelection(spellCheckSelection, aNode, aOffset, newword);
|
||||
return IsPointInSelection(*spellCheckSelection, aNode, aOffset, newword);
|
||||
}
|
||||
|
||||
// mozInlineSpellChecker::ReplaceWord
|
||||
|
@ -1049,9 +1045,7 @@ mozInlineSpellChecker::DidSplitNode(nsINode* aExistingRightNode,
|
|||
if (!mIsListeningToEditActions) {
|
||||
return;
|
||||
}
|
||||
nsIDOMNode* newLeftDOMNode =
|
||||
aNewLeftNode ? aNewLeftNode->AsDOMNode() : nullptr;
|
||||
SpellCheckBetweenNodes(newLeftDOMNode, 0, newLeftDOMNode, 0);
|
||||
SpellCheckBetweenNodes(aNewLeftNode, 0, aNewLeftNode, 0);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1061,7 +1055,7 @@ mozInlineSpellChecker::DidJoinNodes(nsINode& aLeftNode,
|
|||
if (!mIsListeningToEditActions) {
|
||||
return;
|
||||
}
|
||||
SpellCheckBetweenNodes(aRightNode.AsDOMNode(), 0, aRightNode.AsDOMNode(), 0);
|
||||
SpellCheckBetweenNodes(&aRightNode, 0, &aRightNode, 0);
|
||||
}
|
||||
|
||||
// mozInlineSpellChecker::MakeSpellCheckRange
|
||||
|
@ -1076,8 +1070,8 @@ mozInlineSpellChecker::DidJoinNodes(nsINode& aLeftNode,
|
|||
|
||||
nsresult
|
||||
mozInlineSpellChecker::MakeSpellCheckRange(
|
||||
nsIDOMNode* aStartNode, int32_t aStartOffset,
|
||||
nsIDOMNode* aEndNode, int32_t aEndOffset,
|
||||
nsINode* aStartNode, int32_t aStartOffset,
|
||||
nsINode* aEndNode, int32_t aEndOffset,
|
||||
nsRange** aRange)
|
||||
{
|
||||
nsresult rv;
|
||||
|
@ -1096,8 +1090,7 @@ mozInlineSpellChecker::MakeSpellCheckRange(
|
|||
|
||||
// possibly use full range of the editor
|
||||
if (! aStartNode || ! aEndNode) {
|
||||
nsCOMPtr<nsIDOMElement> domRootElement =
|
||||
do_QueryInterface(mTextEditor->GetRoot());
|
||||
Element* domRootElement = mTextEditor->GetRoot();
|
||||
if (NS_WARN_IF(!domRootElement)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
@ -1113,8 +1106,7 @@ mozInlineSpellChecker::MakeSpellCheckRange(
|
|||
// length). The former is faster if we keep getting different nodes here...
|
||||
//
|
||||
// Let's do the thing which can't end up with bad O(N^2) behavior.
|
||||
nsCOMPtr<nsINode> endNode = do_QueryInterface(aEndNode);
|
||||
aEndOffset = endNode->ChildNodes()->Length();
|
||||
aEndOffset = aEndNode->ChildNodes()->Length();
|
||||
}
|
||||
|
||||
// sometimes we are are requested to check an empty range (possibly an empty
|
||||
|
@ -1122,17 +1114,15 @@ mozInlineSpellChecker::MakeSpellCheckRange(
|
|||
if (aStartNode == aEndNode && aStartOffset == aEndOffset)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsINode> startNode = do_QueryInterface(aStartNode);
|
||||
nsCOMPtr<nsINode> endNode = do_QueryInterface(aEndNode);
|
||||
if (aEndOffset) {
|
||||
rv = range->SetStartAndEnd(startNode, aStartOffset, endNode, aEndOffset);
|
||||
rv = range->SetStartAndEnd(aStartNode, aStartOffset, aEndNode, aEndOffset);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
uint32_t endOffset;
|
||||
endNode = nsRange::GetContainerAndOffsetAfter(endNode, &endOffset);
|
||||
rv = range->SetStartAndEnd(startNode, aStartOffset, endNode, endOffset);
|
||||
aEndNode = nsRange::GetContainerAndOffsetAfter(aEndNode, &endOffset);
|
||||
rv = range->SetStartAndEnd(aStartNode, aStartOffset, aEndNode, endOffset);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -1143,9 +1133,9 @@ mozInlineSpellChecker::MakeSpellCheckRange(
|
|||
}
|
||||
|
||||
nsresult
|
||||
mozInlineSpellChecker::SpellCheckBetweenNodes(nsIDOMNode *aStartNode,
|
||||
mozInlineSpellChecker::SpellCheckBetweenNodes(nsINode* aStartNode,
|
||||
int32_t aStartOffset,
|
||||
nsIDOMNode *aEndNode,
|
||||
nsINode* aEndNode,
|
||||
int32_t aEndOffset)
|
||||
{
|
||||
RefPtr<nsRange> range;
|
||||
|
@ -1630,19 +1620,18 @@ mozInlineSpellChecker::ResumeCheck(UniquePtr<mozInlineSpellStatus>&& aStatus)
|
|||
// If there is no intersection, *aRange will be nullptr.
|
||||
|
||||
nsresult
|
||||
mozInlineSpellChecker::IsPointInSelection(nsISelection *aSelection,
|
||||
mozInlineSpellChecker::IsPointInSelection(Selection& aSelection,
|
||||
nsIDOMNode *aNode,
|
||||
int32_t aOffset,
|
||||
nsIDOMRange **aRange)
|
||||
{
|
||||
*aRange = nullptr;
|
||||
|
||||
nsCOMPtr<nsISelectionPrivate> privSel(do_QueryInterface(aSelection));
|
||||
|
||||
nsTArray<nsRange*> ranges;
|
||||
nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
|
||||
nsresult rv = privSel->GetRangesForIntervalArray(node, aOffset, node, aOffset,
|
||||
true, &ranges);
|
||||
nsresult rv = aSelection.GetRangesForIntervalArray(node, aOffset,
|
||||
node, aOffset,
|
||||
true, &ranges);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (ranges.Length() == 0)
|
||||
|
|
|
@ -62,8 +62,10 @@ public:
|
|||
int32_t mWordCount;
|
||||
|
||||
// what happened?
|
||||
enum Operation { eOpChange, // for SpellCheckAfterChange except deleteSelection
|
||||
eOpChangeDelete, // for SpellCheckAfterChange deleteSelection
|
||||
enum Operation { eOpChange, // for SpellCheckAfterEditorChange except
|
||||
// deleteSelection
|
||||
eOpChangeDelete, // for SpellCheckAfterEditorChange with
|
||||
// deleteSelection
|
||||
eOpNavigation, // for HandleNavigationEvent
|
||||
eOpSelection, // re-check all misspelled words
|
||||
eOpResume }; // for resuming a previously started check
|
||||
|
@ -201,9 +203,9 @@ public:
|
|||
mozInlineSpellChecker();
|
||||
|
||||
// spell checks all of the words between two nodes
|
||||
nsresult SpellCheckBetweenNodes(nsIDOMNode *aStartNode,
|
||||
nsresult SpellCheckBetweenNodes(nsINode* aStartNode,
|
||||
int32_t aStartOffset,
|
||||
nsIDOMNode *aEndNode,
|
||||
nsINode* aEndNode,
|
||||
int32_t aEndOffset);
|
||||
|
||||
// examines the dom node in question and returns true if the inline spell
|
||||
|
@ -211,10 +213,6 @@ public:
|
|||
// or an e-mail signature...)
|
||||
bool ShouldSpellCheckNode(mozilla::TextEditor* aTextEditor, nsINode *aNode);
|
||||
|
||||
nsresult SpellCheckAfterChange(nsIDOMNode* aCursorNode, int32_t aCursorOffset,
|
||||
nsIDOMNode* aPreviousNode, int32_t aPreviousOffset,
|
||||
nsISelection* aSpellCheckSelection);
|
||||
|
||||
// spell check the text contained within aRange, potentially scheduling
|
||||
// another check in the future if the time threshold is reached
|
||||
nsresult ScheduleSpellCheck(mozilla::UniquePtr<mozInlineSpellStatus>&& aStatus);
|
||||
|
@ -227,7 +225,7 @@ public:
|
|||
bool* aDoneChecking);
|
||||
|
||||
// helper routine to determine if a point is inside of the passed in selection.
|
||||
nsresult IsPointInSelection(nsISelection *aSelection,
|
||||
nsresult IsPointInSelection(mozilla::dom::Selection& aSelection,
|
||||
nsIDOMNode *aNode,
|
||||
int32_t aOffset,
|
||||
nsIDOMRange **aRange);
|
||||
|
@ -240,8 +238,8 @@ public:
|
|||
nsRange* aRange);
|
||||
bool SpellCheckSelectionIsFull() { return mNumWordsInSpellSelection >= mMaxNumWordsInSpellSelection; }
|
||||
|
||||
nsresult MakeSpellCheckRange(nsIDOMNode* aStartNode, int32_t aStartOffset,
|
||||
nsIDOMNode* aEndNode, int32_t aEndOffset,
|
||||
nsresult MakeSpellCheckRange(nsINode* aStartNode, int32_t aStartOffset,
|
||||
nsINode* aEndNode, int32_t aEndOffset,
|
||||
nsRange** aRange);
|
||||
|
||||
// DOM and editor event registration helper routines
|
||||
|
|
|
@ -12,10 +12,7 @@
|
|||
#include "nsDebug.h"
|
||||
#include "nsAtom.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOMRange.h"
|
||||
#include "nsIEditor.h"
|
||||
#include "nsIDOMNode.h"
|
||||
#include "nsUnicodeProperties.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsIContent.h"
|
||||
|
@ -62,7 +59,6 @@ mozInlineSpellWordUtil::Init(TextEditor* aTextEditor)
|
|||
if (NS_WARN_IF(!mDocument)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mDOMDocument = do_QueryInterface(mDocument);
|
||||
|
||||
// Find the root node for the editor. For contenteditable we'll need something
|
||||
// cleverer here.
|
||||
|
@ -242,13 +238,12 @@ mozInlineSpellWordUtil::MakeNodeOffsetRangeForWord(const RealWord& aWord,
|
|||
// mozInlineSpellWordUtil::GetRangeForWord
|
||||
|
||||
nsresult
|
||||
mozInlineSpellWordUtil::GetRangeForWord(nsIDOMNode* aWordNode,
|
||||
mozInlineSpellWordUtil::GetRangeForWord(nsINode* aWordNode,
|
||||
int32_t aWordOffset,
|
||||
nsRange** aRange)
|
||||
{
|
||||
// Set our soft end and start
|
||||
nsCOMPtr<nsINode> wordNode = do_QueryInterface(aWordNode);
|
||||
NodeOffset pt = NodeOffset(wordNode, aWordOffset);
|
||||
NodeOffset pt(aWordNode, aWordOffset);
|
||||
|
||||
if (!mSoftTextValid || pt != mSoftBegin || pt != mSoftEnd) {
|
||||
InvalidateWords();
|
||||
|
@ -335,8 +330,9 @@ mozInlineSpellWordUtil::MakeRange(NodeOffset aBegin, NodeOffset aEnd,
|
|||
nsRange** aRange)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aBegin.mNode);
|
||||
if (!mDOMDocument)
|
||||
if (!mDocument) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
RefPtr<nsRange> range = new nsRange(aBegin.mNode);
|
||||
nsresult rv = range->SetStartAndEnd(aBegin.mNode, aBegin.mOffset,
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
#ifndef mozInlineSpellWordUtil_h
|
||||
#define mozInlineSpellWordUtil_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
|
@ -88,7 +88,7 @@ public:
|
|||
* 4. Call GetNextWord over and over until it returns false.
|
||||
*/
|
||||
|
||||
class mozInlineSpellWordUtil
|
||||
class MOZ_STACK_CLASS mozInlineSpellWordUtil
|
||||
{
|
||||
public:
|
||||
mozInlineSpellWordUtil()
|
||||
|
@ -113,7 +113,7 @@ public:
|
|||
// THIS CHANGES THE CURRENT POSITION AND RANGE. It is designed to be called
|
||||
// before you actually generate the range you are interested in and iterate
|
||||
// the words in it.
|
||||
nsresult GetRangeForWord(nsIDOMNode* aWordNode, int32_t aWordOffset,
|
||||
nsresult GetRangeForWord(nsINode* aWordNode, int32_t aWordOffset,
|
||||
nsRange** aRange);
|
||||
|
||||
// Convenience functions, object must be initialized
|
||||
|
@ -131,14 +131,12 @@ public:
|
|||
// so we can access characters directly.
|
||||
static void NormalizeWord(nsAString& aWord);
|
||||
|
||||
nsIDOMDocument* GetDOMDocument() const { return mDOMDocument; }
|
||||
nsIDocument* GetDocument() const { return mDocument; }
|
||||
nsINode* GetRootNode() { return mRootNode; }
|
||||
|
||||
private:
|
||||
|
||||
// cached stuff for the editor, set by Init
|
||||
nsCOMPtr<nsIDOMDocument> mDOMDocument;
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
|
||||
// range to check, see SetPosition and SetEnd
|
||||
|
|
|
@ -49,18 +49,9 @@ JITTEST_SANITIZER_ENV=MSAN_SYMBOLIZER_PATH='$(LLVM_SYMBOLIZER)'
|
|||
endif
|
||||
endif
|
||||
|
||||
check-style::
|
||||
(cd $(topsrcdir) && $(PYTHON) $(topsrcdir)/config/check_spidermonkey_style.py);
|
||||
|
||||
check-masm::
|
||||
(cd $(topsrcdir) && $(PYTHON) $(topsrcdir)/config/check_macroassembler_style.py);
|
||||
|
||||
check-js-msg::
|
||||
(cd $(topsrcdir) && $(PYTHON) $(topsrcdir)/config/check_js_msg_encoding.py);
|
||||
|
||||
check-opcode::
|
||||
(cd $(topsrcdir) && $(PYTHON) $(topsrcdir)/config/check_js_opcode.py);
|
||||
|
||||
check-jit-test::
|
||||
$(JITTEST_SANITIZER_ENV) $(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/jit-test/jit_test.py \
|
||||
--no-slow --no-progress --format=automation --jitflags=all \
|
||||
|
@ -68,7 +59,7 @@ check-jit-test::
|
|||
$(JITTEST_EXTRA_ARGS) \
|
||||
$(DIST)/bin/$(JS_SHELL_NAME)$(BIN_SUFFIX) $(JITTEST_TEST_ARGS)
|
||||
|
||||
check:: check-style check-masm check-js-msg check-opcode
|
||||
check:: check-js-msg
|
||||
|
||||
check-jstests:
|
||||
$(wildcard $(RUN_TEST_PROGRAM)) $(PYTHON) -u $(srcdir)/tests/jstests.py \
|
||||
|
|
|
@ -31,11 +31,14 @@ fn main() {
|
|||
// can swap in instead and everything using a single malloc is
|
||||
// good.
|
||||
"--no-jemalloc",
|
||||
// Don't try to clobber the output directory. Without
|
||||
// this option, the build will fail because the directory
|
||||
// already exists but wasn't created by autospider.
|
||||
"--dep",
|
||||
"--objdir", &out_dir,
|
||||
variant])
|
||||
.env("SOURCE", &js_src)
|
||||
.env("PWD", &js_src)
|
||||
.env("AUTOMATION", "1")
|
||||
.stdout(Stdio::inherit())
|
||||
.stderr(Stdio::inherit());
|
||||
println!("Running command: {:?}", cmd);
|
||||
|
|
|
@ -75,3 +75,15 @@ DIST_INSTALL = True
|
|||
# with those in libxul.
|
||||
if CONFIG['OS_TARGET'] == 'Linux':
|
||||
LDFLAGS += ['-Wl,-version-script,symverscript']
|
||||
|
||||
# Run SpiderMonkey style checker after linking the static library. This avoids
|
||||
# running the script for no-op builds.
|
||||
GENERATED_FILES += ['spidermonkey_checks']
|
||||
run_checks = GENERATED_FILES['spidermonkey_checks']
|
||||
run_checks.script = '/config/run_spidermonkey_checks.py'
|
||||
run_checks.inputs += [
|
||||
'!%sjs_static.%s' % (CONFIG['LIB_PREFIX'], CONFIG['LIB_SUFFIX']),
|
||||
'/config/check_spidermonkey_style.py',
|
||||
'/config/check_macroassembler_style.py',
|
||||
'/config/check_js_opcode.py'
|
||||
]
|
||||
|
|
|
@ -125,17 +125,16 @@ function getUnicodeExtensions(locale) {
|
|||
* Parser for BCP 47 language tags.
|
||||
*
|
||||
* Returns null if |locale| can't be parsed as a Language-Tag. If the input is
|
||||
* an irregular grandfathered language tag, the object
|
||||
* a grandfathered language tag, the object
|
||||
*
|
||||
* {
|
||||
* locale: locale.toLowerCase(),
|
||||
* locale: locale (normalized to canonical form),
|
||||
* grandfathered: true,
|
||||
* }
|
||||
*
|
||||
* is returned. Otherwise the returned object has the following structure:
|
||||
*
|
||||
* {
|
||||
* locale: locale.toLowerCase(),
|
||||
* language: language subtag without extlang / undefined,
|
||||
* extlang1: first extlang subtag / undefined,
|
||||
* extlang2: second extlang subtag / undefined,
|
||||
|
@ -147,13 +146,12 @@ function getUnicodeExtensions(locale) {
|
|||
* privateuse: privateuse subtag / undefined,
|
||||
* }
|
||||
*
|
||||
* All language tag subtags are returned in lower-case:
|
||||
* All language tag subtags are returned in their normalized case:
|
||||
*
|
||||
* var langtag = parseLanguageTag("en-Latn-US");
|
||||
* assertEq("en-latn-us", langtag.locale);
|
||||
* var langtag = parseLanguageTag("en-latn-us");
|
||||
* assertEq("en", langtag.language);
|
||||
* assertEq("latn", langtag.script);
|
||||
* assertEq("us", langtag.region);
|
||||
* assertEq("Latn", langtag.script);
|
||||
* assertEq("US", langtag.region);
|
||||
*
|
||||
* Spec: RFC 5646 section 2.1.
|
||||
*/
|
||||
|
@ -307,6 +305,12 @@ function parseLanguageTag(locale) {
|
|||
// script = 4ALPHA ; ISO 15924 code
|
||||
if (tokenLength === 4 && token === ALPHA) {
|
||||
script = tokenStringLower();
|
||||
|
||||
// The first character of a script code needs to be capitalized.
|
||||
// "hans" -> "Hans"
|
||||
script = callFunction(std_String_toUpperCase, script[0]) +
|
||||
Substring(script, 1, script.length - 1);
|
||||
|
||||
if (!nextToken())
|
||||
return null;
|
||||
}
|
||||
|
@ -315,6 +319,10 @@ function parseLanguageTag(locale) {
|
|||
// / 3DIGIT ; UN M.49 code
|
||||
if ((tokenLength === 2 && token === ALPHA) || (tokenLength === 3 && token === DIGIT)) {
|
||||
region = tokenStringLower();
|
||||
|
||||
// Region codes need to be in upper-case. "bu" -> "BU"
|
||||
region = callFunction(std_String_toUpperCase, region);
|
||||
|
||||
if (!nextToken())
|
||||
return null;
|
||||
}
|
||||
|
@ -417,12 +425,11 @@ function parseLanguageTag(locale) {
|
|||
localeLowercase.length - privateuseStart);
|
||||
}
|
||||
|
||||
// Return if the complete input was successfully parsed. That means it is
|
||||
// either a langtag or privateuse-only language tag, or it is a regular
|
||||
// grandfathered language tag.
|
||||
if (token === NONE) {
|
||||
// Return if the complete input was successfully parsed and it is not a
|
||||
// regular grandfathered language tag. That means it is either a langtag
|
||||
// or privateuse-only language tag
|
||||
if (token === NONE && !hasOwn(localeLowercase, grandfatheredMappings)) {
|
||||
return {
|
||||
locale: localeLowercase,
|
||||
language,
|
||||
extlang1,
|
||||
extlang2,
|
||||
|
@ -443,76 +450,48 @@ function parseLanguageTag(locale) {
|
|||
// For example we need to reject "i-ha\u212A" (U+212A KELVIN SIGN) even
|
||||
// though its lower-case form "i-hak" matches a grandfathered language
|
||||
// tag.
|
||||
do {
|
||||
while (token !== NONE) {
|
||||
if (!nextToken())
|
||||
return null;
|
||||
} while (token !== NONE);
|
||||
}
|
||||
|
||||
// grandfathered = irregular ; non-redundant tags registered
|
||||
// / regular ; during the RFC 3066 era
|
||||
switch (localeLowercase) {
|
||||
#ifdef DEBUG
|
||||
// regular = "art-lojban" ; these tags match the 'langtag'
|
||||
// / "cel-gaulish" ; production, but their subtags
|
||||
// / "no-bok" ; are not extended language
|
||||
// / "no-nyn" ; or variant subtags: their meaning
|
||||
// / "zh-guoyu" ; is defined by their registration
|
||||
// / "zh-hakka" ; and all of these are deprecated
|
||||
// / "zh-min" ; in favor of a more modern
|
||||
// / "zh-min-nan" ; subtag or sequence of subtags
|
||||
// / "zh-xiang"
|
||||
case "art-lojban":
|
||||
case "cel-gaulish":
|
||||
case "no-bok":
|
||||
case "no-nyn":
|
||||
case "zh-guoyu":
|
||||
case "zh-hakka":
|
||||
case "zh-min":
|
||||
case "zh-min-nan":
|
||||
case "zh-xiang":
|
||||
assert(false, "regular grandfathered tags should have been matched above");
|
||||
#endif /* DEBUG */
|
||||
|
||||
// irregular = "en-GB-oed" ; irregular tags do not match
|
||||
// / "i-ami" ; the 'langtag' production and
|
||||
// / "i-bnn" ; would not otherwise be
|
||||
// / "i-default" ; considered 'well-formed'
|
||||
// / "i-enochian" ; These tags are all valid,
|
||||
// / "i-hak" ; but most are deprecated
|
||||
// / "i-klingon" ; in favor of more modern
|
||||
// / "i-lux" ; subtags or subtag
|
||||
// / "i-mingo" ; combination
|
||||
// / "i-navajo"
|
||||
// / "i-pwn"
|
||||
// / "i-tao"
|
||||
// / "i-tay"
|
||||
// / "i-tsu"
|
||||
// / "sgn-BE-FR"
|
||||
// / "sgn-BE-NL"
|
||||
// / "sgn-CH-DE"
|
||||
case "en-gb-oed":
|
||||
case "i-ami":
|
||||
case "i-bnn":
|
||||
case "i-default":
|
||||
case "i-enochian":
|
||||
case "i-hak":
|
||||
case "i-klingon":
|
||||
case "i-lux":
|
||||
case "i-mingo":
|
||||
case "i-navajo":
|
||||
case "i-pwn":
|
||||
case "i-tao":
|
||||
case "i-tay":
|
||||
case "i-tsu":
|
||||
case "sgn-be-fr":
|
||||
case "sgn-be-nl":
|
||||
case "sgn-ch-de":
|
||||
return { locale: localeLowercase, grandfathered: true };
|
||||
|
||||
default:
|
||||
return null;
|
||||
// irregular = "en-GB-oed" ; irregular tags do not match
|
||||
// / "i-ami" ; the 'langtag' production and
|
||||
// / "i-bnn" ; would not otherwise be
|
||||
// / "i-default" ; considered 'well-formed'
|
||||
// / "i-enochian" ; These tags are all valid,
|
||||
// / "i-hak" ; but most are deprecated
|
||||
// / "i-klingon" ; in favor of more modern
|
||||
// / "i-lux" ; subtags or subtag
|
||||
// / "i-mingo" ; combination
|
||||
// / "i-navajo"
|
||||
// / "i-pwn"
|
||||
// / "i-tao"
|
||||
// / "i-tay"
|
||||
// / "i-tsu"
|
||||
// / "sgn-BE-FR"
|
||||
// / "sgn-BE-NL"
|
||||
// / "sgn-CH-DE"
|
||||
// regular = "art-lojban" ; these tags match the 'langtag'
|
||||
// / "cel-gaulish" ; production, but their subtags
|
||||
// / "no-bok" ; are not extended language
|
||||
// / "no-nyn" ; or variant subtags: their meaning
|
||||
// / "zh-guoyu" ; is defined by their registration
|
||||
// / "zh-hakka" ; and all of these are deprecated
|
||||
// / "zh-min" ; in favor of a more modern
|
||||
// / "zh-min-nan" ; subtag or sequence of subtags
|
||||
// / "zh-xiang"
|
||||
if (hasOwn(localeLowercase, grandfatheredMappings)) {
|
||||
return {
|
||||
locale: grandfatheredMappings[localeLowercase],
|
||||
grandfathered: true
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
#undef NONE
|
||||
#undef ALPHA
|
||||
#undef DIGIT
|
||||
|
@ -560,16 +539,12 @@ function IsStructurallyValidLanguageTag(locale) {
|
|||
function CanonicalizeLanguageTagFromObject(localeObj) {
|
||||
assert(IsObject(localeObj), "CanonicalizeLanguageTagFromObject");
|
||||
|
||||
var {locale} = localeObj;
|
||||
assert(locale === callFunction(std_String_toLowerCase, locale),
|
||||
"expected lower-case form for locale string");
|
||||
// Handle grandfathered language tags.
|
||||
if (hasOwn("grandfathered", localeObj))
|
||||
return localeObj.locale;
|
||||
|
||||
// Handle mappings for complete tags.
|
||||
if (hasOwn(locale, langTagMappings))
|
||||
return langTagMappings[locale];
|
||||
|
||||
assert(!hasOwn("grandfathered", localeObj),
|
||||
"grandfathered tags should be mapped completely");
|
||||
// Update mappings for complete tags.
|
||||
updateLangTagMappings(localeObj);
|
||||
|
||||
var {
|
||||
language,
|
||||
|
@ -630,25 +605,25 @@ function CanonicalizeLanguageTagFromObject(localeObj) {
|
|||
if (extlang3)
|
||||
canonical += "-" + extlang3;
|
||||
|
||||
// No script replacements are currently present, so append as is.
|
||||
if (script) {
|
||||
// The first character of a script code needs to be capitalized.
|
||||
// "hans" -> "Hans"
|
||||
script = callFunction(std_String_toUpperCase, script[0]) +
|
||||
Substring(script, 1, script.length - 1);
|
||||
|
||||
// No script replacements are currently present, so append as is.
|
||||
assert(script.length === 4 &&
|
||||
script ===
|
||||
callFunction(std_String_toUpperCase, script[0]) +
|
||||
callFunction(std_String_toLowerCase, Substring(script, 1, script.length - 1)),
|
||||
"script must be [A-Z][a-z]{3}");
|
||||
canonical += "-" + script;
|
||||
}
|
||||
|
||||
if (region) {
|
||||
// Region codes need to be in upper-case. "bu" -> "BU"
|
||||
region = callFunction(std_String_toUpperCase, region);
|
||||
|
||||
// Replace deprecated subtags with their preferred values.
|
||||
// "BU" -> "MM"
|
||||
if (hasOwn(region, regionMappings))
|
||||
region = regionMappings[region];
|
||||
|
||||
assert((2 <= region.length && region.length <= 3) &&
|
||||
region === callFunction(std_String_toUpperCase, region),
|
||||
"region must be [A-Z]{2} or [0-9]{3}");
|
||||
canonical += "-" + region;
|
||||
}
|
||||
|
||||
|
@ -733,9 +708,9 @@ function ValidateAndCanonicalizeLanguageTag(locale) {
|
|||
// The language subtag is canonicalized to lower case.
|
||||
locale = callFunction(std_String_toLowerCase, locale);
|
||||
|
||||
// langTagMappings doesn't contain any 2*3ALPHA keys, so we don't need
|
||||
// to check for possible replacements in this map.
|
||||
assert(!hasOwn(locale, langTagMappings), "langTagMappings contains no 2*3ALPHA mappings");
|
||||
// updateLangTagMappings doesn't modify tags containing only
|
||||
// |language| subtags, so we don't need to call it for possible
|
||||
// replacements.
|
||||
|
||||
// Replace deprecated subtags with their preferred values.
|
||||
locale = hasOwn(locale, languageMappings)
|
||||
|
|
|
@ -1,9 +1,321 @@
|
|||
// Generated by make_intl_data.py. DO NOT EDIT.
|
||||
|
||||
/* eslint-disable complexity */
|
||||
// Mappings from complete tags to preferred values.
|
||||
// Derived from IANA Language Subtag Registry, file date 2018-03-20.
|
||||
// Derived from IANA Language Subtag Registry, file date 2018-03-30.
|
||||
// https://www.iana.org/assignments/language-subtag-registry
|
||||
var langTagMappings = {
|
||||
function updateLangTagMappings(tag) {
|
||||
assert(IsObject(tag), "tag is an object");
|
||||
assert(!hasOwn("grandfathered", tag), "tag is not a grandfathered tag");
|
||||
|
||||
switch (tag.language) {
|
||||
case "hy":
|
||||
// hy-arevela -> hy
|
||||
if (tag.variants.length >= 1 &&
|
||||
callFunction(ArrayIndexOf, tag.variants, "arevela") > -1)
|
||||
{
|
||||
var newVariants = [];
|
||||
for (var i = 0; i < tag.variants.length; i++) {
|
||||
var variant = tag.variants[i];
|
||||
if (variant === "arevela")
|
||||
continue;
|
||||
_DefineDataProperty(newVariants, newVariants.length, variant);
|
||||
}
|
||||
tag.variants = newVariants;
|
||||
}
|
||||
// hy-arevmda -> hyw
|
||||
else if (tag.variants.length >= 1 &&
|
||||
callFunction(ArrayIndexOf, tag.variants, "arevmda") > -1)
|
||||
{
|
||||
tag.language = "hyw";
|
||||
var newVariants = [];
|
||||
for (var i = 0; i < tag.variants.length; i++) {
|
||||
var variant = tag.variants[i];
|
||||
if (variant === "arevmda")
|
||||
continue;
|
||||
_DefineDataProperty(newVariants, newVariants.length, variant);
|
||||
}
|
||||
tag.variants = newVariants;
|
||||
}
|
||||
break;
|
||||
case "ja":
|
||||
// ja-Latn-hepburn-heploc -> ja-Latn-alalc97
|
||||
if (tag.script === "Latn" &&
|
||||
tag.variants.length >= 2 &&
|
||||
callFunction(ArrayIndexOf, tag.variants, "hepburn") > -1 &&
|
||||
callFunction(ArrayIndexOf, tag.variants, "heploc", callFunction(ArrayIndexOf, tag.variants, "hepburn") + 1) > -1)
|
||||
{
|
||||
var newVariants = [];
|
||||
for (var i = 0; i < tag.variants.length; i++) {
|
||||
var variant = tag.variants[i];
|
||||
if (variant === "hepburn")
|
||||
continue;
|
||||
if (variant === "heploc")
|
||||
continue;
|
||||
_DefineDataProperty(newVariants, newVariants.length, variant);
|
||||
}
|
||||
if (callFunction(ArrayIndexOf, newVariants, "alalc97") < 0)
|
||||
_DefineDataProperty(newVariants, newVariants.length, "alalc97");
|
||||
tag.variants = newVariants;
|
||||
}
|
||||
break;
|
||||
case "sgn":
|
||||
// sgn-BR -> bzs
|
||||
if (tag.region === "BR" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "bzs";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-CO -> csn
|
||||
else if (tag.region === "CO" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "csn";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-DE -> gsg
|
||||
else if (tag.region === "DE" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "gsg";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-DK -> dsl
|
||||
else if (tag.region === "DK" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "dsl";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-ES -> ssp
|
||||
else if (tag.region === "ES" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "ssp";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-FR -> fsl
|
||||
else if (tag.region === "FR" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "fsl";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-GB -> bfi
|
||||
else if (tag.region === "GB" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "bfi";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-GR -> gss
|
||||
else if (tag.region === "GR" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "gss";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-IE -> isg
|
||||
else if (tag.region === "IE" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "isg";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-IT -> ise
|
||||
else if (tag.region === "IT" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "ise";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-JP -> jsl
|
||||
else if (tag.region === "JP" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "jsl";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-MX -> mfs
|
||||
else if (tag.region === "MX" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "mfs";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-NI -> ncs
|
||||
else if (tag.region === "NI" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "ncs";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-NL -> dse
|
||||
else if (tag.region === "NL" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "dse";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-NO -> nsl
|
||||
else if (tag.region === "NO" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "nsl";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-PT -> psr
|
||||
else if (tag.region === "PT" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "psr";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-SE -> swl
|
||||
else if (tag.region === "SE" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "swl";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-US -> ase
|
||||
else if (tag.region === "US" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "ase";
|
||||
tag.region = undefined;
|
||||
}
|
||||
// sgn-ZA -> sfs
|
||||
else if (tag.region === "ZA" &&
|
||||
tag.extlang1 === undefined &&
|
||||
tag.extlang2 === undefined &&
|
||||
tag.extlang3 === undefined &&
|
||||
tag.script === undefined &&
|
||||
tag.variants.length === 0 &&
|
||||
tag.extensions.length === 0 &&
|
||||
tag.privateuse === undefined)
|
||||
{
|
||||
tag.language = "sfs";
|
||||
tag.region = undefined;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* eslint-enable complexity */
|
||||
|
||||
// Mappings from grandfathered tags to preferred values.
|
||||
// Derived from IANA Language Subtag Registry, file date 2018-03-30.
|
||||
// https://www.iana.org/assignments/language-subtag-registry
|
||||
var grandfatheredMappings = {
|
||||
"art-lojban": "jbo",
|
||||
"cel-gaulish": "cel-gaulish",
|
||||
"en-gb-oed": "en-GB-oxendict",
|
||||
|
@ -20,46 +332,20 @@ var langTagMappings = {
|
|||
"i-tao": "tao",
|
||||
"i-tay": "tay",
|
||||
"i-tsu": "tsu",
|
||||
"ja-latn-hepburn-heploc": "ja-Latn-alalc97",
|
||||
"no-bok": "nb",
|
||||
"no-nyn": "nn",
|
||||
"sgn-be-fr": "sfb",
|
||||
"sgn-be-nl": "vgt",
|
||||
"sgn-br": "bzs",
|
||||
"sgn-ch-de": "sgg",
|
||||
"sgn-co": "csn",
|
||||
"sgn-de": "gsg",
|
||||
"sgn-dk": "dsl",
|
||||
"sgn-es": "ssp",
|
||||
"sgn-fr": "fsl",
|
||||
"sgn-gb": "bfi",
|
||||
"sgn-gr": "gss",
|
||||
"sgn-ie": "isg",
|
||||
"sgn-it": "ise",
|
||||
"sgn-jp": "jsl",
|
||||
"sgn-mx": "mfs",
|
||||
"sgn-ni": "ncs",
|
||||
"sgn-nl": "dse",
|
||||
"sgn-no": "nsl",
|
||||
"sgn-pt": "psr",
|
||||
"sgn-se": "swl",
|
||||
"sgn-us": "ase",
|
||||
"sgn-za": "sfs",
|
||||
"zh-cmn": "cmn",
|
||||
"zh-cmn-hans": "cmn-Hans",
|
||||
"zh-cmn-hant": "cmn-Hant",
|
||||
"zh-gan": "gan",
|
||||
"zh-guoyu": "cmn",
|
||||
"zh-hakka": "hak",
|
||||
"zh-min": "zh-min",
|
||||
"zh-min-nan": "nan",
|
||||
"zh-wuu": "wuu",
|
||||
"zh-xiang": "hsn",
|
||||
"zh-yue": "yue",
|
||||
};
|
||||
|
||||
// Mappings from language subtags to preferred values.
|
||||
// Derived from IANA Language Subtag Registry, file date 2018-03-20.
|
||||
// Derived from IANA Language Subtag Registry, file date 2018-03-30.
|
||||
// https://www.iana.org/assignments/language-subtag-registry
|
||||
var languageMappings = {
|
||||
"aam": "aas",
|
||||
|
@ -143,7 +429,7 @@ var languageMappings = {
|
|||
};
|
||||
|
||||
// Mappings from region subtags to preferred values.
|
||||
// Derived from IANA Language Subtag Registry, file date 2018-03-20.
|
||||
// Derived from IANA Language Subtag Registry, file date 2018-03-30.
|
||||
// https://www.iana.org/assignments/language-subtag-registry
|
||||
var regionMappings = {
|
||||
"BU": "MM",
|
||||
|
@ -158,7 +444,7 @@ var regionMappings = {
|
|||
// All current deprecated extlang subtags have the form `<prefix>-<extlang>`
|
||||
// and their preferred value is exactly equal to `<extlang>`. So each key in
|
||||
// extlangMappings acts both as the extlang subtag and its preferred value.
|
||||
// Derived from IANA Language Subtag Registry, file date 2018-03-20.
|
||||
// Derived from IANA Language Subtag Registry, file date 2018-03-30.
|
||||
// https://www.iana.org/assignments/language-subtag-registry
|
||||
var extlangMappings = {
|
||||
"aao": "ar",
|
||||
|
|
|
@ -69,30 +69,34 @@ def readRegistryRecord(registry):
|
|||
yield record
|
||||
return
|
||||
|
||||
|
||||
def readRegistry(registry):
|
||||
""" Reads IANA Language Subtag Registry and extracts information for Intl.js.
|
||||
|
||||
Information extracted:
|
||||
- langTagMappings: mappings from complete language tags to preferred
|
||||
- grandfatheredMappings: mappings from grandfathered tags to preferred
|
||||
complete language tags
|
||||
- redundantMappings: mappings from redundant tags to preferred complete
|
||||
language tags
|
||||
- languageMappings: mappings from language subtags to preferred subtags
|
||||
- regionMappings: mappings from region subtags to preferred subtags
|
||||
- variantMappings: mappings from complete language tags to preferred
|
||||
complete language tags
|
||||
- extlangMappings: mappings from extlang subtags to preferred subtags,
|
||||
with prefix to be removed
|
||||
Returns these four mappings as dictionaries, along with the registry's
|
||||
Returns these six mappings as dictionaries, along with the registry's
|
||||
file date.
|
||||
|
||||
We also check that extlang mappings don't generate preferred values
|
||||
which in turn are subject to language subtag mappings, so that
|
||||
CanonicalizeLanguageTag can process subtags sequentially.
|
||||
"""
|
||||
langTagMappings = {}
|
||||
grandfatheredMappings = {}
|
||||
redundantMappings = {}
|
||||
languageMappings = {}
|
||||
regionMappings = {}
|
||||
variantMappings = {}
|
||||
extlangMappings = {}
|
||||
languageSubtags = set()
|
||||
extlangSubtags = set()
|
||||
extlangSubtags = []
|
||||
|
||||
for record in readRegistryRecord(registry):
|
||||
if "File-Date" in record:
|
||||
|
@ -103,23 +107,22 @@ def readRegistry(registry):
|
|||
# Grandfathered tags don't use standard syntax, so
|
||||
# CanonicalizeLanguageTag expects the mapping table to provide
|
||||
# the final form for all.
|
||||
# For langTagMappings, keys must be in lower case; values in
|
||||
# For grandfatheredMappings, keys must be in lower case; values in
|
||||
# the case used in the registry.
|
||||
tag = record["Tag"]
|
||||
if "Preferred-Value" in record:
|
||||
langTagMappings[tag.lower()] = record["Preferred-Value"]
|
||||
grandfatheredMappings[tag.lower()] = record["Preferred-Value"]
|
||||
else:
|
||||
langTagMappings[tag.lower()] = tag
|
||||
grandfatheredMappings[tag.lower()] = tag
|
||||
elif record["Type"] == "redundant":
|
||||
# For langTagMappings, keys must be in lower case; values in
|
||||
# the case used in the registry.
|
||||
# For redundantMappings, keys and values must be in the case used
|
||||
# in the registry.
|
||||
if "Preferred-Value" in record:
|
||||
langTagMappings[record["Tag"].lower()] = record["Preferred-Value"]
|
||||
redundantMappings[record["Tag"]] = record["Preferred-Value"]
|
||||
elif record["Type"] == "language":
|
||||
# For languageMappings, keys and values must be in the case used
|
||||
# in the registry.
|
||||
subtag = record["Subtag"]
|
||||
languageSubtags.add(subtag)
|
||||
if "Preferred-Value" in record:
|
||||
# The 'Prefix' field is not allowed for language records.
|
||||
# https://tools.ietf.org/html/rfc5646#section-3.1.2
|
||||
|
@ -139,21 +142,19 @@ def readRegistry(registry):
|
|||
# The registry currently doesn't contain mappings for scripts.
|
||||
raise Exception("Unexpected mapping for script subtags")
|
||||
elif record["Type"] == "variant":
|
||||
subtag = record["Subtag"]
|
||||
# For variantMappings, keys and values must be in the case used in
|
||||
# the registry.
|
||||
if "Preferred-Value" in record:
|
||||
if subtag == "heploc":
|
||||
# The entry for heploc is unique in its complexity; handle
|
||||
# it as special case below.
|
||||
continue
|
||||
# The registry currently doesn't contain mappings for variants,
|
||||
# except for heploc which is already handled above.
|
||||
raise Exception("Unexpected mapping for variant subtags")
|
||||
if "Prefix" not in record:
|
||||
raise Exception("Unexpected mapping for variant subtags")
|
||||
tag = "{}-{}".format(record["Prefix"], record["Subtag"])
|
||||
variantMappings[tag] = record["Preferred-Value"]
|
||||
elif record["Type"] == "extlang":
|
||||
# For extlangMappings, keys must be in the case used in the
|
||||
# registry; values are records with the preferred value and the
|
||||
# prefix to be removed.
|
||||
subtag = record["Subtag"]
|
||||
extlangSubtags.add(subtag)
|
||||
extlangSubtags.append(subtag)
|
||||
if "Preferred-Value" in record:
|
||||
preferred = record["Preferred-Value"]
|
||||
# The 'Preferred-Value' and 'Subtag' fields MUST be identical.
|
||||
|
@ -173,57 +174,349 @@ def readRegistry(registry):
|
|||
raise Exception("Conflict: extlang with lang mapping: " + extlang)
|
||||
|
||||
# Special case for heploc.
|
||||
langTagMappings["ja-latn-hepburn-heploc"] = "ja-Latn-alalc97"
|
||||
assert variantMappings["ja-Latn-hepburn-heploc"] == "alalc97"
|
||||
variantMappings["ja-Latn-hepburn-heploc"] = "ja-Latn-alalc97"
|
||||
|
||||
# ValidateAndCanonicalizeLanguageTag in CommonFunctions.js expects
|
||||
# langTagMappings contains no 2*3ALPHA.
|
||||
assert all(len(lang) > 3 for lang in langTagMappings.iterkeys())
|
||||
# redundantMappings contains no 2*3ALPHA.
|
||||
assert all(len(lang) > 3 for lang in redundantMappings.iterkeys())
|
||||
|
||||
return {"fileDate": fileDate,
|
||||
"langTagMappings": langTagMappings,
|
||||
"grandfatheredMappings": grandfatheredMappings,
|
||||
"redundantMappings": redundantMappings,
|
||||
"languageMappings": languageMappings,
|
||||
"regionMappings": regionMappings,
|
||||
"variantMappings": variantMappings,
|
||||
"extlangMappings": extlangMappings}
|
||||
|
||||
|
||||
def writeMappingsVar(intlData, dict, name, description, fileDate, url):
|
||||
""" Writes a variable definition with a mapping table to file intlData.
|
||||
|
||||
Writes the contents of dictionary dict to file intlData with the given
|
||||
variable name and a comment with description, fileDate, and URL.
|
||||
"""
|
||||
intlData.write("\n")
|
||||
def writeMappingHeader(println, description, fileDate, url):
|
||||
if type(description) is not list:
|
||||
description = [description]
|
||||
for desc in description:
|
||||
intlData.write("// {0}\n".format(desc))
|
||||
intlData.write("// Derived from IANA Language Subtag Registry, file date {0}.\n".format(fileDate))
|
||||
intlData.write("// {0}\n".format(url))
|
||||
intlData.write("var {0} = {{\n".format(name))
|
||||
keys = sorted(dict)
|
||||
for key in keys:
|
||||
if isinstance(dict[key], basestring):
|
||||
value = '"{0}"'.format(dict[key])
|
||||
println(u"// {0}".format(desc))
|
||||
println(u"// Derived from IANA Language Subtag Registry, file date {0}.".format(fileDate))
|
||||
println(u"// {0}".format(url))
|
||||
|
||||
def writeMappingsVar(println, mapping, name, description, fileDate, url):
|
||||
""" Writes a variable definition with a mapping table.
|
||||
|
||||
Writes the contents of dictionary |mapping| through the |println|
|
||||
function with the given variable name and a comment with description,
|
||||
fileDate, and URL.
|
||||
"""
|
||||
println(u"")
|
||||
writeMappingHeader(println, description, fileDate, url)
|
||||
println(u"var {0} = {{".format(name))
|
||||
for key in sorted(mapping):
|
||||
if isinstance(mapping[key], basestring):
|
||||
value = '"{0}"'.format(mapping[key])
|
||||
else:
|
||||
preferred = dict[key]["preferred"]
|
||||
prefix = dict[key]["prefix"]
|
||||
preferred = mapping[key]["preferred"]
|
||||
prefix = mapping[key]["prefix"]
|
||||
if key != preferred:
|
||||
raise Exception("Expected '{0}' matches preferred locale '{1}'".format(key, preferred))
|
||||
value = '"{0}"'.format(prefix)
|
||||
intlData.write(' "{0}": {1},\n'.format(key, value))
|
||||
intlData.write("};\n")
|
||||
println(u' "{0}": {1},'.format(key, value))
|
||||
println(u"};")
|
||||
|
||||
def writeMappingsFunction(println, variantMappings, redundantMappings, extlangMappings, description, fileDate, url):
|
||||
""" Writes a function definition which performs language tag mapping.
|
||||
|
||||
def writeLanguageTagData(intlData, fileDate, url, langTagMappings, languageMappings,
|
||||
regionMappings, extlangMappings):
|
||||
Processes the contents of dictionaries |variantMappings| and
|
||||
|redundantMappings| through the |println| function with the given
|
||||
function name and a comment with description, fileDate, and URL.
|
||||
"""
|
||||
|
||||
class Subtag:
|
||||
Language, ExtLang, Script, Region, Variant = range(5)
|
||||
Invalid = -1
|
||||
|
||||
def splitSubtags(tag):
|
||||
seenLanguage = False
|
||||
for subtag in tag.split("-"):
|
||||
# language = 2*3ALPHA / 4ALPHA / 5*8ALPHA
|
||||
if len(subtag) in range(2, 8+1) and subtag.isalpha() and not seenLanguage:
|
||||
seenLanguage = True
|
||||
kind = Subtag.Language
|
||||
|
||||
# extlang = 3ALPHA
|
||||
elif len(subtag) == 3 and subtag.isalpha() and seenLanguage:
|
||||
kind = Subtag.ExtLang
|
||||
|
||||
# script = 4ALPHA
|
||||
elif len(subtag) == 4 and subtag.isalpha():
|
||||
kind = Subtag.Script
|
||||
|
||||
# region = 2ALPHA / 3DIGIT
|
||||
elif ((len(subtag) == 2 and subtag.isalpha()) or
|
||||
(len(subtag) == 3 and subtag.isdigit())):
|
||||
kind = Subtag.Region
|
||||
|
||||
# variant = 5*8alphanum / (DIGIT 3alphanum)
|
||||
elif ((len(subtag) in range(5, 8+1) and subtag.isalnum()) or
|
||||
(len(subtag) == 4 and subtag[0].isdigit() and subtag[1:].isalnum())):
|
||||
kind = Subtag.Variant
|
||||
|
||||
else:
|
||||
assert False, "unexpected language tag '{}'".format(key)
|
||||
|
||||
yield (kind, subtag)
|
||||
|
||||
def language(tag):
|
||||
(kind, subtag) = next(splitSubtags(tag))
|
||||
assert kind == Subtag.Language
|
||||
return subtag
|
||||
|
||||
def variants(tag):
|
||||
return [v for (k, v) in splitSubtags(tag) if k == Subtag.Variant]
|
||||
|
||||
def emitCompare(tag, preferred, isFirstLanguageTag):
|
||||
def println_indent(level, *args):
|
||||
println(u" " * (4 * level - 1), *args)
|
||||
println2 = partial(println_indent, 2)
|
||||
println3 = partial(println_indent, 3)
|
||||
|
||||
def maybeNext(it):
|
||||
dummy = (Subtag.Invalid, "")
|
||||
return next(it, dummy)
|
||||
|
||||
# Add a comment for the language tag mapping.
|
||||
println2(u"// {} -> {}".format(tag, preferred))
|
||||
|
||||
# Compare the input language tag with the current language tag.
|
||||
cond = []
|
||||
extlangIndex = 1
|
||||
lastVariant = None
|
||||
for (kind, subtag) in splitSubtags(tag):
|
||||
if kind == Subtag.Language:
|
||||
continue
|
||||
|
||||
if kind == Subtag.ExtLang:
|
||||
assert extlangIndex in [1, 2, 3],\
|
||||
"Language-Tag permits no more than three extlang subtags"
|
||||
cond.append('tag.extlang{} === "{}"'.format(extlangIndex, subtag))
|
||||
extlangIndex += 1
|
||||
elif kind == Subtag.Script:
|
||||
cond.append('tag.script === "{}"'.format(subtag))
|
||||
elif kind == Subtag.Region:
|
||||
cond.append('tag.region === "{}"'.format(subtag))
|
||||
else:
|
||||
assert kind == Subtag.Variant
|
||||
if lastVariant is None:
|
||||
cond.append("tag.variants.length >= {}".format(len(variants(tag))))
|
||||
cond.append('callFunction(ArrayIndexOf, tag.variants, "{}") > -1'.format(subtag))
|
||||
else:
|
||||
cond.append('callFunction(ArrayIndexOf, tag.variants, "{}", callFunction(ArrayIndexOf, tag.variants, "{}") + 1) > -1'.format(subtag, lastVariant))
|
||||
lastVariant = subtag
|
||||
|
||||
# Require exact matches for redundant language tags.
|
||||
if tag in redundantMappings:
|
||||
tag_it = splitSubtags(tag)
|
||||
tag_next = partial(maybeNext, tag_it)
|
||||
(tag_kind, _) = tag_next()
|
||||
|
||||
assert tag_kind == Subtag.Language
|
||||
(tag_kind, _) = tag_next()
|
||||
|
||||
subtags = ([(Subtag.ExtLang, "extlang{}".format(i)) for i in range(1, 3+1)] +
|
||||
[(Subtag.Script, "script"), (Subtag.Region, "region")])
|
||||
for kind, prop_name in subtags:
|
||||
if tag_kind == kind:
|
||||
(tag_kind, _) = tag_next()
|
||||
else:
|
||||
cond.append("tag.{} === undefined".format(prop_name))
|
||||
|
||||
cond.append("tag.variants.length === {}".format(len(variants(tag))))
|
||||
while tag_kind == Subtag.Variant:
|
||||
(tag_kind, _) = tag_next()
|
||||
|
||||
cond.append("tag.extensions.length === 0")
|
||||
cond.append("tag.privateuse === undefined")
|
||||
assert list(tag_it) == [], "unhandled tag subtags"
|
||||
|
||||
# Emit either:
|
||||
#
|
||||
# if (cond) {
|
||||
#
|
||||
# or:
|
||||
#
|
||||
# if (cond_1 &&
|
||||
# cond_2 &&
|
||||
# ...
|
||||
# cond_n)
|
||||
# {
|
||||
#
|
||||
# depending on the number of conditions.
|
||||
ifOrElseIf = "if" if isFirstLanguageTag else "else if"
|
||||
assert len(cond) > 0, "expect at least one subtag condition"
|
||||
if len(cond) == 1:
|
||||
println2(u"{} ({}) {{".format(ifOrElseIf, cond[0]))
|
||||
else:
|
||||
println2(u"{} ({} &&".format(ifOrElseIf, cond[0]))
|
||||
for c in cond[1:-1]:
|
||||
println2(u"{}{} &&".format(" " * (len(ifOrElseIf) + 2), c))
|
||||
println2(u"{}{})".format(" " * (len(ifOrElseIf) + 2), cond[-1]))
|
||||
println2(u"{")
|
||||
|
||||
# Iterate over all subtags of |tag| and |preferred| and update |tag|
|
||||
# with |preferred| in the process. |tag| is modified in-place to use
|
||||
# the preferred values.
|
||||
tag_it = splitSubtags(tag)
|
||||
tag_next = partial(maybeNext, tag_it)
|
||||
(tag_kind, tag_subtag) = tag_next()
|
||||
|
||||
preferred_it = splitSubtags(preferred)
|
||||
preferred_next = partial(maybeNext, preferred_it)
|
||||
(preferred_kind, preferred_subtag) = preferred_next()
|
||||
|
||||
# Update the language subtag.
|
||||
assert tag_kind == Subtag.Language and preferred_kind == Subtag.Language
|
||||
if tag_subtag != preferred_subtag:
|
||||
println3(u'tag.language = "{}";'.format(preferred_subtag))
|
||||
(tag_kind, tag_subtag) = tag_next()
|
||||
(preferred_kind, preferred_subtag) = preferred_next()
|
||||
|
||||
# Remove any extlang subtags per RFC 5646, 4.5:
|
||||
# 'The canonical form contains no 'extlang' subtags.'
|
||||
# https://tools.ietf.org/html/rfc5646#section-4.5
|
||||
assert preferred_kind != Subtag.ExtLang
|
||||
extlangIndex = 1
|
||||
while tag_kind == Subtag.ExtLang:
|
||||
assert extlangIndex in [1, 2, 3],\
|
||||
"Language-Tag permits no more than three extlang subtags"
|
||||
println3(u"tag.extlang{} = undefined;".format(extlangIndex))
|
||||
extlangIndex += 1
|
||||
(tag_kind, tag_subtag) = tag_next()
|
||||
|
||||
# Update the script and region subtags.
|
||||
for kind, prop_name in [(Subtag.Script, "script"), (Subtag.Region, "region")]:
|
||||
if tag_kind == kind and preferred_kind == kind:
|
||||
if tag_subtag != preferred_subtag:
|
||||
println3(u'tag.{} = "{}";'.format(prop_name, preferred_subtag))
|
||||
(tag_kind, tag_subtag) = tag_next()
|
||||
(preferred_kind, preferred_subtag) = preferred_next()
|
||||
elif tag_kind == kind:
|
||||
println3(u"tag.{} = undefined;".format(prop_name))
|
||||
(tag_kind, tag_subtag) = tag_next()
|
||||
elif preferred_kind == kind:
|
||||
println3(u'tag.{} = "{}";'.format(prop_name, preferred_subtag))
|
||||
(preferred_kind, preferred_subtag) = preferred_next()
|
||||
|
||||
# Update variant subtags.
|
||||
if tag_kind == Subtag.Variant or preferred_kind == Subtag.Variant:
|
||||
# JS doesn't provide an easy way to remove elements from an array
|
||||
# which doesn't trigger Symbol.species, so we need to create a new
|
||||
# array and copy all elements.
|
||||
println3(u"var newVariants = [];")
|
||||
|
||||
# Copy all variant subtags, ignoring those which should be removed.
|
||||
println3(u"for (var i = 0; i < tag.variants.length; i++) {")
|
||||
println3(u" var variant = tag.variants[i];")
|
||||
while tag_kind == Subtag.Variant:
|
||||
println3(u' if (variant === "{}")'.format(tag_subtag))
|
||||
println3(u" continue;")
|
||||
(tag_kind, tag_subtag) = tag_next()
|
||||
println3(u" _DefineDataProperty(newVariants, newVariants.length, variant);")
|
||||
println3(u"}")
|
||||
|
||||
# Add the new variants, unless already present.
|
||||
while preferred_kind == Subtag.Variant:
|
||||
println3(u'if (callFunction(ArrayIndexOf, newVariants, "{}") < 0)'.format(preferred_subtag))
|
||||
println3(u' _DefineDataProperty(newVariants, newVariants.length, "{}");'.format(preferred_subtag))
|
||||
(preferred_kind, preferred_subtag) = preferred_next()
|
||||
|
||||
# Update the property.
|
||||
println3(u"tag.variants = newVariants;")
|
||||
|
||||
# Ensure both language tags were completely processed.
|
||||
assert list(tag_it) == [], "unhandled tag subtags"
|
||||
assert list(preferred_it) == [], "unhandled preferred subtags"
|
||||
|
||||
println2(u"}")
|
||||
|
||||
# Remove mappings for redundant language tags which are from our point of
|
||||
# view, wait for it, redundant, because there is an equivalent extlang
|
||||
# mapping.
|
||||
#
|
||||
# For example this entry for the redundant tag "zh-cmn":
|
||||
#
|
||||
# Type: redundant
|
||||
# Tag: zh-cmn
|
||||
# Preferred-Value: cmn
|
||||
#
|
||||
# Can also be expressed through the extlang mapping for "cmn":
|
||||
#
|
||||
# Type: extlang
|
||||
# Subtag: cmn
|
||||
# Preferred-Value: cmn
|
||||
# Prefix: zh
|
||||
#
|
||||
def hasExtlangMapping(tag, preferred):
|
||||
tag_it = splitSubtags(tag)
|
||||
(_, tag_lang) = next(tag_it)
|
||||
(tag_kind, tag_extlang) = next(tag_it)
|
||||
|
||||
preferred_it = splitSubtags(preferred)
|
||||
(_, preferred_lang) = next(preferred_it)
|
||||
|
||||
# Return true if the mapping is for an extlang language and the extlang
|
||||
# mapping table contains an equivalent entry and any trailing elements,
|
||||
# if present, are the same.
|
||||
return (tag_kind == Subtag.ExtLang and
|
||||
(tag_extlang, {"preferred": preferred_lang, "prefix": tag_lang}) in extlangMappings.items() and
|
||||
list(tag_it) == list(preferred_it))
|
||||
|
||||
# Create a single mapping for variant and redundant tags, ignoring the
|
||||
# entries which are also covered through extlang mappings.
|
||||
langTagMappings = {tag: preferred
|
||||
for mapping in [variantMappings, redundantMappings]
|
||||
for (tag, preferred) in mapping.items()
|
||||
if not hasExtlangMapping(tag, preferred)}
|
||||
|
||||
println(u"")
|
||||
println(u"/* eslint-disable complexity */")
|
||||
writeMappingHeader(println, description, fileDate, url)
|
||||
println(u"function updateLangTagMappings(tag) {")
|
||||
println(u' assert(IsObject(tag), "tag is an object");')
|
||||
println(u' assert(!hasOwn("grandfathered", tag), "tag is not a grandfathered tag");')
|
||||
println(u"")
|
||||
|
||||
# Switch on the language subtag.
|
||||
println(u" switch (tag.language) {")
|
||||
for lang in sorted(set(language(tag) for tag in langTagMappings)):
|
||||
println(u' case "{}":'.format(lang))
|
||||
isFirstLanguageTag = True
|
||||
for tag in sorted(tag for tag in langTagMappings if language(tag) == lang):
|
||||
assert not isinstance(langTagMappings[tag], dict),\
|
||||
"only supports complete language tags"
|
||||
emitCompare(tag, langTagMappings[tag], isFirstLanguageTag)
|
||||
isFirstLanguageTag = False
|
||||
println(u" break;")
|
||||
println(u" }")
|
||||
|
||||
println(u"}")
|
||||
println(u"/* eslint-enable complexity */")
|
||||
|
||||
def writeLanguageTagData(println, data, url):
|
||||
""" Writes the language tag data to the Intl data file. """
|
||||
writeMappingsVar(intlData, langTagMappings, "langTagMappings",
|
||||
"Mappings from complete tags to preferred values.", fileDate, url)
|
||||
writeMappingsVar(intlData, languageMappings, "languageMappings",
|
||||
|
||||
fileDate = data["fileDate"]
|
||||
grandfatheredMappings = data["grandfatheredMappings"]
|
||||
redundantMappings = data["redundantMappings"]
|
||||
languageMappings = data["languageMappings"]
|
||||
regionMappings = data["regionMappings"]
|
||||
variantMappings = data["variantMappings"]
|
||||
extlangMappings = data["extlangMappings"]
|
||||
|
||||
writeMappingsFunction(println, variantMappings, redundantMappings, extlangMappings,
|
||||
"Mappings from complete tags to preferred values.", fileDate, url)
|
||||
writeMappingsVar(println, grandfatheredMappings, "grandfatheredMappings",
|
||||
"Mappings from grandfathered tags to preferred values.", fileDate, url)
|
||||
writeMappingsVar(println, languageMappings, "languageMappings",
|
||||
"Mappings from language subtags to preferred values.", fileDate, url)
|
||||
writeMappingsVar(intlData, regionMappings, "regionMappings",
|
||||
writeMappingsVar(println, regionMappings, "regionMappings",
|
||||
"Mappings from region subtags to preferred values.", fileDate, url)
|
||||
writeMappingsVar(intlData, extlangMappings, "extlangMappings",
|
||||
writeMappingsVar(println, extlangMappings, "extlangMappings",
|
||||
["Mappings from extlang subtags to preferred values.",
|
||||
"All current deprecated extlang subtags have the form `<prefix>-<extlang>`",
|
||||
"and their preferred value is exactly equal to `<extlang>`. So each key in",
|
||||
|
@ -256,17 +549,13 @@ def updateLangTags(args):
|
|||
print("Processing IANA Language Subtag Registry...")
|
||||
with closing(registry) as reg:
|
||||
data = readRegistry(reg)
|
||||
fileDate = data["fileDate"]
|
||||
langTagMappings = data["langTagMappings"]
|
||||
languageMappings = data["languageMappings"]
|
||||
regionMappings = data["regionMappings"]
|
||||
extlangMappings = data["extlangMappings"]
|
||||
|
||||
print("Writing Intl data...")
|
||||
with codecs.open(out, "w", encoding="utf-8") as intlData:
|
||||
intlData.write("// Generated by make_intl_data.py. DO NOT EDIT.\n")
|
||||
writeLanguageTagData(intlData, fileDate, url, langTagMappings, languageMappings,
|
||||
regionMappings, extlangMappings)
|
||||
with io.open(out, mode="w", encoding="utf-8", newline="") as f:
|
||||
println = partial(print, file=f)
|
||||
|
||||
println(u"// Generated by make_intl_data.py. DO NOT EDIT.")
|
||||
writeLanguageTagData(println, data, url)
|
||||
|
||||
def flines(filepath, encoding="utf-8"):
|
||||
""" Open filepath and iterate over its content. """
|
||||
|
@ -746,11 +1035,11 @@ def processTimeZones(tzdataDir, icuDir, icuTzDir, version, ignoreBackzone, ignor
|
|||
|
||||
println(u"// Format:")
|
||||
println(u'// "LinkName", "Target" // ICU-Target [time zone file]')
|
||||
println(u"struct LinkAndTarget");
|
||||
println(u"{");
|
||||
println(u" const char* const link;");
|
||||
println(u" const char* const target;");
|
||||
println(u"};");
|
||||
println(u"struct LinkAndTarget")
|
||||
println(u"{")
|
||||
println(u" const char* const link;")
|
||||
println(u" const char* const target;")
|
||||
println(u"};")
|
||||
println(u"")
|
||||
println(u"const LinkAndTarget ianaLinksCanonicalizedDifferentlyByICU[] = {")
|
||||
for (zone, target, icuTarget) in incorrectLinks:
|
||||
|
|
|
@ -477,11 +477,8 @@ if use_minidump:
|
|||
# first failed status.
|
||||
results = []
|
||||
|
||||
# 'checks' is a superset of 'check-style'.
|
||||
if 'checks' in test_suites:
|
||||
results.append(run_test_command([MAKE, 'check']))
|
||||
elif 'check-style' in test_suites:
|
||||
results.append(run_test_command([MAKE, 'check-style']))
|
||||
|
||||
if 'jittest' in test_suites:
|
||||
results.append(run_test_command([MAKE, 'check-jit-test']))
|
||||
|
|
|
@ -3,8 +3,5 @@
|
|||
"debug": true,
|
||||
"skip-tests": {
|
||||
"all": ["jstests", "jittest", "checks"]
|
||||
},
|
||||
"extra-tests": {
|
||||
"all": ["check-style"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -244,15 +244,17 @@ GCRuntime::tryNewTenuredThing(JSContext* cx, AllocKind kind, size_t thingSize)
|
|||
// chunks available it may also allocate new memory directly.
|
||||
t = reinterpret_cast<T*>(refillFreeListFromAnyThread(cx, kind));
|
||||
|
||||
if (MOZ_UNLIKELY(!t && allowGC && !cx->helperThread())) {
|
||||
// We have no memory available for a new chunk; perform an
|
||||
// all-compartments, non-incremental, shrinking GC and wait for
|
||||
// sweeping to finish.
|
||||
JS::PrepareForFullGC(cx);
|
||||
cx->runtime()->gc.gc(GC_SHRINK, JS::gcreason::LAST_DITCH);
|
||||
cx->runtime()->gc.waitBackgroundSweepOrAllocEnd();
|
||||
if (MOZ_UNLIKELY(!t && allowGC)) {
|
||||
if (!cx->helperThread()) {
|
||||
// We have no memory available for a new chunk; perform an
|
||||
// all-compartments, non-incremental, shrinking GC and wait for
|
||||
// sweeping to finish.
|
||||
JS::PrepareForFullGC(cx);
|
||||
cx->runtime()->gc.gc(GC_SHRINK, JS::gcreason::LAST_DITCH);
|
||||
cx->runtime()->gc.waitBackgroundSweepOrAllocEnd();
|
||||
|
||||
t = tryNewTenuredThing<T, NoGC>(cx, kind, thingSize);
|
||||
t = tryNewTenuredThing<T, NoGC>(cx, kind, thingSize);
|
||||
}
|
||||
if (!t)
|
||||
ReportOutOfMemory(cx);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,10 @@ Zone * const Zone::NotOnList = reinterpret_cast<Zone*>(1);
|
|||
|
||||
JS::Zone::Zone(JSRuntime* rt)
|
||||
: JS::shadow::Zone(rt, &rt->gc.marker),
|
||||
// Note: don't use |this| before initializing helperThreadUse_!
|
||||
// ProtectedData checks in CheckZone::check may read this field.
|
||||
helperThreadUse_(HelperThreadUse::None),
|
||||
helperThreadOwnerContext_(nullptr),
|
||||
debuggers(this, nullptr),
|
||||
uniqueIds_(this),
|
||||
suppressAllocationMetadataBuilder(this, false),
|
||||
|
@ -54,8 +58,6 @@ JS::Zone::Zone(JSRuntime* rt)
|
|||
nurseryShapes_(this),
|
||||
data(this, nullptr),
|
||||
isSystem(this, false),
|
||||
helperThreadOwnerContext_(nullptr),
|
||||
helperThreadUse(HelperThreadUse::None),
|
||||
#ifdef DEBUG
|
||||
gcLastSweepGroupIndex(this, 0),
|
||||
#endif
|
||||
|
@ -78,7 +80,7 @@ JS::Zone::Zone(JSRuntime* rt)
|
|||
|
||||
Zone::~Zone()
|
||||
{
|
||||
MOZ_ASSERT(helperThreadUse == HelperThreadUse::None);
|
||||
MOZ_ASSERT(helperThreadUse_ == HelperThreadUse::None);
|
||||
|
||||
JSRuntime* rt = runtimeFromAnyThread();
|
||||
if (this == rt->gc.systemZone)
|
||||
|
|
|
@ -151,6 +151,44 @@ struct Zone : public JS::shadow::Zone,
|
|||
MOZ_MUST_USE bool init(bool isSystem);
|
||||
void destroy(js::FreeOp *fop);
|
||||
|
||||
private:
|
||||
enum class HelperThreadUse : uint32_t {
|
||||
None,
|
||||
Pending,
|
||||
Active
|
||||
};
|
||||
mozilla::Atomic<HelperThreadUse> helperThreadUse_;
|
||||
|
||||
// The helper thread context with exclusive access to this zone, if
|
||||
// usedByHelperThread(), or nullptr when on the main thread.
|
||||
js::UnprotectedData<JSContext*> helperThreadOwnerContext_;
|
||||
|
||||
public:
|
||||
bool ownedByCurrentHelperThread();
|
||||
void setHelperThreadOwnerContext(JSContext* cx);
|
||||
|
||||
// Whether this zone was created for use by a helper thread.
|
||||
bool createdForHelperThread() const {
|
||||
return helperThreadUse_ != HelperThreadUse::None;
|
||||
}
|
||||
// Whether this zone is currently in use by a helper thread.
|
||||
bool usedByHelperThread() {
|
||||
MOZ_ASSERT_IF(isAtomsZone(), helperThreadUse_ == HelperThreadUse::None);
|
||||
return helperThreadUse_ == HelperThreadUse::Active;
|
||||
}
|
||||
void setCreatedForHelperThread() {
|
||||
MOZ_ASSERT(helperThreadUse_ == HelperThreadUse::None);
|
||||
helperThreadUse_ = HelperThreadUse::Pending;
|
||||
}
|
||||
void setUsedByHelperThread() {
|
||||
MOZ_ASSERT(helperThreadUse_ == HelperThreadUse::Pending);
|
||||
helperThreadUse_ = HelperThreadUse::Active;
|
||||
}
|
||||
void clearUsedByHelperThread() {
|
||||
MOZ_ASSERT(helperThreadUse_ != HelperThreadUse::None);
|
||||
helperThreadUse_ = HelperThreadUse::None;
|
||||
}
|
||||
|
||||
void findOutgoingEdges(js::gc::ZoneComponentFinder& finder);
|
||||
|
||||
void discardJitCode(js::FreeOp* fop, bool discardBaselineCode = true);
|
||||
|
@ -513,48 +551,6 @@ struct Zone : public JS::shadow::Zone,
|
|||
|
||||
js::ZoneData<bool> isSystem;
|
||||
|
||||
private:
|
||||
// The helper thread context with exclusive access to this zone, if
|
||||
// usedByHelperThread(), or nullptr when on the main thread.
|
||||
js::UnprotectedData<JSContext*> helperThreadOwnerContext_;
|
||||
|
||||
public:
|
||||
bool ownedByCurrentHelperThread();
|
||||
void setHelperThreadOwnerContext(JSContext* cx);
|
||||
|
||||
private:
|
||||
enum class HelperThreadUse : uint32_t
|
||||
{
|
||||
None,
|
||||
Pending,
|
||||
Active
|
||||
};
|
||||
|
||||
mozilla::Atomic<HelperThreadUse> helperThreadUse;
|
||||
|
||||
public:
|
||||
// Whether this zone was created for use by a helper thread.
|
||||
bool createdForHelperThread() const {
|
||||
return helperThreadUse != HelperThreadUse::None;
|
||||
}
|
||||
// Whether this zone is currently in use by a helper thread.
|
||||
bool usedByHelperThread() {
|
||||
MOZ_ASSERT_IF(isAtomsZone(), helperThreadUse == HelperThreadUse::None);
|
||||
return helperThreadUse == HelperThreadUse::Active;
|
||||
}
|
||||
void setCreatedForHelperThread() {
|
||||
MOZ_ASSERT(helperThreadUse == HelperThreadUse::None);
|
||||
helperThreadUse = HelperThreadUse::Pending;
|
||||
}
|
||||
void setUsedByHelperThread() {
|
||||
MOZ_ASSERT(helperThreadUse == HelperThreadUse::Pending);
|
||||
helperThreadUse = HelperThreadUse::Active;
|
||||
}
|
||||
void clearUsedByHelperThread() {
|
||||
MOZ_ASSERT(helperThreadUse != HelperThreadUse::None);
|
||||
helperThreadUse = HelperThreadUse::None;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
js::ZoneData<unsigned> gcLastSweepGroupIndex;
|
||||
#endif
|
||||
|
|
|
@ -330,7 +330,7 @@ MacroAssemblerMIPS64::ma_dror(Register rd, Register rt, Register shift)
|
|||
void
|
||||
MacroAssemblerMIPS64::ma_drol(Register rd, Register rt, Register shift)
|
||||
{
|
||||
ma_negu(ScratchRegister, shift);
|
||||
as_dsubu(ScratchRegister, zero, shift);
|
||||
as_drotrv(rd, rt, ScratchRegister);
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "mozilla/MathAlgorithms.h"
|
||||
|
||||
#include <float.h>
|
||||
#include <limits>
|
||||
|
||||
#include "jit/AtomicOperations.h"
|
||||
#include "jit/mips64/Assembler-mips64.h"
|
||||
|
@ -1557,6 +1558,7 @@ Simulator::testFCSRBit(uint32_t cc)
|
|||
|
||||
// Sets the rounding error codes in FCSR based on the result of the rounding.
|
||||
// Returns true if the operation was invalid.
|
||||
template <typename T>
|
||||
bool
|
||||
Simulator::setFCSRRoundError(double original, double rounded)
|
||||
{
|
||||
|
@ -1584,7 +1586,9 @@ Simulator::setFCSRRoundError(double original, double rounded)
|
|||
ret = true;
|
||||
}
|
||||
|
||||
if (rounded > INT_MAX || rounded < INT_MIN) {
|
||||
if ((long double)rounded > (long double)std::numeric_limits<T>::max() ||
|
||||
(long double)rounded < (long double)std::numeric_limits<T>::min())
|
||||
{
|
||||
setFCSRBit(kFCSROverflowFlagBit, true);
|
||||
setFCSRBit(kFCSROverflowCauseBit, true);
|
||||
// The reference is not really clear but it seems this is required:
|
||||
|
@ -2115,19 +2119,19 @@ typedef int32_t (*Prototype_Int_GeneralGeneralInt64Int64)(int64_t arg0, int64_t
|
|||
int64_t arg3);
|
||||
typedef double (*Prototype_Double_None)();
|
||||
typedef double (*Prototype_Double_Double)(double arg0);
|
||||
typedef double (*Prototype_Double_Int)(int32_t arg0);
|
||||
typedef int32_t (*Prototype_Int_Double)(double arg0);
|
||||
typedef int32_t (*Prototype_Int_DoubleIntInt)(double arg0, int32_t arg1, int32_t arg2);
|
||||
typedef int32_t (*Prototype_Int_IntDoubleIntInt)(int32_t arg0, double arg1, int32_t arg2,
|
||||
int32_t arg3);
|
||||
typedef double (*Prototype_Double_Int)(int64_t arg0);
|
||||
typedef int64_t (*Prototype_Int_Double)(double arg0);
|
||||
typedef int64_t (*Prototype_Int_DoubleIntInt)(double arg0, int64_t arg1, int64_t arg2);
|
||||
typedef int64_t (*Prototype_Int_IntDoubleIntInt)(int64_t arg0, double arg1, int64_t arg2,
|
||||
int64_t arg3);
|
||||
typedef float (*Prototype_Float32_Float32)(float arg0);
|
||||
typedef float (*Prototype_Float32_Float32Float32)(float arg0, float arg1);
|
||||
typedef float (*Prototype_Float32_IntInt)(int32_t arg0, int32_t arg1);
|
||||
typedef float (*Prototype_Float32_IntInt)(int64_t arg0, int64_t arg1);
|
||||
|
||||
typedef double (*Prototype_Double_DoubleInt)(double arg0, int32_t arg1);
|
||||
typedef double (*Prototype_Double_IntDouble)(int32_t arg0, double arg1);
|
||||
typedef double (*Prototype_Double_DoubleInt)(double arg0, int64_t arg1);
|
||||
typedef double (*Prototype_Double_IntDouble)(int64_t arg0, double arg1);
|
||||
typedef double (*Prototype_Double_DoubleDouble)(double arg0, double arg1);
|
||||
typedef int32_t (*Prototype_Int_IntDouble)(int32_t arg0, double arg1);
|
||||
typedef int64_t (*Prototype_Int_IntDouble)(int64_t arg0, double arg1);
|
||||
|
||||
typedef double (*Prototype_Double_DoubleDoubleDouble)(double arg0, double arg1, double arg2);
|
||||
typedef double (*Prototype_Double_DoubleDoubleDoubleDouble)(double arg0, double arg1,
|
||||
|
@ -2190,9 +2194,8 @@ Simulator::softwareInterrupt(SimInstruction* instr)
|
|||
case Args_General3: {
|
||||
Prototype_General3 target = reinterpret_cast<Prototype_General3>(external);
|
||||
int64_t result = target(arg0, arg1, arg2);
|
||||
if(external == intptr_t(&js::wasm::Instance::wake)) {
|
||||
if (external == intptr_t(&js::wasm::Instance::wake))
|
||||
result = int32_t(result);
|
||||
}
|
||||
setCallResult(result);
|
||||
break;
|
||||
}
|
||||
|
@ -2238,36 +2241,42 @@ Simulator::softwareInterrupt(SimInstruction* instr)
|
|||
case Args_Int_Double: {
|
||||
double dval0 = getFpuRegisterDouble(12);
|
||||
Prototype_Int_Double target = reinterpret_cast<Prototype_Int_Double>(external);
|
||||
int32_t res = target(dval0);
|
||||
setRegister(v0, res);
|
||||
int64_t result = target(dval0);
|
||||
if (external == intptr_t((int32_t(*)(double))JS::ToInt32))
|
||||
result = int32_t(result);
|
||||
setRegister(v0, result);
|
||||
break;
|
||||
}
|
||||
case Args_Int_GeneralGeneralGeneralInt64: {
|
||||
Prototype_Int_GeneralGeneralGeneralInt64 target =
|
||||
reinterpret_cast<Prototype_Int_GeneralGeneralGeneralInt64>(external);
|
||||
int32_t res = target(arg0, arg1, arg2, arg3);
|
||||
setRegister(v0, res);
|
||||
int64_t result = target(arg0, arg1, arg2, arg3);
|
||||
if (external == intptr_t(&js::wasm::Instance::wait_i32))
|
||||
result = int32_t(result);
|
||||
setRegister(v0, result);
|
||||
break;
|
||||
}
|
||||
case Args_Int_GeneralGeneralInt64Int64: {
|
||||
Prototype_Int_GeneralGeneralInt64Int64 target =
|
||||
reinterpret_cast<Prototype_Int_GeneralGeneralInt64Int64>(external);
|
||||
int32_t res = target(arg0, arg1, arg2, arg3);
|
||||
setRegister(v0, res);
|
||||
int64_t result = target(arg0, arg1, arg2, arg3);
|
||||
if (external == intptr_t(&js::wasm::Instance::wait_i64))
|
||||
result = int32_t(result);
|
||||
setRegister(v0, result);
|
||||
break;
|
||||
}
|
||||
case Args_Int_DoubleIntInt: {
|
||||
double dval = getFpuRegisterDouble(12);
|
||||
Prototype_Int_DoubleIntInt target = reinterpret_cast<Prototype_Int_DoubleIntInt>(external);
|
||||
int32_t res = target(dval, int32_t(arg1), int32_t(arg2));
|
||||
setRegister(v0, res);
|
||||
int64_t result = target(dval, arg1, arg2);
|
||||
setRegister(v0, result);
|
||||
break;
|
||||
}
|
||||
case Args_Int_IntDoubleIntInt: {
|
||||
double dval = getFpuRegisterDouble(13);
|
||||
Prototype_Int_IntDoubleIntInt target = reinterpret_cast<Prototype_Int_IntDoubleIntInt>(external);
|
||||
int32_t res = target(int32_t(arg0), dval, int32_t(arg2), int32_t(arg3));
|
||||
setRegister(v0, res);
|
||||
int64_t result = target(arg0, dval, arg2, arg3);
|
||||
setRegister(v0, result);
|
||||
break;
|
||||
}
|
||||
case Args_Double_Double: {
|
||||
|
@ -2297,20 +2306,20 @@ Simulator::softwareInterrupt(SimInstruction* instr)
|
|||
}
|
||||
case Args_Float32_IntInt: {
|
||||
Prototype_Float32_IntInt target = reinterpret_cast<Prototype_Float32_IntInt>(external);
|
||||
float fresult = target(int32_t(arg0), int32_t(arg1));
|
||||
float fresult = target(arg0, arg1);
|
||||
setCallResultFloat(fresult);
|
||||
break;
|
||||
}
|
||||
case Args_Double_Int: {
|
||||
Prototype_Double_Int target = reinterpret_cast<Prototype_Double_Int>(external);
|
||||
double dresult = target(int32_t(arg0));
|
||||
double dresult = target(arg0);
|
||||
setCallResultDouble(dresult);
|
||||
break;
|
||||
}
|
||||
case Args_Double_DoubleInt: {
|
||||
double dval0 = getFpuRegisterDouble(12);
|
||||
Prototype_Double_DoubleInt target = reinterpret_cast<Prototype_Double_DoubleInt>(external);
|
||||
double dresult = target(dval0, int32_t(arg1));
|
||||
double dresult = target(dval0, arg1);
|
||||
setCallResultDouble(dresult);
|
||||
break;
|
||||
}
|
||||
|
@ -2325,14 +2334,14 @@ Simulator::softwareInterrupt(SimInstruction* instr)
|
|||
case Args_Double_IntDouble: {
|
||||
double dval1 = getFpuRegisterDouble(13);
|
||||
Prototype_Double_IntDouble target = reinterpret_cast<Prototype_Double_IntDouble>(external);
|
||||
double dresult = target(int32_t(arg0), dval1);
|
||||
double dresult = target(arg0, dval1);
|
||||
setCallResultDouble(dresult);
|
||||
break;
|
||||
}
|
||||
case Args_Int_IntDouble: {
|
||||
double dval1 = getFpuRegisterDouble(13);
|
||||
Prototype_Int_IntDouble target = reinterpret_cast<Prototype_Int_IntDouble>(external);
|
||||
int32_t result = target(int32_t(arg0), dval1);
|
||||
int64_t result = target(arg0, dval1);
|
||||
setRegister(v0, result);
|
||||
break;
|
||||
}
|
||||
|
@ -2730,7 +2739,7 @@ Simulator::configureTypeRegister(SimInstruction* instr,
|
|||
alu_out = ~(rs | rt);
|
||||
break;
|
||||
case ff_slt:
|
||||
alu_out = I32_CHECK(rs) < I32_CHECK(rt) ? 1 : 0;
|
||||
alu_out = I64(rs) < I64(rt) ? 1 : 0;
|
||||
break;
|
||||
case ff_sltu:
|
||||
alu_out = U64(rs) < U64(rt) ? 1 : 0;
|
||||
|
@ -2774,7 +2783,7 @@ Simulator::configureTypeRegister(SimInstruction* instr,
|
|||
}
|
||||
break;
|
||||
case ff_ddiv:
|
||||
if (I32_CHECK(rs) == INT_MIN && I32_CHECK(rt) == -1) {
|
||||
if (I64(rs) == INT64_MIN && I64(rt) == -1) {
|
||||
i128hilo = U64(INT64_MIN);
|
||||
} else {
|
||||
uint64_t div = rs / rt;
|
||||
|
@ -3086,65 +3095,72 @@ Simulator::decodeTypeRegister(SimInstruction* instr)
|
|||
result--;
|
||||
}
|
||||
setFpuRegisterLo(fd_reg, result);
|
||||
if (setFCSRRoundError(fs_value, rounded)) {
|
||||
if (setFCSRRoundError<int32_t>(fs_value, rounded))
|
||||
setFpuRegisterLo(fd_reg, kFPUInvalidResult);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ff_trunc_w_fmt: { // Truncate float to word (round towards 0).
|
||||
float rounded = truncf(fs_value);
|
||||
int32_t result = I32(rounded);
|
||||
setFpuRegisterLo(fd_reg, result);
|
||||
if (setFCSRRoundError(fs_value, rounded)) {
|
||||
if (setFCSRRoundError<int32_t>(fs_value, rounded))
|
||||
setFpuRegisterLo(fd_reg, kFPUInvalidResult);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ff_floor_w_fmt: { // Round float to word towards negative infinity.
|
||||
float rounded = std::floor(fs_value);
|
||||
int32_t result = I32(rounded);
|
||||
setFpuRegisterLo(fd_reg, result);
|
||||
if (setFCSRRoundError(fs_value, rounded)) {
|
||||
if (setFCSRRoundError<int32_t>(fs_value, rounded))
|
||||
setFpuRegisterLo(fd_reg, kFPUInvalidResult);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ff_ceil_w_fmt: { // Round double to word towards positive infinity.
|
||||
float rounded = std::ceil(fs_value);
|
||||
int32_t result = I32(rounded);
|
||||
setFpuRegisterLo(fd_reg, result);
|
||||
if (setFCSRRoundError(fs_value, rounded)) {
|
||||
if (setFCSRRoundError<int32_t>(fs_value, rounded))
|
||||
setFpuRegisterLo(fd_reg, kFPUInvalidResult);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ff_cvt_l_fmt: { // Mips64r2: Truncate float to 64-bit long-word.
|
||||
float rounded = truncf(fs_value);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
break;
|
||||
}
|
||||
case ff_cvt_l_fmt: // Mips64r2: Truncate float to 64-bit long-word.
|
||||
// Rounding modes are not yet supported.
|
||||
MOZ_ASSERT((FCSR_ & 3) == 0);
|
||||
// In rounding mode 0 it should behave like ROUND.
|
||||
MOZ_FALLTHROUGH;
|
||||
case ff_round_l_fmt: { // Mips64r2 instruction.
|
||||
float rounded =
|
||||
fs_value > 0 ? std::floor(fs_value + 0.5) : std::ceil(fs_value - 0.5);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
if (setFCSRRoundError<int64_t>(fs_value, rounded))
|
||||
setFpuRegister(fd_reg, kFPUInvalidResult64);
|
||||
break;
|
||||
}
|
||||
case ff_trunc_l_fmt: { // Mips64r2 instruction.
|
||||
float rounded = truncf(fs_value);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
if (setFCSRRoundError<int64_t>(fs_value, rounded))
|
||||
setFpuRegister(fd_reg, kFPUInvalidResult64);
|
||||
break;
|
||||
}
|
||||
case ff_floor_l_fmt: // Mips64r2 instruction.
|
||||
i64 = I64(std::floor(fs_value));
|
||||
case ff_floor_l_fmt: { // Mips64r2 instruction.
|
||||
float rounded = std::floor(fs_value);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
if (setFCSRRoundError<int64_t>(fs_value, rounded))
|
||||
setFpuRegister(fd_reg, kFPUInvalidResult64);
|
||||
break;
|
||||
case ff_ceil_l_fmt: // Mips64r2 instruction.
|
||||
i64 = I64(std::ceil(fs_value));
|
||||
}
|
||||
case ff_ceil_l_fmt: { // Mips64r2 instruction.
|
||||
float rounded = std::ceil(fs_value);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
if (setFCSRRoundError<int64_t>(fs_value, rounded))
|
||||
setFpuRegister(fd_reg, kFPUInvalidResult64);
|
||||
break;
|
||||
}
|
||||
case ff_cvt_ps_s:
|
||||
case ff_c_f_fmt:
|
||||
MOZ_CRASH();
|
||||
|
@ -3237,7 +3253,7 @@ Simulator::decodeTypeRegister(SimInstruction* instr)
|
|||
result--;
|
||||
}
|
||||
setFpuRegisterLo(fd_reg, result);
|
||||
if (setFCSRRoundError(ds_value, rounded))
|
||||
if (setFCSRRoundError<int32_t>(ds_value, rounded))
|
||||
setFpuRegisterLo(fd_reg, kFPUInvalidResult);
|
||||
break;
|
||||
}
|
||||
|
@ -3245,7 +3261,7 @@ Simulator::decodeTypeRegister(SimInstruction* instr)
|
|||
double rounded = trunc(ds_value);
|
||||
int32_t result = I32(rounded);
|
||||
setFpuRegisterLo(fd_reg, result);
|
||||
if (setFCSRRoundError(ds_value, rounded))
|
||||
if (setFCSRRoundError<int32_t>(ds_value, rounded))
|
||||
setFpuRegisterLo(fd_reg, kFPUInvalidResult);
|
||||
break;
|
||||
}
|
||||
|
@ -3253,7 +3269,7 @@ Simulator::decodeTypeRegister(SimInstruction* instr)
|
|||
double rounded = std::floor(ds_value);
|
||||
int32_t result = I32(rounded);
|
||||
setFpuRegisterLo(fd_reg, result);
|
||||
if (setFCSRRoundError(ds_value, rounded))
|
||||
if (setFCSRRoundError<int32_t>(ds_value, rounded))
|
||||
setFpuRegisterLo(fd_reg, kFPUInvalidResult);
|
||||
break;
|
||||
}
|
||||
|
@ -3261,40 +3277,51 @@ Simulator::decodeTypeRegister(SimInstruction* instr)
|
|||
double rounded = std::ceil(ds_value);
|
||||
int32_t result = I32(rounded);
|
||||
setFpuRegisterLo(fd_reg, result);
|
||||
if (setFCSRRoundError(ds_value, rounded))
|
||||
if (setFCSRRoundError<int32_t>(ds_value, rounded))
|
||||
setFpuRegisterLo(fd_reg, kFPUInvalidResult);
|
||||
break;
|
||||
}
|
||||
case ff_cvt_s_fmt: // Convert double to float (single).
|
||||
setFpuRegisterFloat(fd_reg, static_cast<float>(ds_value));
|
||||
break;
|
||||
case ff_cvt_l_fmt: { // Mips64r2: Truncate double to 64-bit long-word.
|
||||
double rounded = trunc(ds_value);
|
||||
case ff_cvt_l_fmt: // Mips64r2: Truncate double to 64-bit long-word.
|
||||
// Rounding modes are not yet supported.
|
||||
MOZ_ASSERT((FCSR_ & 3) == 0);
|
||||
// In rounding mode 0 it should behave like ROUND.
|
||||
MOZ_FALLTHROUGH;
|
||||
case ff_round_l_fmt: { // Mips64r2 instruction.
|
||||
double rounded =
|
||||
ds_value > 0 ? std::floor(ds_value + 0.5) : std::ceil(ds_value - 0.5);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
if (setFCSRRoundError<int64_t>(ds_value, rounded))
|
||||
setFpuRegister(fd_reg, kFPUInvalidResult64);
|
||||
break;
|
||||
}
|
||||
case ff_trunc_l_fmt: { // Mips64r2 instruction.
|
||||
double rounded = trunc(ds_value);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
if (setFCSRRoundError<int64_t>(ds_value, rounded))
|
||||
setFpuRegister(fd_reg, kFPUInvalidResult64);
|
||||
break;
|
||||
}
|
||||
case ff_round_l_fmt: { // Mips64r2 instruction.
|
||||
double rounded =
|
||||
ds_value > 0 ? std::floor(ds_value + 0.5) : std::ceil(ds_value - 0.5);
|
||||
case ff_floor_l_fmt: { // Mips64r2 instruction.
|
||||
double rounded = std::floor(ds_value);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
if (setFCSRRoundError<int64_t>(ds_value, rounded))
|
||||
setFpuRegister(fd_reg, kFPUInvalidResult64);
|
||||
break;
|
||||
}
|
||||
case ff_floor_l_fmt: // Mips64r2 instruction.
|
||||
i64 = I64(std::floor(ds_value));
|
||||
setFpuRegister(fd_reg, i64);
|
||||
break;
|
||||
case ff_ceil_l_fmt: // Mips64r2 instruction.
|
||||
i64 = I64(std::ceil(ds_value));
|
||||
case ff_ceil_l_fmt: { // Mips64r2 instruction.
|
||||
double rounded = std::ceil(ds_value);
|
||||
i64 = I64(rounded);
|
||||
setFpuRegister(fd_reg, i64);
|
||||
if (setFCSRRoundError<int64_t>(ds_value, rounded))
|
||||
setFpuRegister(fd_reg, kFPUInvalidResult64);
|
||||
break;
|
||||
}
|
||||
case ff_c_f_fmt:
|
||||
MOZ_CRASH();
|
||||
break;
|
||||
|
|
|
@ -75,6 +75,7 @@ const int kNumFPURegisters = 32;
|
|||
const int kFCSRRegister = 31;
|
||||
const int kInvalidFPUControlRegister = -1;
|
||||
const uint32_t kFPUInvalidResult = static_cast<uint32_t>(1 << 31) - 1;
|
||||
const uint64_t kFPUInvalidResult64 = static_cast<uint64_t>(1ULL << 63) - 1;
|
||||
|
||||
// FCSR constants.
|
||||
const uint32_t kFCSRInexactFlagBit = 2;
|
||||
|
@ -197,6 +198,7 @@ class Simulator {
|
|||
double getFpuRegisterDouble(int fpureg) const;
|
||||
void setFCSRBit(uint32_t cc, bool value);
|
||||
bool testFCSRBit(uint32_t cc);
|
||||
template <typename T>
|
||||
bool setFCSRRoundError(double original, double rounded);
|
||||
|
||||
// Special case of set_register and get_register to access the raw PC value.
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
// |reftest| skip-if(!this.hasOwnProperty("Intl"))
|
||||
|
||||
const languageTags = {
|
||||
// The preferred value of "hy-arevela" is "hy".
|
||||
"hy-arevela": "hy",
|
||||
"hy-Armn-arevela": "hy-Armn",
|
||||
"hy-AM-arevela": "hy-AM",
|
||||
"hy-arevela-fonipa": "hy-fonipa",
|
||||
"hy-fonipa-arevela": "hy-fonipa",
|
||||
|
||||
// The preferred value of "hy-arevmda" is "hyw".
|
||||
"hy-arevmda": "hyw",
|
||||
"hy-Armn-arevmda": "hyw-Armn",
|
||||
"hy-AM-arevmda": "hyw-AM",
|
||||
"hy-arevmda-fonipa": "hyw-fonipa",
|
||||
"hy-fonipa-arevmda": "hyw-fonipa",
|
||||
|
||||
// The preferred value of "ja-Latn-hepburn-heploc" is "ja-Latn-alalc97".
|
||||
"ja-Latn-hepburn-heploc": "ja-Latn-alalc97",
|
||||
"ja-Latn-JP-hepburn-heploc": "ja-Latn-JP-alalc97",
|
||||
|
||||
// Ensure we don't emit "alalc97" when it is already present.
|
||||
"ja-Latn-alalc97-hepburn-heploc": "ja-Latn-alalc97",
|
||||
"ja-Latn-hepburn-alalc97-heploc": "ja-Latn-alalc97",
|
||||
"ja-Latn-hepburn-heploc-alalc97": "ja-Latn-alalc97",
|
||||
|
||||
// No replacement when "heploc" appears before "hepburn".
|
||||
"ja-Latn-heploc-hepburn": "ja-Latn-heploc-hepburn",
|
||||
};
|
||||
|
||||
for (let [tag, canonical] of Object.entries(languageTags)) {
|
||||
assertEq(Intl.getCanonicalLocales(tag)[0], canonical);
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
|
@ -1669,6 +1669,7 @@ GlobalHelperThreadState::finishParseTask(JSContext* cx, ParseTaskKind kind, void
|
|||
if (!script) {
|
||||
// No error was reported, but no script produced. Assume we hit out of
|
||||
// memory.
|
||||
MOZ_DIAGNOSTIC_ASSERT(false);
|
||||
ReportOutOfMemory(cx);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1705,6 +1706,7 @@ GlobalHelperThreadState::finishParseTask(JSContext* cx, ParseTaskKind kind, void
|
|||
if (scripts.length() != expectedLength) {
|
||||
// No error was reported, but fewer scripts produced than expected.
|
||||
// Assume we hit out of memory.
|
||||
MOZ_DIAGNOSTIC_ASSERT(false);
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -2460,7 +2460,7 @@ pref("security.csp.experimentalEnabled", false);
|
|||
pref("security.csp.enableStrictDynamic", true);
|
||||
|
||||
#if defined(DEBUG) && !defined(ANDROID)
|
||||
pref("csp.content_privileged_about_uris_without_csp", "blank,cache,certerror,credits,home,logo,neterror,newtab,printpreview,srcdoc,studies");
|
||||
pref("csp.content_privileged_about_uris_without_csp", "blank,cache,credits,home,logo,newtab,printpreview,srcdoc,studies");
|
||||
#endif
|
||||
|
||||
#ifdef NIGHTLY_BUILD
|
||||
|
|
|
@ -13,6 +13,7 @@ cd "$SRCDIR/js/src"
|
|||
|
||||
export PATH="$PATH:$TOOLTOOL_CHECKOUT/cargo/bin:$TOOLTOOL_CHECKOUT/rustc/bin"
|
||||
export RUST_BACKTRACE=1
|
||||
export AUTOMATION=1
|
||||
|
||||
cargo build --verbose --frozen --features debugmozjs
|
||||
cargo build --verbose --frozen
|
||||
|
|
|
@ -308,18 +308,6 @@ class CheckSpiderMonkeyCommand(MachCommandBase):
|
|||
self.bindir, executable_name('jsapi-tests'))]
|
||||
jsapi_tests_result = subprocess.call(jsapi_tests_cmd)
|
||||
|
||||
print('running check-style')
|
||||
check_style_cmd = [python, os.path.join(
|
||||
self.topsrcdir, 'config', 'check_spidermonkey_style.py')]
|
||||
check_style_result = subprocess.call(
|
||||
check_style_cmd, cwd=self.topsrcdir)
|
||||
|
||||
print('running check-masm')
|
||||
check_masm_cmd = [python, os.path.join(
|
||||
self.topsrcdir, 'config', 'check_macroassembler_style.py')]
|
||||
check_masm_result = subprocess.call(
|
||||
check_masm_cmd, cwd=self.topsrcdir)
|
||||
|
||||
print('running check-js-msg-encoding')
|
||||
check_js_msg_cmd = [python, os.path.join(
|
||||
self.topsrcdir, 'config', 'check_js_msg_encoding.py')]
|
||||
|
@ -327,7 +315,7 @@ class CheckSpiderMonkeyCommand(MachCommandBase):
|
|||
check_js_msg_cmd, cwd=self.topsrcdir)
|
||||
|
||||
all_passed = jittest_result and jstest_result and jsapi_tests_result and \
|
||||
check_style_result and check_masm_result and check_js_msg_result
|
||||
check_js_msg_result
|
||||
|
||||
return all_passed
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
[hkdf.https.worker.html]
|
||||
disabled:
|
||||
if ccov and (os == "win"): https://bugzilla.mozilla.org/show_bug.cgi?id=1434754
|
||||
|
||||
[short derivedKey, normal salt, SHA-384, with normal info with 0 length]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[DOMRectList.html]
|
||||
[DOMRectList [NoInterfaceObject\]]
|
||||
expected: FAIL
|
||||
|
|
@ -10,12 +10,12 @@ setup(() => {
|
|||
});
|
||||
|
||||
test(() => {
|
||||
assert_false('DOMRectList' in window);
|
||||
}, 'DOMRectList [NoInterfaceObject]');
|
||||
assert_true('DOMRectList' in window);
|
||||
}, 'DOMRectList is not [NoInterfaceObject]');
|
||||
|
||||
test(() => {
|
||||
assert_true(domRectList instanceof Array);
|
||||
}, 'DOMRectList [LegacyArrayClass]');
|
||||
assert_false(domRectList instanceof Array);
|
||||
}, 'DOMRectList is not [LegacyArrayClass]');
|
||||
|
||||
test(() => {
|
||||
assert_equals(domRectList.length, 1);
|
||||
|
|
|
@ -649,7 +649,6 @@ EnvironmentAddonBuilder.prototype = {
|
|||
theme: await this._getActiveTheme(),
|
||||
activePlugins: this._getActivePlugins(atStartup),
|
||||
activeGMPlugins: await this._getActiveGMPlugins(atStartup),
|
||||
activeExperiment: {},
|
||||
persona: personaId,
|
||||
};
|
||||
|
||||
|
|
|
@ -265,10 +265,6 @@ Structure:
|
|||
},
|
||||
...
|
||||
},
|
||||
activeExperiment: { // obsolete in firefox 61, section is empty if there's no active experiment
|
||||
id: <string>, // id
|
||||
branch: <string>, // branch name
|
||||
},
|
||||
persona: <string>, // id of the current persona
|
||||
},
|
||||
experiments: {
|
||||
|
@ -419,3 +415,11 @@ Just like activePlugins, this will report dummy values until the blocklist is lo
|
|||
experiments
|
||||
-----------
|
||||
For each experiment we collect the ``id`` and the ``branch`` the client is enrolled in. Both fields are truncated to 100 characters and a warning is printed when that happens.
|
||||
|
||||
|
||||
Version History
|
||||
===============
|
||||
|
||||
- Firefox 61:
|
||||
|
||||
- Removed empty ``addons.activeExperiment`` (`bug 1452935 <https://bugzilla.mozilla.org/show_bug.cgi?id=1452935>`_).
|
||||
|
|
|
@ -669,7 +669,6 @@ var EnvironmentData = {
|
|||
this.renderAddonsObject(addons.activeAddons, addonSection, "activeAddons");
|
||||
this.renderActivePlugins(addons.activePlugins, addonSection, "activePlugins");
|
||||
this.renderKeyValueObject(addons.theme, addonSection, "theme");
|
||||
this.renderKeyValueObject(addons.activeExperiment, addonSection, "activeExperiment");
|
||||
this.renderAddonsObject(addons.activeGMPlugins, addonSection, "activeGMPlugins");
|
||||
this.renderPersona(addons, addonSection, "persona");
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче