forked from mirrors/gecko-dev
Merge autoland to mozilla-central a=merge
This commit is contained in:
commit
16c7c33a62
156 changed files with 2244 additions and 1629 deletions
|
|
@ -313,7 +313,6 @@ mobile/android/locales/
|
|||
|
||||
# Non-standard `(catch ex if ...)`
|
||||
mobile/android/chrome/content/browser.js
|
||||
mobile/android/components/Snippets.js
|
||||
|
||||
# Only contains non-standard test files.
|
||||
python/**
|
||||
|
|
|
|||
|
|
@ -241,11 +241,10 @@ var ContentBlocking = {
|
|||
this.identityPopupMultiView = $("#identity-popup-multiView");
|
||||
this.reportBreakageButton = $("#identity-popup-content-blocking-report-breakage");
|
||||
this.reportBreakageURL = $("#identity-popup-breakageReportView-collection-url");
|
||||
this.reportBreakageUA = $("#identity-popup-breakageReportView-collection-userAgent");
|
||||
this.reportBreakageLearnMore = $("#identity-popup-breakageReportView-learn-more");
|
||||
|
||||
let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL");
|
||||
this.reportBreakageLearnMore.href = baseURL + "tracking-protection-pbm";
|
||||
this.reportBreakageLearnMore.href = baseURL + "blocking-breakage";
|
||||
|
||||
this.updateReportBreakageUI = () => {
|
||||
this.reportBreakageButton.hidden = !Services.prefs.getBoolPref(this.PREF_REPORT_BREAKAGE_ENABLED);
|
||||
|
|
@ -356,7 +355,7 @@ var ContentBlocking = {
|
|||
// Leave the ? at the end of the URL to signify that this URL had its query stripped.
|
||||
let urlWithoutQuery = this.reportURI.asciiSpec.replace(this.reportURI.query, "");
|
||||
let body = `Full URL: ${urlWithoutQuery}\n`;
|
||||
body += `userAgent: ${this.reportBreakageUA.textContent}\n`;
|
||||
body += `userAgent: ${navigator.userAgent}\n`;
|
||||
|
||||
body += "\n**Preferences**\n";
|
||||
body += `${TrackingProtection.PREF_ENABLED_GLOBALLY}: ${Services.prefs.getBoolPref(TrackingProtection.PREF_ENABLED_GLOBALLY)}\n`;
|
||||
|
|
@ -395,7 +394,6 @@ var ContentBlocking = {
|
|||
this.reportURI = gBrowser.currentURI;
|
||||
let urlWithoutQuery = this.reportURI.asciiSpec.replace("?" + this.reportURI.query, "");
|
||||
this.reportBreakageURL.textContent = urlWithoutQuery;
|
||||
this.reportBreakageUA.textContent = navigator.userAgent;
|
||||
this.identityPopupMultiView.showSubView("identity-popup-breakageReportView");
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -5455,7 +5455,13 @@ nsBrowserAccess.prototype = {
|
|||
}
|
||||
// Pass all params to openDialog to ensure that "url" isn't passed through
|
||||
// loadOneOrMoreURIs, which splits based on "|"
|
||||
newWindow = openDialog(AppConstants.BROWSER_CHROME_URL, "_blank", features, url, null, null, null);
|
||||
try {
|
||||
newWindow = openDialog(AppConstants.BROWSER_CHROME_URL, "_blank", features,
|
||||
// window.arguments
|
||||
url, null, null, null, null, null, null, null, aTriggeringPrincipal);
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
break;
|
||||
case Ci.nsIBrowserDOMWindow.OPEN_NEWTAB :
|
||||
// If we have an opener, that means that the caller is expecting access
|
||||
|
|
|
|||
|
|
@ -162,10 +162,8 @@ add_task(async function testReportBreakage() {
|
|||
|
||||
let submitButton = document.getElementById("identity-popup-breakageReportView-submit");
|
||||
let reportURL = document.getElementById("identity-popup-breakageReportView-collection-url").textContent;
|
||||
let reportUA = document.getElementById("identity-popup-breakageReportView-collection-userAgent").textContent;
|
||||
|
||||
is(reportURL, TRACKING_PAGE, "Shows the correct URL in the report UI.");
|
||||
is(reportUA, navigator.userAgent, "Shows the correct user agent in the report UI.");
|
||||
|
||||
// Make sure that sending the report closes the identity popup.
|
||||
let popuphidden = BrowserTestUtils.waitForEvent(gIdentityHandler._identityPopup, "popuphidden");
|
||||
|
|
@ -207,7 +205,7 @@ add_task(async function testReportBreakage() {
|
|||
"Content-Disposition: form-data; name=\"title\"\r\n\r\ntracking.example.org\r\n",
|
||||
"Content-Disposition: form-data; name=\"body\"\r\n\r\n" +
|
||||
`Full URL: ${reportURL + "?"}\r\n` +
|
||||
`userAgent: ${reportUA}\r\n\r\n` +
|
||||
`userAgent: ${navigator.userAgent}\r\n\r\n` +
|
||||
"**Preferences**\r\n" +
|
||||
`${prefsBody}\r\n` +
|
||||
"**Comments**\r\n" +
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ add_task(async function clearURLBarAfterParentProcessURL() {
|
|||
}, {capture: true, once: true});
|
||||
});
|
||||
document.getElementById("home-button").click();
|
||||
if (!tab.linkedBrowser.isRemoteBrowser) {
|
||||
await BrowserTestUtils.waitForEvent(tab.linkedBrowser, "XULFrameLoaderCreated");
|
||||
}
|
||||
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
is(gURLBar.value, "", "URL bar should be empty");
|
||||
is(tab.linkedBrowser.userTypedValue, null, "The browser should have no recorded userTypedValue");
|
||||
|
|
@ -36,6 +39,9 @@ add_task(async function clearURLBarAfterParentProcessURLInExistingTab() {
|
|||
newTabBrowser.loadURI("about:preferences");
|
||||
});
|
||||
document.getElementById("home-button").click();
|
||||
if (!tab.linkedBrowser.isRemoteBrowser) {
|
||||
await BrowserTestUtils.waitForEvent(tab.linkedBrowser, "XULFrameLoaderCreated");
|
||||
}
|
||||
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
is(gURLBar.value, "", "URL bar should be empty");
|
||||
is(tab.linkedBrowser.userTypedValue, null, "The browser should have no recorded userTypedValue");
|
||||
|
|
|
|||
|
|
@ -81,7 +81,6 @@ function startServer(cert) {
|
|||
}
|
||||
};
|
||||
|
||||
tlsServer.setSessionCache(false);
|
||||
tlsServer.setSessionTickets(false);
|
||||
tlsServer.setRequestClientCertificate(Ci.nsITLSServerSocket.REQUEST_ALWAYS);
|
||||
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@
|
|||
<hbox id="identity-popup-content-blocking-category-tracking-protection"
|
||||
class="identity-popup-content-blocking-category" align="center" role="group">
|
||||
<image class="identity-popup-content-blocking-category-icon tracking-protection-icon"/>
|
||||
<label flex="1" class="identity-popup-content-blocking-category-label">&contentBlocking.trackingProtection.label;</label>
|
||||
<label flex="1" class="identity-popup-content-blocking-category-label">&contentBlocking.trackingProtection2.label;</label>
|
||||
<label flex="1" class="identity-popup-content-blocking-category-state-label">&contentBlocking.trackingProtection.blocked.label;</label>
|
||||
<label flex="1" class="identity-popup-content-blocking-category-add-blocking text-link"
|
||||
onclick="ContentBlocking.openPreferences('identityPopup-CB-tracking-protection');">&contentBlocking.trackingProtection.add.label;</label>
|
||||
|
|
@ -122,7 +122,7 @@
|
|||
<label id="identity-popup-content-blocking-report-breakage"
|
||||
onclick="ContentBlocking.showReportBreakageSubview();"
|
||||
class="text-link subviewkeynav"
|
||||
flex="1">&contentBlocking.openBreakageReportView.label;</label>
|
||||
flex="1">&contentBlocking.openBreakageReportView2.label;</label>
|
||||
</vbox>
|
||||
</hbox>
|
||||
|
||||
|
|
@ -251,7 +251,7 @@
|
|||
title="&contentBlocking.breakageReportView.label;"
|
||||
descriptionheightworkaround="true">
|
||||
<vbox id="identity-popup-breakageReportView-heading">
|
||||
<description>&contentBlocking.breakageReportView.description;</description>
|
||||
<description>&contentBlocking.breakageReportView2.description;</description>
|
||||
<label id="identity-popup-breakageReportView-learn-more"
|
||||
class="text-link">&contentBlocking.breakageReportView.learnMore;</label>
|
||||
</vbox>
|
||||
|
|
@ -260,10 +260,6 @@
|
|||
<label class="identity-popup-breakageReportView-collection-label">&contentBlocking.breakageReportView.collection.url.label;</label>
|
||||
<label id="identity-popup-breakageReportView-collection-url"/>
|
||||
</vbox>
|
||||
<vbox class="identity-popup-breakageReportView-collection-section">
|
||||
<label class="identity-popup-breakageReportView-collection-label">&contentBlocking.breakageReportView.collection.userAgent.label;</label>
|
||||
<label id="identity-popup-breakageReportView-collection-userAgent"/>
|
||||
</vbox>
|
||||
<vbox class="identity-popup-breakageReportView-collection-section">
|
||||
<label class="identity-popup-breakageReportView-collection-label">&contentBlocking.breakageReportView.collection.comments.label;</label>
|
||||
<textbox multiline="true" id="identity-popup-breakageReportView-collection-comments"/>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
"use strict";
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
const {actionCreators: ac, actionTypes: at} = ChromeUtils.import("resource://activity-stream/common/Actions.jsm", {});
|
||||
const {TippyTopProvider} = ChromeUtils.import("resource://activity-stream/lib/TippyTopProvider.jsm", {});
|
||||
|
|
@ -76,7 +77,7 @@ this.TopSitesFeed = class TopSitesFeed {
|
|||
this._storage = this.store.dbStorage.getDbTable("sectionPrefs");
|
||||
this.refresh({broadcast: true});
|
||||
Services.obs.addObserver(this, "browser-search-engine-modified");
|
||||
this._currentSearchHostname = getShortURLForCurrentSearch();
|
||||
XPCOMUtils.defineLazyGetter(this, "_currentSearchHostname", getShortURLForCurrentSearch);
|
||||
}
|
||||
|
||||
uninit() {
|
||||
|
|
@ -214,6 +215,9 @@ this.TopSitesFeed = class TopSitesFeed {
|
|||
async getLinksWithDefaults() {
|
||||
const numItems = this.store.getState().Prefs.values[ROWS_PREF] * TOP_SITES_MAX_SITES_PER_ROW;
|
||||
const searchShortcutsExperiment = this.store.getState().Prefs.values[SEARCH_SHORTCUTS_EXPERIMENT];
|
||||
// We must wait for search services to initialize in order to access default
|
||||
// search engine properties without triggering a synchronous initialization
|
||||
await new Promise(resolve => Services.search.init(resolve));
|
||||
|
||||
// Get all frecent sites from history
|
||||
const frecent = (await this.frecentCache.request({
|
||||
|
|
|
|||
|
|
@ -185,7 +185,13 @@ const TEST_GLOBAL = {
|
|||
appinfo: {appBuildID: "20180710100040"}
|
||||
},
|
||||
XPCOMUtils: {
|
||||
defineLazyGetter(_1, _2, f) { f(); },
|
||||
defineLazyGetter(object, name, f) {
|
||||
if (object && name) {
|
||||
object[name] = f();
|
||||
} else {
|
||||
f();
|
||||
}
|
||||
},
|
||||
defineLazyGlobalGetters() {},
|
||||
defineLazyModuleGetter() {},
|
||||
defineLazyServiceGetter() {},
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
XPCOMUtils.defineLazyServiceGetter(this, "WindowsUIUtils",
|
||||
"@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gSystemPrincipal",
|
||||
() => Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
function shouldLoadURI(aURI) {
|
||||
if (aURI && !aURI.schemeIs("chrome"))
|
||||
return true;
|
||||
|
|
@ -162,6 +165,8 @@ function getPostUpdateOverridePage(defaultOverridePage) {
|
|||
* The nsICommandLine object given to nsICommandLineHandler's handle
|
||||
* method.
|
||||
* Used to check if we are processing the command line for the initial launch.
|
||||
* @param triggeringPrincipal
|
||||
* The nsIPrincipal to use as triggering principal for the page load(s).
|
||||
* @param urlOrUrlList (optional)
|
||||
* When omitted, the browser window will be opened with the default
|
||||
* arguments, which will usually load the homepage.
|
||||
|
|
@ -175,15 +180,20 @@ function getPostUpdateOverridePage(defaultOverridePage) {
|
|||
* @param forcePrivate (optional)
|
||||
* Boolean. If set to true, the new window will be a private browsing one.
|
||||
*/
|
||||
function openBrowserWindow(cmdLine, urlOrUrlList, postData = null,
|
||||
function openBrowserWindow(cmdLine, triggeringPrincipal, urlOrUrlList, postData = null,
|
||||
forcePrivate = false) {
|
||||
let chromeURL = AppConstants.BROWSER_CHROME_URL;
|
||||
|
||||
let args;
|
||||
if (!urlOrUrlList) {
|
||||
// Just pass in the defaultArgs directly
|
||||
// Just pass in the defaultArgs directly. We'll use system principal on the other end.
|
||||
args = [gBrowserContentHandler.defaultArgs];
|
||||
} else if (Array.isArray(urlOrUrlList)) {
|
||||
// There isn't an explicit way to pass a principal here, so we load multiple URLs
|
||||
// with system principal when we get to actually loading them.
|
||||
if (!triggeringPrincipal || !triggeringPrincipal.equals(gSystemPrincipal)) {
|
||||
throw new Error("Can't open multiple URLs with something other than system principal.");
|
||||
}
|
||||
// Passing an nsIArray for the url disables the "|"-splitting behavior.
|
||||
let uriArray = Cc["@mozilla.org/array;1"]
|
||||
.createInstance(Ci.nsIMutableArray);
|
||||
|
|
@ -197,10 +207,17 @@ function openBrowserWindow(cmdLine, urlOrUrlList, postData = null,
|
|||
} else {
|
||||
// Always pass at least 3 arguments to avoid the "|"-splitting behavior,
|
||||
// ie. avoid the loadOneOrMoreURIs function.
|
||||
// Also, we need to pass the triggering principal.
|
||||
args = [urlOrUrlList,
|
||||
null, // charset
|
||||
null, // referer
|
||||
postData];
|
||||
postData,
|
||||
undefined, // allowThirdPartyFixup; this would be `false` but that
|
||||
// needs a conversion. Hopefully bug 1485961 will fix.
|
||||
undefined, // referrer policy
|
||||
undefined, // user context id
|
||||
null, // origin principal
|
||||
triggeringPrincipal];
|
||||
}
|
||||
|
||||
if (cmdLine.state == Ci.nsICommandLine.STATE_INITIAL_LAUNCH) {
|
||||
|
|
@ -257,7 +274,7 @@ function openPreferences(cmdLine, extraArgs) {
|
|||
} else {
|
||||
Services.telemetry.getHistogramById("FX_PREFERENCES_OPENED_VIA").add("other");
|
||||
}
|
||||
openBrowserWindow(cmdLine, "about:preferences");
|
||||
openBrowserWindow(cmdLine, gSystemPrincipal, "about:preferences");
|
||||
}
|
||||
|
||||
function doSearch(searchTerm, cmdLine) {
|
||||
|
|
@ -270,7 +287,7 @@ function doSearch(searchTerm, cmdLine) {
|
|||
|
||||
// XXXbsmedberg: use handURIToExistingBrowser to obey tabbed-browsing
|
||||
// preferences, but need nsIBrowserDOMWindow extensions
|
||||
openBrowserWindow(cmdLine, submission.uri.spec, submission.postData);
|
||||
openBrowserWindow(cmdLine, gSystemPrincipal, submission.uri.spec, submission.postData);
|
||||
}
|
||||
|
||||
function nsBrowserContentHandler() {
|
||||
|
|
@ -295,7 +312,7 @@ nsBrowserContentHandler.prototype = {
|
|||
/* nsICommandLineHandler */
|
||||
handle: function bch_handle(cmdLine) {
|
||||
if (cmdLine.handleFlag("browser", false)) {
|
||||
openBrowserWindow(cmdLine);
|
||||
openBrowserWindow(cmdLine, gSystemPrincipal);
|
||||
cmdLine.preventDefault = true;
|
||||
}
|
||||
|
||||
|
|
@ -316,7 +333,7 @@ nsBrowserContentHandler.prototype = {
|
|||
let uri = resolveURIInternal(cmdLine, uriparam);
|
||||
if (!shouldLoadURI(uri))
|
||||
continue;
|
||||
openBrowserWindow(cmdLine, uri.spec);
|
||||
openBrowserWindow(cmdLine, gSystemPrincipal, uri.spec);
|
||||
cmdLine.preventDefault = true;
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
@ -328,7 +345,7 @@ nsBrowserContentHandler.prototype = {
|
|||
let uri = resolveURIInternal(cmdLine, uriparam);
|
||||
handURIToExistingBrowser(uri, Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
|
||||
cmdLine, false,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
gSystemPrincipal);
|
||||
cmdLine.preventDefault = true;
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
@ -391,8 +408,7 @@ nsBrowserContentHandler.prototype = {
|
|||
resolvedURI = resolveURIInternal(cmdLine, privateWindowParam);
|
||||
}
|
||||
handURIToExistingBrowser(resolvedURI, Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
|
||||
cmdLine, forcePrivate,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
cmdLine, forcePrivate, gSystemPrincipal);
|
||||
cmdLine.preventDefault = true;
|
||||
}
|
||||
} catch (e) {
|
||||
|
|
@ -401,7 +417,7 @@ nsBrowserContentHandler.prototype = {
|
|||
}
|
||||
// NS_ERROR_INVALID_ARG is thrown when flag exists, but has no param.
|
||||
if (cmdLine.handleFlag("private-window", false)) {
|
||||
openBrowserWindow(cmdLine, "about:privatebrowsing", null,
|
||||
openBrowserWindow(cmdLine, gSystemPrincipal, "about:privatebrowsing", null,
|
||||
PrivateBrowsingUtils.enabled);
|
||||
cmdLine.preventDefault = true;
|
||||
}
|
||||
|
|
@ -434,7 +450,7 @@ nsBrowserContentHandler.prototype = {
|
|||
if (fileParam) {
|
||||
var file = cmdLine.resolveFile(fileParam);
|
||||
var fileURI = Services.io.newFileURI(file);
|
||||
openBrowserWindow(cmdLine, fileURI.spec);
|
||||
openBrowserWindow(cmdLine, gSystemPrincipal, fileURI.spec);
|
||||
cmdLine.preventDefault = true;
|
||||
}
|
||||
|
||||
|
|
@ -663,7 +679,7 @@ function handURIToExistingBrowser(uri, location, cmdLine, forcePrivate, triggeri
|
|||
var navWin = BrowserWindowTracker.getTopWindow({private: allowPrivate});
|
||||
if (!navWin) {
|
||||
// if we couldn't load it in an existing window, open a new one
|
||||
openBrowserWindow(cmdLine, uri.spec, null, forcePrivate);
|
||||
openBrowserWindow(cmdLine, triggeringPrincipal, uri.spec, null, forcePrivate);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -744,8 +760,7 @@ nsDefaultCommandLineHandler.prototype = {
|
|||
// current tab, new tab, or new window as prefs determine.
|
||||
try {
|
||||
handURIToExistingBrowser(urilist[0], Ci.nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW,
|
||||
cmdLine, false,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
cmdLine, false, gSystemPrincipal);
|
||||
return;
|
||||
} catch (e) {
|
||||
}
|
||||
|
|
@ -753,7 +768,7 @@ nsDefaultCommandLineHandler.prototype = {
|
|||
|
||||
var URLlist = urilist.filter(shouldLoadURI).map(u => u.spec);
|
||||
if (URLlist.length) {
|
||||
openBrowserWindow(cmdLine, URLlist);
|
||||
openBrowserWindow(cmdLine, gSystemPrincipal, URLlist);
|
||||
}
|
||||
|
||||
} else if (!cmdLine.preventDefault) {
|
||||
|
|
@ -767,7 +782,7 @@ nsDefaultCommandLineHandler.prototype = {
|
|||
return;
|
||||
}
|
||||
}
|
||||
openBrowserWindow(cmdLine);
|
||||
openBrowserWindow(cmdLine, gSystemPrincipal);
|
||||
} else {
|
||||
// Need a better solution in the future to avoid opening the blank window
|
||||
// when command line parameters say we are not going to show a browser
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ Preferences.addAll([
|
|||
{ id: "network.proxy.backup.ssl_port", type: "int" },
|
||||
{ id: "network.proxy.backup.socks", type: "string" },
|
||||
{ id: "network.proxy.backup.socks_port", type: "int" },
|
||||
{ id: "network.trr.mode", type: "int" },
|
||||
{ id: "network.trr.uri", type: "string" },
|
||||
]);
|
||||
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
|
|
@ -277,5 +279,35 @@ var gConnectionsDialog = {
|
|||
handleControllingExtension(PREF_SETTING_TYPE, PROXY_KEY)
|
||||
.then(setInputsDisabledState);
|
||||
}
|
||||
},
|
||||
|
||||
isDnsOverHttpsEnabled() {
|
||||
// values outside 1:4 are considered falsey/disabled in this context
|
||||
let trrPref = Preferences.get("network.trr.mode");
|
||||
let enabled = trrPref.value > 0 && trrPref.value < 5;
|
||||
return enabled;
|
||||
},
|
||||
|
||||
readDnsOverHttpsMode() {
|
||||
// called to update checked element property to reflect current pref value
|
||||
let enabled = this.isDnsOverHttpsEnabled();
|
||||
let uriPref = Preferences.get("network.trr.uri");
|
||||
uriPref.disabled = !enabled;
|
||||
return enabled;
|
||||
},
|
||||
|
||||
writeDnsOverHttpsMode() {
|
||||
// called to update pref with user change
|
||||
let trrModeCheckbox = document.getElementById("networkDnsOverHttps");
|
||||
// we treat checked/enabled as mode 2
|
||||
return trrModeCheckbox.checked ? 2 : 0;
|
||||
},
|
||||
|
||||
writeDnsOverHttpsUri() {
|
||||
// called to update pref with user input
|
||||
let input = document.getElementById("networkDnsOverHttpsUrl");
|
||||
let uriString = input.value.trim();
|
||||
// turn an empty string into `undefined` to clear the pref back to the default
|
||||
return uriString.length ? uriString : undefined;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -148,6 +148,18 @@
|
|||
<checkbox id="networkProxySOCKSRemoteDNS"
|
||||
preference="network.proxy.socks_remote_dns"
|
||||
data-l10n-id="connection-proxy-socks-remote-dns" />
|
||||
<checkbox id="networkDnsOverHttps"
|
||||
data-l10n-id="connection-dns-over-https"
|
||||
preference="network.trr.mode"
|
||||
onsyncfrompreference="return gConnectionsDialog.readDnsOverHttpsMode();"
|
||||
onsynctopreference="return gConnectionsDialog.writeDnsOverHttpsMode()" />
|
||||
<hbox class="indent" flex="1" align="center">
|
||||
<label control="networkDnsOverHttpsUrl" data-l10n-id="connection-dns-over-https-url"
|
||||
data-l10n-attrs="tooltiptext"/>
|
||||
<textbox id="networkDnsOverHttpsUrl" flex="1" preference="network.trr.uri"
|
||||
placeholder="https://doh.example.com/dns-query"
|
||||
onsynctopreference="return gConnectionsDialog.writeDnsOverHttpsUri()" />
|
||||
</hbox>
|
||||
<separator/>
|
||||
</vbox>
|
||||
</dialog>
|
||||
|
|
|
|||
|
|
@ -652,12 +652,12 @@
|
|||
class="subcategory"
|
||||
hidden="true"
|
||||
data-category="paneGeneral">
|
||||
<label class="header-name" flex="1" data-l10n-id="network-proxy-title"/>
|
||||
<label class="header-name" flex="1" data-l10n-id="network-settings-title"/>
|
||||
</hbox>
|
||||
|
||||
<!-- Network Proxy-->
|
||||
<!-- Network Settings-->
|
||||
<groupbox id="connectionGroup" data-category="paneGeneral" hidden="true">
|
||||
<caption class="search-header" hidden="true"><label data-l10n-id="network-proxy-title"/></caption>
|
||||
<caption class="search-header" hidden="true"><label data-l10n-id="network-settings-title"/></caption>
|
||||
|
||||
<hbox align="center">
|
||||
<hbox align="center" flex="1">
|
||||
|
|
@ -694,7 +694,9 @@
|
|||
connection-proxy-autotype.label,
|
||||
connection-proxy-reload.label,
|
||||
connection-proxy-autologin.label,
|
||||
connection-proxy-socks-remote-dns.label
|
||||
connection-proxy-socks-remote-dns.label,
|
||||
connection-dns-over-https,
|
||||
connection-dns-over-https-url
|
||||
" />
|
||||
</hbox>
|
||||
</hbox>
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ skip-if = os != "win" # Windows-specific handler application selection dialog
|
|||
[browser_connection_bug388287.js]
|
||||
[browser_connection_bug1445991.js]
|
||||
skip-if = (verify && debug && (os == 'linux' || os == 'mac'))
|
||||
[browser_connection_dnsoverhttps.js]
|
||||
[browser_contentblocking.js]
|
||||
[browser_cookies_exceptions.js]
|
||||
[browser_defaultbrowser_alwayscheck.js]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,172 @@
|
|||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const SUBDIALOG_URL = "chrome://browser/content/preferences/connection.xul";
|
||||
const TRR_MODE_PREF = "network.trr.mode";
|
||||
const TRR_URI_PREF = "network.trr.uri";
|
||||
|
||||
const modeCheckboxSelector = "#networkDnsOverHttps";
|
||||
const uriTextboxSelector = "#networkDnsOverHttpsUrl";
|
||||
const defaultPrefValues = Object.freeze({
|
||||
[TRR_MODE_PREF]: 0,
|
||||
[TRR_URI_PREF]: "",
|
||||
});
|
||||
|
||||
function resetPrefs() {
|
||||
Services.prefs.clearUserPref(TRR_MODE_PREF);
|
||||
Services.prefs.clearUserPref(TRR_URI_PREF);
|
||||
}
|
||||
|
||||
async function setup() {
|
||||
await new Promise(res => {
|
||||
resetPrefs();
|
||||
open_preferences(res);
|
||||
});
|
||||
}
|
||||
|
||||
async function openConnectionsSubDialog() {
|
||||
/*
|
||||
The connection dialog has type="child", So it has to be opened as a sub dialog
|
||||
of the main pref tab. Prefs only get updated after the subdialog is confirmed & closed
|
||||
*/
|
||||
let dialog = await openAndLoadSubDialog(SUBDIALOG_URL);
|
||||
ok(dialog, "connection window opened");
|
||||
return dialog;
|
||||
}
|
||||
|
||||
function waitForPrefObserver(name) {
|
||||
return new Promise(resolve => {
|
||||
const observer = {
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aData == name) {
|
||||
Services.prefs.removeObserver(name, observer);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
};
|
||||
Services.prefs.addObserver(name, observer);
|
||||
});
|
||||
}
|
||||
|
||||
async function testWithProperties(props) {
|
||||
info("testing with " + JSON.stringify(props));
|
||||
if (props.hasOwnProperty(TRR_MODE_PREF)) {
|
||||
Services.prefs.setIntPref(TRR_MODE_PREF, props[TRR_MODE_PREF]);
|
||||
}
|
||||
if (props.hasOwnProperty(TRR_URI_PREF)) {
|
||||
Services.prefs.setStringPref(TRR_URI_PREF, props[TRR_URI_PREF]);
|
||||
}
|
||||
|
||||
let dialog = await openConnectionsSubDialog();
|
||||
let doc = dialog.document;
|
||||
let dialogClosingPromise = BrowserTestUtils.waitForEvent(doc.documentElement,
|
||||
"dialogclosing");
|
||||
let modeCheckbox = doc.querySelector(modeCheckboxSelector);
|
||||
let uriTextbox = doc.querySelector(uriTextboxSelector);
|
||||
let uriPrefChangedPromise;
|
||||
let modePrefChangedPromise;
|
||||
|
||||
if (props.hasOwnProperty("expectedModeChecked")) {
|
||||
is(modeCheckbox.checked, props.expectedModeChecked, "mode checkbox has expected checked state");
|
||||
}
|
||||
if (props.hasOwnProperty("expectedUriValue")) {
|
||||
is(uriTextbox.value, props.expectedUriValue, "URI textbox has expected value");
|
||||
}
|
||||
if (props.clickMode) {
|
||||
modePrefChangedPromise = waitForPrefObserver(TRR_MODE_PREF);
|
||||
modeCheckbox.scrollIntoView();
|
||||
EventUtils.synthesizeMouseAtCenter(modeCheckbox, {},
|
||||
modeCheckbox.ownerGlobal);
|
||||
}
|
||||
if (props.hasOwnProperty("inputUriKeys")) {
|
||||
uriPrefChangedPromise = waitForPrefObserver(TRR_URI_PREF);
|
||||
uriTextbox.focus();
|
||||
// delete whatever is in there
|
||||
EventUtils.synthesizeKey("a", { accelKey: true }, uriTextbox.ownerGlobal);
|
||||
EventUtils.synthesizeKey("KEY_Backspace", {}, uriTextbox.ownerGlobal);
|
||||
// and type in the new stuff
|
||||
EventUtils.synthesizeKey(props.inputUriKeys, {}, uriTextbox.ownerGlobal);
|
||||
let changePromise = waitForEvent(uriTextbox, "change");
|
||||
// move focus to trigger change event
|
||||
modeCheckbox.focus();
|
||||
await changePromise;
|
||||
}
|
||||
|
||||
doc.documentElement.acceptDialog();
|
||||
|
||||
let dialogClosingEvent = await dialogClosingPromise;
|
||||
ok(dialogClosingEvent, "connection window closed");
|
||||
|
||||
await Promise.all([uriPrefChangedPromise, modePrefChangedPromise]);
|
||||
|
||||
if (props.hasOwnProperty("expectedFinalUriPref")) {
|
||||
let uriPref = Services.prefs.getStringPref(TRR_URI_PREF);
|
||||
is(uriPref, props.expectedFinalUriPref, "uri pref ended up with the expected value");
|
||||
}
|
||||
|
||||
if (props.hasOwnProperty("expectedModePref")) {
|
||||
let modePref = Services.prefs.getIntPref(TRR_MODE_PREF);
|
||||
is(modePref, props.expectedModePref, "mode pref ended up with the expected value");
|
||||
}
|
||||
}
|
||||
|
||||
registerCleanupFunction(resetPrefs);
|
||||
|
||||
add_task(async function default_values() {
|
||||
let uriPref = Services.prefs.getStringPref(TRR_URI_PREF);
|
||||
let modePref = Services.prefs.getIntPref(TRR_MODE_PREF);
|
||||
is(modePref, defaultPrefValues[TRR_MODE_PREF],
|
||||
`Actual value of ${TRR_MODE_PREF} matches expected default value`);
|
||||
is(uriPref, defaultPrefValues[TRR_URI_PREF],
|
||||
`Actual value of ${TRR_MODE_PREF} matches expected default value`);
|
||||
});
|
||||
|
||||
let testVariations = [
|
||||
// verify state with defaults
|
||||
{ expectedModePref: 0, expectedUriValue: "" },
|
||||
|
||||
// verify each of the modes maps to the correct checked state
|
||||
{ [TRR_MODE_PREF]: 0, expectedModeChecked: false },
|
||||
{ [TRR_MODE_PREF]: 1, expectedModeChecked: true },
|
||||
{ [TRR_MODE_PREF]: 2, expectedModeChecked: true },
|
||||
{ [TRR_MODE_PREF]: 3, expectedModeChecked: true },
|
||||
{ [TRR_MODE_PREF]: 4, expectedModeChecked: true },
|
||||
{ [TRR_MODE_PREF]: 5, expectedModeChecked: false },
|
||||
// verify an out of bounds mode value maps to the correct checked state
|
||||
{ [TRR_MODE_PREF]: 77, expectedModeChecked: false },
|
||||
|
||||
// verify toggling the checkbox gives the right outcomes
|
||||
{ clickMode: true, expectedModeValue: 2, expectedUriValue: "" },
|
||||
{
|
||||
[TRR_MODE_PREF]: 4,
|
||||
expectedModeChecked: true, clickMode: true, expectedModePref: 0,
|
||||
},
|
||||
{
|
||||
[TRR_MODE_PREF]: 2, [TRR_URI_PREF]: "https://example.com",
|
||||
expectedModeValue: true, expectedUriValue: "https://example.com",
|
||||
},
|
||||
{
|
||||
clickMode: true, inputUriKeys: "https://example.com",
|
||||
expectedModePref: 2, expectedFinalUriPref: "https://example.com",
|
||||
},
|
||||
|
||||
// verify the uri can be cleared
|
||||
{
|
||||
[TRR_MODE_PREF]: 2, [TRR_URI_PREF]: "https://example.com",
|
||||
expectedUriValue: "https://example.com", inputUriKeys: "", expectedFinalUriPref: "",
|
||||
},
|
||||
|
||||
// verify uri gets sanitized
|
||||
{
|
||||
clickMode: true, inputUriKeys: " https://example.com ",
|
||||
expectedModePref: 2, expectedFinalUriPref: "https://example.com",
|
||||
},
|
||||
];
|
||||
|
||||
for (let props of testVariations) {
|
||||
add_task(async function() {
|
||||
await setup();
|
||||
await testWithProperties(props);
|
||||
resetPrefs();
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
}
|
||||
|
|
@ -81,3 +81,11 @@ connection-proxy-autologin =
|
|||
connection-proxy-socks-remote-dns =
|
||||
.label = Proxy DNS when using SOCKS v5
|
||||
.accesskey = D
|
||||
|
||||
connection-dns-over-https =
|
||||
.label = Enable DNS over HTTPS
|
||||
.accesskey = H
|
||||
|
||||
connection-dns-over-https-url = URL
|
||||
.accesskey = U
|
||||
.tooltiptext = URL for resolving DNS over HTTPS
|
||||
|
|
|
|||
|
|
@ -405,7 +405,7 @@ browsing-search-on-start-typing =
|
|||
|
||||
## General Section - Proxy
|
||||
|
||||
network-proxy-title = Network Proxy
|
||||
network-settings-title = Network Settings
|
||||
|
||||
network-proxy-connection-description = Configure how { -brand-short-name } connects to the internet.
|
||||
|
||||
|
|
|
|||
|
|
@ -938,7 +938,7 @@ you can use these alternative items. Otherwise, their values should be empty. -
|
|||
the type of content blocking is currently not enabled. -->
|
||||
<!ENTITY contentBlocking.fastBlock.add.label "Add Blocking…">
|
||||
|
||||
<!ENTITY contentBlocking.trackingProtection.label "Trackers">
|
||||
<!ENTITY contentBlocking.trackingProtection2.label "All Detected Trackers">
|
||||
<!-- LOCALIZATION NOTE (contentBlocking.trackingProtection.blocked.label):
|
||||
This label signals that this type of content blocking is turned
|
||||
ON and is successfully blocking tracker content, so this is
|
||||
|
|
@ -964,12 +964,11 @@ you can use these alternative items. Otherwise, their values should be empty. -
|
|||
the type of content blocking is currently not enabled. -->
|
||||
<!ENTITY contentBlocking.3rdPartyCookies.add.label "Add Blocking…">
|
||||
|
||||
<!ENTITY contentBlocking.openBreakageReportView.label "Report Problems">
|
||||
<!ENTITY contentBlocking.openBreakageReportView2.label "Report a problem">
|
||||
<!ENTITY contentBlocking.breakageReportView.label "Report Problems">
|
||||
<!ENTITY contentBlocking.breakageReportView.description "Content blocking can cause problems with some websites. When you report problems, you’ll help make &brandShortName; better for everyone. (This will send a URL as well as information about your privacy and content blocking settings to Mozilla.)">
|
||||
<!ENTITY contentBlocking.breakageReportView2.description "Content blocking can cause problems with some websites. When you report problems, you’ll help make &brandShortName; better for everyone. (This will send a URL as well as information about your browser settings to Mozilla.)">
|
||||
<!ENTITY contentBlocking.breakageReportView.learnMore "Learn More">
|
||||
<!ENTITY contentBlocking.breakageReportView.collection.url.label "URL">
|
||||
<!ENTITY contentBlocking.breakageReportView.collection.userAgent.label "&brandShortName; Version Number">
|
||||
<!ENTITY contentBlocking.breakageReportView.collection.comments.label "What problems did you have? (Optional)">
|
||||
<!ENTITY contentBlocking.breakageReportView.sendReport.label "Send Report">
|
||||
<!ENTITY contentBlocking.breakageReportView.cancel.label "Cancel">
|
||||
|
|
|
|||
|
|
@ -562,6 +562,10 @@ description#identity-popup-content-verifier,
|
|||
margin-top: -0.1em;
|
||||
}
|
||||
|
||||
.identity-popup-content-blocking-category-label {
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.identity-popup-content-blocking-category-label,
|
||||
.identity-popup-permission-label {
|
||||
margin-inline-start: 1em;
|
||||
|
|
|
|||
|
|
@ -474,7 +474,8 @@ if __name__ == "__main__":
|
|||
clang_repo = config["clang_repo"]
|
||||
extra_repo = config.get("extra_repo")
|
||||
lld_repo = config.get("lld_repo")
|
||||
compiler_repo = config["compiler_repo"]
|
||||
# On some packages we don't use compiler_repo
|
||||
compiler_repo = config.get("compiler_repo")
|
||||
libcxx_repo = config["libcxx_repo"]
|
||||
libcxxabi_repo = config.get("libcxxabi_repo")
|
||||
stages = 3
|
||||
|
|
@ -543,7 +544,8 @@ if __name__ == "__main__":
|
|||
if not args.skip_checkout:
|
||||
checkout_or_update(llvm_repo, llvm_source_dir)
|
||||
checkout_or_update(clang_repo, clang_source_dir)
|
||||
checkout_or_update(compiler_repo, compiler_rt_source_dir)
|
||||
if compiler_repo is not None:
|
||||
checkout_or_update(compiler_repo, compiler_rt_source_dir)
|
||||
checkout_or_update(libcxx_repo, libcxx_source_dir)
|
||||
if lld_repo:
|
||||
checkout_or_update(lld_repo, lld_source_dir)
|
||||
|
|
|
|||
|
|
@ -1,23 +0,0 @@
|
|||
Backport cxx14 default dialect flag from clang 6.0.0 trunk to 5.0.1
|
||||
|
||||
Index: lib/Frontend/CompilerInvocation.cpp
|
||||
===================================================================
|
||||
--- a/clang/lib/Frontend/CompilerInvocation.cpp (revision 320871)
|
||||
+++ b/clang/lib/Frontend/CompilerInvocation.cpp (working copy)
|
||||
@@ -1690,11 +1690,11 @@
|
||||
break;
|
||||
case InputKind::CXX:
|
||||
case InputKind::ObjCXX:
|
||||
- // The PS4 uses C++11 as the default C++ standard.
|
||||
- if (T.isPS4())
|
||||
- LangStd = LangStandard::lang_gnucxx11;
|
||||
- else
|
||||
- LangStd = LangStandard::lang_gnucxx98;
|
||||
+#if defined(CLANG_DEFAULT_STD_CXX)
|
||||
+ LangStd = CLANG_DEFAULT_STD_CXX;
|
||||
+#else
|
||||
+ LangStd = LangStandard::lang_gnucxx14;
|
||||
+#endif
|
||||
break;
|
||||
case InputKind::RenderScript:
|
||||
LangStd = LangStandard::lang_c99;
|
||||
|
|
@ -1,22 +1,20 @@
|
|||
{
|
||||
"llvm_revision": "320871",
|
||||
"llvm_revision": "340491",
|
||||
"stages": "1",
|
||||
"build_libcxx": true,
|
||||
"build_type": "Release",
|
||||
"assertions": false,
|
||||
"build_clang_tidy": true,
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_501/final",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_501/final",
|
||||
"extra_repo": "https://llvm.org/svn/llvm-project/clang-tools-extra/tags/RELEASE_501/final",
|
||||
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_501/final",
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_501/final",
|
||||
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/tags/RELEASE_501/final",
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_700/rc2/",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_700/rc2/",
|
||||
"extra_repo": "https://llvm.org/svn/llvm-project/clang-tools-extra/tags/RELEASE_700/rc2/",
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_700/rc2/",
|
||||
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/tags/RELEASE_700/rc2/",
|
||||
"python_path": "/usr/bin/python2.7",
|
||||
"gcc_dir": "/builds/worker/workspace/build/src/gcc",
|
||||
"cc": "/builds/worker/workspace/build/src/gcc/bin/gcc",
|
||||
"cxx": "/builds/worker/workspace/build/src/gcc/bin/g++",
|
||||
"as": "/builds/worker/workspace/build/src/gcc/bin/gcc",
|
||||
"patches": [
|
||||
"clang-tidy-cxx14.patch"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +1,16 @@
|
|||
{
|
||||
"llvm_revision": "320871",
|
||||
"llvm_revision": "340491",
|
||||
"stages": "1",
|
||||
"build_libcxx": true,
|
||||
"build_type": "Release",
|
||||
"assertions": false,
|
||||
"build_clang_tidy": true,
|
||||
"osx_cross_compile": true,
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_501/final",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_501/final",
|
||||
"extra_repo": "https://llvm.org/svn/llvm-project/clang-tools-extra/tags/RELEASE_501/final",
|
||||
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_501/final",
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_501/final",
|
||||
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/tags/RELEASE_501/final",
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_700/rc2",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_700/rc2",
|
||||
"extra_repo": "https://llvm.org/svn/llvm-project/clang-tools-extra/tags/RELEASE_700/rc2",
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/tags/RELEASE_700/rc2",
|
||||
"libcxxabi_repo": "https://llvm.org/svn/llvm-project/libcxxabi/tags/RELEASE_700/rc2",
|
||||
"python_path": "/usr/bin/python2.7",
|
||||
"gcc_dir": "/builds/worker/workspace/build/src/gcc",
|
||||
"cc": "/builds/worker/workspace/build/src/clang/bin/clang",
|
||||
|
|
@ -19,11 +18,8 @@
|
|||
"as": "/builds/worker/workspace/build/src/clang/bin/clang",
|
||||
"ar": "/builds/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin11-ar",
|
||||
"ranlib": "/builds/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin11-ranlib",
|
||||
"libtool": "/builds/worker/workspace/build/src/cctools/bin/x86_64-apple-darwin11-libtool",
|
||||
"ld": "/builds/worker/workspace/build/src/clang/bin/clang",
|
||||
"patches": [
|
||||
"llvm-debug-frame-for-5.patch",
|
||||
"compiler-rt-cross-compile.patch",
|
||||
"compiler-rt-no-codesign.patch",
|
||||
"clang-tidy-cxx14.patch"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,18 @@
|
|||
{
|
||||
"llvm_revision": "320871",
|
||||
"llvm_revision": "340491",
|
||||
"stages": "1",
|
||||
"build_libcxx": false,
|
||||
"build_type": "Release",
|
||||
"assertions": false,
|
||||
"build_clang_tidy": true,
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_501/final",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_501/final",
|
||||
"extra_repo": "https://llvm.org/svn/llvm-project/clang-tools-extra/tags/RELEASE_501/final",
|
||||
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_501/final",
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_700/rc2",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_700/rc2",
|
||||
"extra_repo": "https://llvm.org/svn/llvm-project/clang-tools-extra/tags/RELEASE_700/rc2",
|
||||
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_700/rc2",
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
|
||||
"python_path": "c:/mozilla-build/python/python.exe",
|
||||
"cc": "cl.exe",
|
||||
"cxx": "cl.exe",
|
||||
"patches": [
|
||||
"clang-tidy-cxx14.patch"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,19 @@
|
|||
{
|
||||
"llvm_revision": "320871",
|
||||
"llvm_revision": "340491",
|
||||
"stages": "1",
|
||||
"build_libcxx": false,
|
||||
"build_type": "Release",
|
||||
"assertions": false,
|
||||
"build_clang_tidy": true,
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_501/final",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_501/final",
|
||||
"extra_repo": "https://llvm.org/svn/llvm-project/clang-tools-extra/tags/RELEASE_501/final",
|
||||
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_501/final",
|
||||
"llvm_repo": "https://llvm.org/svn/llvm-project/llvm/tags/RELEASE_700/rc2",
|
||||
"clang_repo": "https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_700/rc2",
|
||||
"extra_repo": "https://llvm.org/svn/llvm-project/clang-tools-extra/tags/RELEASE_700/rc2",
|
||||
"compiler_repo": "https://llvm.org/svn/llvm-project/compiler-rt/tags/RELEASE_700/rc2",
|
||||
"libcxx_repo": "https://llvm.org/svn/llvm-project/libcxx/trunk",
|
||||
"python_path": "c:/mozilla-build/python/python.exe",
|
||||
"cc": "cl.exe",
|
||||
"cxx": "cl.exe",
|
||||
"ml": "ml64.exe",
|
||||
"patches": [
|
||||
"clang-tidy-cxx14.patch"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp
|
||||
===================================================================
|
||||
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (revision 226419)
|
||||
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp (working copy)
|
||||
@@ -210,6 +210,8 @@
|
||||
OutStreamer->EmitFileDirective(M.getSourceFileName());
|
||||
}
|
||||
|
||||
+ OutStreamer->EmitCFISections(true, true);
|
||||
+
|
||||
GCModuleInfo *MI = getAnalysisIfAvailable<GCModuleInfo>();
|
||||
assert(MI && "AsmPrinter didn't require GCModuleInfo?");
|
||||
for (auto &I : *MI)
|
||||
|
|
@ -24,10 +24,13 @@ void ExplicitImplicitChecker::check(const MatchFinder::MatchResult &Result) {
|
|||
const CXXRecordDecl *Declaration =
|
||||
Result.Nodes.getNodeAs<CXXRecordDecl>("class");
|
||||
|
||||
FixItHint FixItHint =
|
||||
FixItHint::CreateInsertion(Ctor->getLocation(), "explicit ");
|
||||
diag(Ctor->getLocation(), "bad implicit conversion constructor for %0",
|
||||
DiagnosticIDs::Error)
|
||||
<< Declaration->getDeclName();
|
||||
diag(Ctor->getLocation(),
|
||||
"consider adding the explicit keyword to the constructor",
|
||||
DiagnosticIDs::Note);
|
||||
DiagnosticIDs::Note)
|
||||
<< FixItHint;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ def do_import(mozilla_path, clang_tidy_path):
|
|||
'LINK_LIBS', 'clangTidyMozillaModule')
|
||||
add_item_to_cmake_section(os.path.join(module_path, '..', 'tool',
|
||||
'CMakeLists.txt'),
|
||||
'target_link_libraries', 'clangTidyMozillaModule')
|
||||
'PRIVATE', 'clangTidyMozillaModule')
|
||||
with open(os.path.join(module_path, '..', 'CMakeLists.txt'), 'a') as f:
|
||||
f.write('add_subdirectory(%s)\n' % module)
|
||||
with open(os.path.join(module_path, '..', 'tool', 'ClangTidyMain.cpp'), 'a') as f:
|
||||
|
|
|
|||
|
|
@ -68,7 +68,6 @@ HOST_COMPILE_FLAGS['VISIBILITY'] = []
|
|||
# libc++ is required to build plugins against clang on OS X.
|
||||
if CONFIG['HOST_OS_ARCH'] == 'Darwin':
|
||||
HOST_CXXFLAGS += ['-stdlib=libc++']
|
||||
HOST_LDFLAGS += ['-lc++']
|
||||
|
||||
DIRS += [
|
||||
'tests',
|
||||
|
|
|
|||
417
devtools/client/shared/TelemetryStopwatch.jsm
Normal file
417
devtools/client/shared/TelemetryStopwatch.jsm
Normal file
|
|
@ -0,0 +1,417 @@
|
|||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = ["TelemetryStopwatch"];
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Log",
|
||||
"resource://gre/modules/Log.jsm");
|
||||
|
||||
// Weak map does not allow using null objects as keys. These objects are used
|
||||
// as 'null' placeholders.
|
||||
const NULL_OBJECT = {};
|
||||
const NULL_KEY = {};
|
||||
|
||||
/**
|
||||
* Timers is a variation of a Map used for storing information about running
|
||||
* Stopwatches. Timers has the following data structure:
|
||||
*
|
||||
* {
|
||||
* "HISTOGRAM_NAME": WeakMap {
|
||||
* Object || NULL_OBJECT: Map {
|
||||
* "KEY" || NULL_KEY: startTime
|
||||
* ...
|
||||
* }
|
||||
* ...
|
||||
* }
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* // Stores current time for a keyed histogram "PLAYING_WITH_CUTE_ANIMALS".
|
||||
* Timers.put("PLAYING_WITH_CUTE_ANIMALS", null, "CATS", Date.now());
|
||||
*
|
||||
* @example
|
||||
* // Returns information about a simple Stopwatch.
|
||||
* let startTime = Timers.get("PLAYING_WITH_CUTE_ANIMALS", null, "CATS");
|
||||
*/
|
||||
const Timers = {
|
||||
_timers: new Map(),
|
||||
|
||||
_validTypes(histogram, obj, key) {
|
||||
const nonEmptyString = value => {
|
||||
return typeof value === "string" && value !== "" && value.length > 0;
|
||||
};
|
||||
return nonEmptyString(histogram) &&
|
||||
typeof obj == "object" &&
|
||||
(key === NULL_KEY || nonEmptyString(key));
|
||||
},
|
||||
|
||||
get(histogram, obj, key) {
|
||||
key = key === null ? NULL_KEY : key;
|
||||
obj = obj || NULL_OBJECT;
|
||||
|
||||
if (!this.has(histogram, obj, key)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this._timers.get(histogram).get(obj).get(key);
|
||||
},
|
||||
|
||||
put(histogram, obj, key, startTime) {
|
||||
key = key === null ? NULL_KEY : key;
|
||||
obj = obj || NULL_OBJECT;
|
||||
|
||||
if (!this._validTypes(histogram, obj, key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const objectMap = this._timers.get(histogram) || new WeakMap();
|
||||
const keyedInfo = objectMap.get(obj) || new Map();
|
||||
keyedInfo.set(key, startTime);
|
||||
objectMap.set(obj, keyedInfo);
|
||||
this._timers.set(histogram, objectMap);
|
||||
return true;
|
||||
},
|
||||
|
||||
has(histogram, obj, key) {
|
||||
key = key === null ? NULL_KEY : key;
|
||||
obj = obj || NULL_OBJECT;
|
||||
|
||||
return this._timers.has(histogram) &&
|
||||
this._timers.get(histogram).has(obj) &&
|
||||
this._timers.get(histogram).get(obj).has(key);
|
||||
},
|
||||
|
||||
delete(histogram, obj, key) {
|
||||
key = key === null ? NULL_KEY : key;
|
||||
obj = obj || NULL_OBJECT;
|
||||
|
||||
if (!this.has(histogram, obj, key)) {
|
||||
return false;
|
||||
}
|
||||
const objectMap = this._timers.get(histogram);
|
||||
const keyedInfo = objectMap.get(obj);
|
||||
if (keyedInfo.size > 1) {
|
||||
keyedInfo.delete(key);
|
||||
return true;
|
||||
}
|
||||
objectMap.delete(obj);
|
||||
// NOTE:
|
||||
// We never delete empty objecMaps from this._timers because there is no
|
||||
// nice solution for tracking the number of objects in a WeakMap.
|
||||
// WeakMap is not enumerable, so we can't deterministically say when it's
|
||||
// empty. We accept that trade-off here, given that entries for short-lived
|
||||
// objects will go away when they are no longer referenced
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
var TelemetryStopwatch = {
|
||||
/**
|
||||
* Starts a timer associated with a telemetry histogram. The timer can be
|
||||
* directly associated with a histogram, or with a pair of a histogram and
|
||||
* an object.
|
||||
*
|
||||
* @param {String} aHistogram - a string which must be a valid histogram name.
|
||||
*
|
||||
* @param {Object} aObj - Optional parameter. If specified, the timer is
|
||||
* associated with this object, meaning that multiple
|
||||
* timers for the same histogram may be run
|
||||
* concurrently, as long as they are associated with
|
||||
* different objects.
|
||||
*
|
||||
* @returns {Boolean} True if the timer was successfully started, false
|
||||
* otherwise. If a timer already exists, it can't be
|
||||
* started again, and the existing one will be cleared in
|
||||
* order to avoid measurements errors.
|
||||
*/
|
||||
start(aHistogram, aObj) {
|
||||
return TelemetryStopwatchImpl.start(aHistogram, aObj, null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns whether a timer associated with a telemetry histogram is currently
|
||||
* running. The timer can be directly associated with a histogram, or with a
|
||||
* pair of a histogram and an object.
|
||||
*
|
||||
* @param {String} aHistogram - a string which must be a valid histogram name.
|
||||
*
|
||||
* @param {Object} aObj - Optional parameter. If specified, the timer is
|
||||
* associated with this object, meaning that multiple
|
||||
* timers for the same histogram may be run
|
||||
* concurrently, as long as they are associated with
|
||||
* different objects.
|
||||
*
|
||||
* @returns {Boolean} True if the timer exists and is currently running.
|
||||
*/
|
||||
running(aHistogram, aObj) {
|
||||
return TelemetryStopwatchImpl.running(aHistogram, aObj, null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Deletes the timer associated with a telemetry histogram. The timer can be
|
||||
* directly associated with a histogram, or with a pair of a histogram and
|
||||
* an object. Important: Only use this method when a legitimate cancellation
|
||||
* should be done.
|
||||
*
|
||||
* @param {String} aHistogram - a string which must be a valid histogram name.
|
||||
*
|
||||
* @param {Object} aObj - Optional parameter. If specified, the timer is
|
||||
* associated with this object, meaning that multiple
|
||||
* timers or a same histogram may be run concurrently,
|
||||
* as long as they are associated with different
|
||||
* objects.
|
||||
*
|
||||
* @returns {Boolean} True if the timer exist and it was cleared, False
|
||||
* otherwise.
|
||||
*/
|
||||
cancel(aHistogram, aObj) {
|
||||
return TelemetryStopwatchImpl.cancel(aHistogram, aObj, null);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the elapsed time for a particular stopwatch. Primarily for
|
||||
* debugging purposes. Must be called prior to finish.
|
||||
*
|
||||
* @param {String} aHistogram - a string which must be a valid histogram name.
|
||||
* If an invalid name is given, the function will
|
||||
* throw.
|
||||
*
|
||||
* @param (Object) aObj - Optional parameter which associates the histogram
|
||||
* timer with the given object.
|
||||
*
|
||||
* @param {Boolean} aCanceledOkay - Optional parameter which will suppress any
|
||||
* warnings that normally fire when a stopwatch
|
||||
* is finished after being cancelled. Defaults
|
||||
* to false.
|
||||
*
|
||||
* @returns {Integer} time in milliseconds or -1 if the stopwatch was not
|
||||
* found.
|
||||
*/
|
||||
timeElapsed(aHistogram, aObj, aCanceledOkay) {
|
||||
return TelemetryStopwatchImpl.timeElapsed(aHistogram, aObj, null,
|
||||
aCanceledOkay);
|
||||
},
|
||||
|
||||
/**
|
||||
* Stops the timer associated with the given histogram (and object),
|
||||
* calculates the time delta between start and finish, and adds the value
|
||||
* to the histogram.
|
||||
*
|
||||
* @param {String} aHistogram - a string which must be a valid histogram name.
|
||||
*
|
||||
* @param {Object} aObj - Optional parameter which associates the histogram
|
||||
* timer with the given object.
|
||||
*
|
||||
* @param {Boolean} aCanceledOkay - Optional parameter which will suppress any
|
||||
* warnings that normally fire when a stopwatch
|
||||
* is finished after being cancelled. Defaults
|
||||
* to false.
|
||||
*
|
||||
* @returns {Boolean} True if the timer was succesfully stopped and the data
|
||||
* was added to the histogram, False otherwise.
|
||||
*/
|
||||
finish(aHistogram, aObj, aCanceledOkay) {
|
||||
return TelemetryStopwatchImpl.finish(aHistogram, aObj, null, aCanceledOkay);
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts a timer associated with a keyed telemetry histogram. The timer can
|
||||
* be directly associated with a histogram and its key. Similarly to
|
||||
* @see{TelemetryStopwatch.stat} the histogram and its key can be associated
|
||||
* with an object. Each key may have multiple associated objects and each
|
||||
* object can be associated with multiple keys.
|
||||
*
|
||||
* @param {String} aHistogram - a string which must be a valid histogram name.
|
||||
*
|
||||
* @param {String} aKey - a string which must be a valid histgram key.
|
||||
*
|
||||
* @param {Object} aObj - Optional parameter. If specified, the timer is
|
||||
* associated with this object, meaning that multiple
|
||||
* timers for the same histogram may be run
|
||||
* concurrently,as long as they are associated with
|
||||
* different objects.
|
||||
*
|
||||
* @returns {Boolean} True if the timer was successfully started, false
|
||||
* otherwise. If a timer already exists, it can't be
|
||||
* started again, and the existing one will be cleared in
|
||||
* order to avoid measurements errors.
|
||||
*/
|
||||
startKeyed(aHistogram, aKey, aObj) {
|
||||
return TelemetryStopwatchImpl.start(aHistogram, aObj, aKey);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns whether a timer associated with a telemetry histogram is currently
|
||||
* running. Similarly to @see{TelemetryStopwatch.running} the timer and its
|
||||
* key can be associated with an object. Each key may have multiple associated
|
||||
* objects and each object can be associated with multiple keys.
|
||||
*
|
||||
* @param {String} aHistogram - a string which must be a valid histogram name.
|
||||
*
|
||||
* @param {String} aKey - a string which must be a valid histgram key.
|
||||
*
|
||||
* @param {Object} aObj - Optional parameter. If specified, the timer is
|
||||
* associated with this object, meaning that multiple
|
||||
* timers for the same histogram may be run
|
||||
* concurrently, as long as they are associated with
|
||||
* different objects.
|
||||
*
|
||||
* @returns {Boolean} True if the timer exists and is currently running.
|
||||
*/
|
||||
runningKeyed(aHistogram, aKey, aObj) {
|
||||
return TelemetryStopwatchImpl.running(aHistogram, aObj, aKey);
|
||||
},
|
||||
|
||||
/**
|
||||
* Deletes the timer associated with a keyed histogram. Important: Only use
|
||||
* this method when a legitimate cancellation should be done.
|
||||
*
|
||||
* @param {String} aHistogram - a string which must be a valid histogram name.
|
||||
*
|
||||
* @param {String} aKey - a string which must be a valid histgram key.
|
||||
*
|
||||
* @param {Object} aObj - Optional parameter. If specified, the timer
|
||||
* associated with this object is deleted.
|
||||
*
|
||||
* @return {Boolean} True if the timer exist and it was cleared, False
|
||||
* otherwise.
|
||||
*/
|
||||
cancelKeyed(aHistogram, aKey, aObj) {
|
||||
return TelemetryStopwatchImpl.cancel(aHistogram, aObj, aKey);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the elapsed time for a particular stopwatch. Primarily for
|
||||
* debugging purposes. Must be called prior to finish.
|
||||
*
|
||||
* @param {String} aHistogram - a string which must be a valid histogram name.
|
||||
*
|
||||
* @param {String} aKey - a string which must be a valid histgram key.
|
||||
*
|
||||
* @param {Object} aObj - Optional parameter. If specified, the timer
|
||||
* associated with this object is used to calculate
|
||||
* the elapsed time.
|
||||
*
|
||||
* @return {Integer} time in milliseconds or -1 if the stopwatch was not
|
||||
* found.
|
||||
*/
|
||||
timeElapsedKeyed(aHistogram, aKey, aObj, aCanceledOkay) {
|
||||
return TelemetryStopwatchImpl.timeElapsed(aHistogram, aObj, aKey,
|
||||
aCanceledOkay);
|
||||
},
|
||||
|
||||
/**
|
||||
* Stops the timer associated with the given keyed histogram (and object),
|
||||
* calculates the time delta between start and finish, and adds the value
|
||||
* to the keyed histogram.
|
||||
*
|
||||
* @param {String} aHistogram - a string which must be a valid histogram name.
|
||||
*
|
||||
* @param {String} aKey - a string which must be a valid histgram key.
|
||||
*
|
||||
* @param {Object} aObj - optional parameter which associates the histogram
|
||||
* timer with the given object.
|
||||
*
|
||||
* @param {Boolean} aCanceledOkay - Optional parameter which will suppress any
|
||||
* warnings that normally fire when a stopwatch
|
||||
* is finished after being cancelled. Defaults
|
||||
* to false.
|
||||
*
|
||||
* @returns {Boolean} True if the timer was succesfully stopped and the data
|
||||
* was added to the histogram, False otherwise.
|
||||
*/
|
||||
finishKeyed(aHistogram, aKey, aObj, aCanceledOkay) {
|
||||
return TelemetryStopwatchImpl.finish(aHistogram, aObj, aKey, aCanceledOkay);
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the testing mode. Used by tests.
|
||||
*/
|
||||
setTestModeEnabled(testing) {
|
||||
TelemetryStopwatchImpl.suppressErrors(true);
|
||||
},
|
||||
};
|
||||
|
||||
var TelemetryStopwatchImpl = {
|
||||
// Suppress errors. Used when testing.
|
||||
_suppressErrors: false,
|
||||
|
||||
suppressErrors(suppress) {
|
||||
this._suppressErrors = suppress;
|
||||
},
|
||||
|
||||
start(histogram, object, key) {
|
||||
if (Timers.has(histogram, object, key)) {
|
||||
Timers.delete(histogram, object, key);
|
||||
if (!this._suppressErrors) {
|
||||
Cu.reportError(`TelemetryStopwatch: key "${histogram}" was already ` +
|
||||
"initialized");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return Timers.put(histogram, object, key, Cu.now());
|
||||
},
|
||||
|
||||
running(histogram, object, key) {
|
||||
return Timers.has(histogram, object, key);
|
||||
},
|
||||
|
||||
cancel(histogram, object, key) {
|
||||
return Timers.delete(histogram, object, key);
|
||||
},
|
||||
|
||||
timeElapsed(histogram, object, key, aCanceledOkay) {
|
||||
const startTime = Timers.get(histogram, object, key);
|
||||
if (startTime === null) {
|
||||
if (!aCanceledOkay && !this._suppressErrors) {
|
||||
Cu.reportError("TelemetryStopwatch: requesting elapsed time for " +
|
||||
`nonexisting stopwatch. Histogram: "${histogram}", ` +
|
||||
`key: "${key}"`);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
try {
|
||||
const delta = Cu.now() - startTime;
|
||||
return Math.round(delta / 1000);
|
||||
} catch (e) {
|
||||
if (!this._suppressErrors) {
|
||||
Cu.reportError("TelemetryStopwatch: failed to calculate elapsed time " +
|
||||
`for Histogram: "${histogram}", key: "${key}", ` +
|
||||
`exception: ${Log.exceptionStr(e)}`);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
},
|
||||
|
||||
finish(histogram, object, key, aCanceledOkay) {
|
||||
const delta = this.timeElapsed(histogram, object, key, aCanceledOkay);
|
||||
if (delta == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (key) {
|
||||
Services.telemetry.getKeyedHistogramById(histogram).add(key, delta);
|
||||
} else {
|
||||
Services.telemetry.getHistogramById(histogram).add(delta);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!this._suppressErrors) {
|
||||
Cu.reportError("TelemetryStopwatch: failed to update the Histogram " +
|
||||
`"${histogram}", using key: "${key}", ` +
|
||||
`exception: ${Log.exceptionStr(e)}`);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return Timers.delete(histogram, object, key);
|
||||
}
|
||||
};
|
||||
|
|
@ -49,6 +49,7 @@ DevToolsModules(
|
|||
'stylesheet-utils.js',
|
||||
'suggestion-picker.js',
|
||||
'telemetry.js',
|
||||
'TelemetryStopwatch.jsm',
|
||||
'theme.js',
|
||||
'undo.js',
|
||||
'unicode-url.js',
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
"use strict";
|
||||
|
||||
const Services = require("Services");
|
||||
const { TelemetryStopwatch } = require("resource://gre/modules/TelemetryStopwatch.jsm");
|
||||
const { TelemetryStopwatch } = require("devtools/client/shared/TelemetryStopwatch.jsm");
|
||||
const { getNthPathExcluding } = require("devtools/shared/platform/stack");
|
||||
const { TelemetryEnvironment } = require("resource://gre/modules/TelemetryEnvironment.jsm");
|
||||
|
||||
|
|
|
|||
|
|
@ -485,7 +485,6 @@ SocketListener.prototype = {
|
|||
async _setAdditionalSocketOptions() {
|
||||
if (this.encryption) {
|
||||
this._socket.serverCert = await cert.local.getOrCreate();
|
||||
this._socket.setSessionCache(false);
|
||||
this._socket.setSessionTickets(false);
|
||||
const requestCert = Ci.nsITLSServerSocket.REQUEST_NEVER;
|
||||
this._socket.setRequestClientCertificate(requestCert);
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@ const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
|||
const { dumpn } = DevToolsUtils;
|
||||
const flags = require("devtools/shared/flags");
|
||||
const StreamUtils = require("devtools/shared/transport/stream-utils");
|
||||
const promise = require("promise");
|
||||
const defer = require("devtools/shared/defer");
|
||||
|
||||
loader.lazyGetter(this, "Pipe", () => {
|
||||
return CC("@mozilla.org/pipe;1", "nsIPipe", "init");
|
||||
|
|
@ -84,7 +82,7 @@ LocalDebuggerTransport.prototype = {
|
|||
dumpn("Sent bulk packet " + serial + " for actor " + actor);
|
||||
if (!this.other) {
|
||||
const error = new Error("startBulkSend: other side of transport missing");
|
||||
return promise.reject(error);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
const pipe = new Pipe(true, true, 0, 0, null);
|
||||
|
|
@ -96,51 +94,48 @@ LocalDebuggerTransport.prototype = {
|
|||
}
|
||||
|
||||
// Receiver
|
||||
const deferred = defer();
|
||||
const packet = {
|
||||
actor: actor,
|
||||
type: type,
|
||||
length: length,
|
||||
copyTo: (output) => {
|
||||
const copying =
|
||||
StreamUtils.copyStream(pipe.inputStream, output, length);
|
||||
deferred.resolve(copying);
|
||||
return copying;
|
||||
},
|
||||
stream: pipe.inputStream,
|
||||
done: deferred
|
||||
};
|
||||
|
||||
this.other.hooks.onBulkPacket(packet);
|
||||
new Promise((receiverResolve) => {
|
||||
const packet = {
|
||||
actor: actor,
|
||||
type: type,
|
||||
length: length,
|
||||
copyTo: (output) => {
|
||||
const copying =
|
||||
StreamUtils.copyStream(pipe.inputStream, output, length);
|
||||
receiverResolve(copying);
|
||||
return copying;
|
||||
},
|
||||
stream: pipe.inputStream,
|
||||
done: receiverResolve
|
||||
};
|
||||
|
||||
this.other.hooks.onBulkPacket(packet);
|
||||
})
|
||||
// Await the result of reading from the stream
|
||||
deferred.promise.then(() => pipe.inputStream.close(), this.close);
|
||||
.then(() => pipe.inputStream.close(), this.close);
|
||||
}, "LocalDebuggerTransport instance's this.other.hooks.onBulkPacket"));
|
||||
|
||||
// Sender
|
||||
const sendDeferred = defer();
|
||||
|
||||
// The remote transport is not capable of resolving immediately here, so we
|
||||
// shouldn't be able to either.
|
||||
DevToolsUtils.executeSoon(() => {
|
||||
const copyDeferred = defer();
|
||||
|
||||
sendDeferred.resolve({
|
||||
copyFrom: (input) => {
|
||||
const copying =
|
||||
StreamUtils.copyStream(input, pipe.outputStream, length);
|
||||
copyDeferred.resolve(copying);
|
||||
return copying;
|
||||
},
|
||||
stream: pipe.outputStream,
|
||||
done: copyDeferred
|
||||
return new Promise((senderResolve) => {
|
||||
// The remote transport is not capable of resolving immediately here, so we
|
||||
// shouldn't be able to either.
|
||||
DevToolsUtils.executeSoon(() => {
|
||||
return new Promise((copyResolve) => {
|
||||
senderResolve({
|
||||
copyFrom: (input) => {
|
||||
const copying =
|
||||
StreamUtils.copyStream(input, pipe.outputStream, length);
|
||||
copyResolve(copying);
|
||||
return copying;
|
||||
},
|
||||
stream: pipe.outputStream,
|
||||
done: copyResolve
|
||||
});
|
||||
})
|
||||
// Await the result of writing to the stream
|
||||
.then(() => pipe.outputStream.close(), this.close);
|
||||
});
|
||||
|
||||
// Await the result of writing to the stream
|
||||
copyDeferred.promise.then(() => pipe.outputStream.close(), this.close);
|
||||
});
|
||||
|
||||
return sendDeferred.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
|||
const { dumpn, dumpv } = DevToolsUtils;
|
||||
const flags = require("devtools/shared/flags");
|
||||
const StreamUtils = require("devtools/shared/transport/stream-utils");
|
||||
const defer = require("devtools/shared/defer");
|
||||
|
||||
DevToolsUtils.defineLazyGetter(this, "unicodeConverter", () => {
|
||||
// eslint-disable-next-line no-shadow
|
||||
|
|
@ -231,7 +230,11 @@ exports.JSONPacket = JSONPacket;
|
|||
function BulkPacket(transport) {
|
||||
Packet.call(this, transport);
|
||||
this._done = false;
|
||||
this._readyForWriting = defer();
|
||||
let _resolve;
|
||||
this._readyForWriting = new Promise((resolve) => {
|
||||
_resolve = resolve;
|
||||
});
|
||||
this._readyForWriting.resolve = _resolve;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -271,24 +274,23 @@ BulkPacket.prototype.read = function(stream) {
|
|||
// Temporarily pause monitoring of the input stream
|
||||
this._transport.pauseIncoming();
|
||||
|
||||
const deferred = defer();
|
||||
|
||||
this._transport._onBulkReadReady({
|
||||
actor: this.actor,
|
||||
type: this.type,
|
||||
length: this.length,
|
||||
copyTo: (output) => {
|
||||
dumpv("CT length: " + this.length);
|
||||
const copying = StreamUtils.copyStream(stream, output, this.length);
|
||||
deferred.resolve(copying);
|
||||
return copying;
|
||||
},
|
||||
stream: stream,
|
||||
done: deferred
|
||||
});
|
||||
|
||||
// Await the result of reading from the stream
|
||||
deferred.promise.then(() => {
|
||||
new Promise((resolve) => {
|
||||
this._transport._onBulkReadReady({
|
||||
actor: this.actor,
|
||||
type: this.type,
|
||||
length: this.length,
|
||||
copyTo: (output) => {
|
||||
dumpv("CT length: " + this.length);
|
||||
const copying = StreamUtils.copyStream(stream, output, this.length);
|
||||
resolve(copying);
|
||||
return copying;
|
||||
},
|
||||
stream: stream,
|
||||
done: resolve
|
||||
});
|
||||
// Await the result of reading from the stream
|
||||
})
|
||||
.then(() => {
|
||||
dumpv("onReadDone called, ending bulk mode");
|
||||
this._done = true;
|
||||
this._transport.resumeIncoming();
|
||||
|
|
@ -324,21 +326,20 @@ BulkPacket.prototype.write = function(stream) {
|
|||
// Temporarily pause the monitoring of the output stream
|
||||
this._transport.pauseOutgoing();
|
||||
|
||||
const deferred = defer();
|
||||
|
||||
this._readyForWriting.resolve({
|
||||
copyFrom: (input) => {
|
||||
dumpv("CF length: " + this.length);
|
||||
const copying = StreamUtils.copyStream(input, stream, this.length);
|
||||
deferred.resolve(copying);
|
||||
return copying;
|
||||
},
|
||||
stream: stream,
|
||||
done: deferred
|
||||
});
|
||||
|
||||
// Await the result of writing to the stream
|
||||
deferred.promise.then(() => {
|
||||
new Promise((resolve) => {
|
||||
this._readyForWriting.resolve({
|
||||
copyFrom: (input) => {
|
||||
dumpv("CF length: " + this.length);
|
||||
const copying = StreamUtils.copyStream(input, stream, this.length);
|
||||
resolve(copying);
|
||||
return copying;
|
||||
},
|
||||
stream: stream,
|
||||
done: resolve
|
||||
});
|
||||
// Await the result of writing to the stream
|
||||
})
|
||||
.then(() => {
|
||||
dumpv("onWriteDone called, ending bulk mode");
|
||||
this._done = true;
|
||||
this._transport.resumeOutgoing();
|
||||
|
|
@ -352,7 +353,7 @@ BulkPacket.prototype.write = function(stream) {
|
|||
|
||||
Object.defineProperty(BulkPacket.prototype, "streamReadyForWriting", {
|
||||
get: function() {
|
||||
return this._readyForWriting.promise;
|
||||
return this._readyForWriting;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ const Services = require("Services");
|
|||
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
||||
const { dumpv } = DevToolsUtils;
|
||||
const EventEmitter = require("devtools/shared/event-emitter");
|
||||
const defer = require("devtools/shared/defer");
|
||||
|
||||
DevToolsUtils.defineLazyGetter(this, "IOUtil", () => {
|
||||
return Cc["@mozilla.org/io-util;1"].getService(Ci.nsIIOUtil);
|
||||
|
|
@ -75,7 +74,14 @@ function StreamCopier(input, output, length) {
|
|||
}
|
||||
this._length = length;
|
||||
this._amountLeft = length;
|
||||
this._deferred = defer();
|
||||
let _resolve;
|
||||
let _reject;
|
||||
this._deferred = new Promise((resolve, reject) => {
|
||||
_resolve = resolve;
|
||||
_reject = reject;
|
||||
});
|
||||
this._deferred.resolve = _resolve;
|
||||
this._deferred.reject = _reject;
|
||||
|
||||
this._copy = this._copy.bind(this);
|
||||
this._flush = this._flush.bind(this);
|
||||
|
|
@ -85,7 +91,7 @@ function StreamCopier(input, output, length) {
|
|||
// Allows the copier to offer a promise interface for the simple succeed or
|
||||
// fail scenarios, but also emit events (due to the EventEmitter) for other
|
||||
// states, like progress.
|
||||
this.then = this._deferred.promise.then.bind(this._deferred.promise);
|
||||
this.then = this._deferred.then.bind(this._deferred);
|
||||
this.then(this._destroy, this._destroy);
|
||||
|
||||
// Stream ready callback starts as |_copy|, but may switch to |_flush| at end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
/* exported Cr, CC, NetUtil, defer, errorCount, initTestDebuggerServer,
|
||||
/* exported Cr, CC, NetUtil, errorCount, initTestDebuggerServer,
|
||||
writeTestTempFile, socket_transport, local_transport, really_long
|
||||
*/
|
||||
|
||||
|
|
@ -12,7 +12,6 @@ var CC = Components.Constructor;
|
|||
const { require } =
|
||||
ChromeUtils.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const { NetUtil } = require("resource://gre/modules/NetUtil.jsm");
|
||||
const promise = require("promise");
|
||||
const defer = require("devtools/shared/defer");
|
||||
|
||||
const Services = require("Services");
|
||||
|
|
@ -148,7 +147,7 @@ var socket_transport = async function() {
|
|||
};
|
||||
|
||||
function local_transport() {
|
||||
return promise.resolve(DebuggerServer.connectPipe());
|
||||
return Promise.resolve(DebuggerServer.connectPipe());
|
||||
}
|
||||
|
||||
/** * Sample Data ***/
|
||||
|
|
|
|||
|
|
@ -74,22 +74,21 @@ function json_reply(client, response) {
|
|||
});
|
||||
|
||||
// Send bulk data to server
|
||||
const copyDeferred = defer();
|
||||
request.on("bulk-send-ready", ({writer, done}) => {
|
||||
const input = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
input.setData(reallyLong, reallyLong.length);
|
||||
try {
|
||||
writer.copyFrom(input, () => {
|
||||
input.close();
|
||||
done();
|
||||
});
|
||||
do_throw(new Error("Copying should fail, the stream is not async."));
|
||||
} catch (e) {
|
||||
Assert.ok(true);
|
||||
copyDeferred.resolve();
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
request.on("bulk-send-ready", ({writer, done}) => {
|
||||
const input = Cc["@mozilla.org/io/string-input-stream;1"]
|
||||
.createInstance(Ci.nsIStringInputStream);
|
||||
input.setData(reallyLong, reallyLong.length);
|
||||
try {
|
||||
writer.copyFrom(input, () => {
|
||||
input.close();
|
||||
done();
|
||||
});
|
||||
do_throw(new Error("Copying should fail, the stream is not async."));
|
||||
} catch (e) {
|
||||
Assert.ok(true);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return copyDeferred.promise;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,31 +105,31 @@ var replyHandlers = {
|
|||
|
||||
json: function(request) {
|
||||
// Receive JSON reply from server
|
||||
const replyDeferred = defer();
|
||||
request.on("json-reply", (reply) => {
|
||||
Assert.ok(reply.allDone);
|
||||
replyDeferred.resolve();
|
||||
return new Promise((resolve) => {
|
||||
request.on("json-reply", (reply) => {
|
||||
Assert.ok(reply.allDone);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
return replyDeferred.promise;
|
||||
},
|
||||
|
||||
bulk: function(request) {
|
||||
// Receive bulk data reply from server
|
||||
const replyDeferred = defer();
|
||||
request.on("bulk-reply", ({length, copyTo}) => {
|
||||
Assert.equal(length, really_long().length);
|
||||
return new Promise((resolve) => {
|
||||
request.on("bulk-reply", ({length, copyTo}) => {
|
||||
Assert.equal(length, really_long().length);
|
||||
|
||||
const outputFile = getTestTempFile("bulk-output", true);
|
||||
outputFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("666", 8));
|
||||
const outputFile = getTestTempFile("bulk-output", true);
|
||||
outputFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("666", 8));
|
||||
|
||||
const output = FileUtils.openSafeFileOutputStream(outputFile);
|
||||
const output = FileUtils.openSafeFileOutputStream(outputFile);
|
||||
|
||||
copyTo(output).then(() => {
|
||||
FileUtils.closeSafeFileOutputStream(output);
|
||||
replyDeferred.resolve(verify_files());
|
||||
copyTo(output).then(() => {
|
||||
FileUtils.closeSafeFileOutputStream(output);
|
||||
resolve(verify_files());
|
||||
});
|
||||
});
|
||||
});
|
||||
return replyDeferred.promise;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -141,16 +141,27 @@ var test_bulk_request_cs = async function(transportFactory, actorType, replyType
|
|||
cleanup_files();
|
||||
writeTestTempFile("bulk-input", really_long());
|
||||
|
||||
const clientDeferred = defer();
|
||||
const serverDeferred = defer();
|
||||
const bulkCopyDeferred = defer();
|
||||
let clientResolve;
|
||||
const clientDeferred = new Promise((resolve) => {
|
||||
clientResolve = resolve;
|
||||
});
|
||||
|
||||
let serverResolve;
|
||||
const serverDeferred = new Promise((resolve) => {
|
||||
serverResolve = resolve;
|
||||
});
|
||||
|
||||
let bulkCopyResolve;
|
||||
const bulkCopyDeferred = new Promise((resolve) => {
|
||||
bulkCopyResolve = resolve;
|
||||
});
|
||||
|
||||
const transport = await transportFactory();
|
||||
|
||||
const client = new DebuggerClient(transport);
|
||||
client.connect().then(([app, traits]) => {
|
||||
Assert.equal(traits.bulk, true);
|
||||
client.listTabs().then(clientDeferred.resolve);
|
||||
client.listTabs().then(clientResolve);
|
||||
});
|
||||
|
||||
function bulkSendReadyCallback({copyFrom}) {
|
||||
|
|
@ -160,12 +171,12 @@ var test_bulk_request_cs = async function(transportFactory, actorType, replyType
|
|||
}, input => {
|
||||
copyFrom(input).then(() => {
|
||||
input.close();
|
||||
bulkCopyDeferred.resolve();
|
||||
bulkCopyResolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
clientDeferred.promise.then(response => {
|
||||
clientDeferred.then(response => {
|
||||
const request = client.startBulkRequest({
|
||||
actor: response.testBulk,
|
||||
type: actorType,
|
||||
|
|
@ -184,14 +195,14 @@ var test_bulk_request_cs = async function(transportFactory, actorType, replyType
|
|||
|
||||
DebuggerServer.on("connectionchange", type => {
|
||||
if (type === "closed") {
|
||||
serverDeferred.resolve();
|
||||
serverResolve();
|
||||
}
|
||||
});
|
||||
|
||||
return promise.all([
|
||||
clientDeferred.promise,
|
||||
bulkCopyDeferred.promise,
|
||||
serverDeferred.promise
|
||||
return Promise.all([
|
||||
clientDeferred,
|
||||
bulkCopyDeferred,
|
||||
serverDeferred
|
||||
]);
|
||||
};
|
||||
|
||||
|
|
@ -200,18 +211,25 @@ var test_json_request_cs = async function(transportFactory, actorType, replyType
|
|||
cleanup_files();
|
||||
writeTestTempFile("bulk-input", really_long());
|
||||
|
||||
const clientDeferred = defer();
|
||||
const serverDeferred = defer();
|
||||
let clientResolve;
|
||||
const clientDeferred = new Promise((resolve) => {
|
||||
clientResolve = resolve;
|
||||
});
|
||||
|
||||
let serverResolve;
|
||||
const serverDeferred = new Promise((resolve) => {
|
||||
serverResolve = resolve;
|
||||
});
|
||||
|
||||
const transport = await transportFactory();
|
||||
|
||||
const client = new DebuggerClient(transport);
|
||||
client.connect((app, traits) => {
|
||||
Assert.equal(traits.bulk, true);
|
||||
client.listTabs().then(clientDeferred.resolve);
|
||||
client.listTabs().then(clientResolve);
|
||||
});
|
||||
|
||||
clientDeferred.promise.then(response => {
|
||||
clientDeferred.then(response => {
|
||||
const request = client.request({
|
||||
to: response.testBulk,
|
||||
type: actorType
|
||||
|
|
@ -226,13 +244,13 @@ var test_json_request_cs = async function(transportFactory, actorType, replyType
|
|||
|
||||
DebuggerServer.on("connectionchange", type => {
|
||||
if (type === "closed") {
|
||||
serverDeferred.resolve();
|
||||
serverResolve();
|
||||
}
|
||||
});
|
||||
|
||||
return promise.all([
|
||||
clientDeferred.promise,
|
||||
serverDeferred.promise
|
||||
return Promise.all([
|
||||
clientDeferred,
|
||||
serverDeferred
|
||||
]);
|
||||
};
|
||||
|
||||
|
|
@ -248,19 +266,18 @@ function verify_files() {
|
|||
Assert.equal(outputFile.fileSize, reallyLong.length);
|
||||
|
||||
// Ensure output file contents actually match
|
||||
const compareDeferred = defer();
|
||||
NetUtil.asyncFetch({
|
||||
uri: NetUtil.newURI(getTestTempFile("bulk-output")),
|
||||
loadUsingSystemPrincipal: true
|
||||
}, input => {
|
||||
const outputData = NetUtil.readInputStreamToString(input, reallyLong.length);
|
||||
// Avoid do_check_eq here so we don't log the contents
|
||||
Assert.ok(outputData === reallyLong);
|
||||
input.close();
|
||||
compareDeferred.resolve();
|
||||
});
|
||||
|
||||
return compareDeferred.promise.then(cleanup_files);
|
||||
return new Promise((resolve) => {
|
||||
NetUtil.asyncFetch({
|
||||
uri: NetUtil.newURI(getTestTempFile("bulk-output")),
|
||||
loadUsingSystemPrincipal: true
|
||||
}, input => {
|
||||
const outputData = NetUtil.readInputStreamToString(input, reallyLong.length);
|
||||
// Avoid do_check_eq here so we don't log the contents
|
||||
Assert.ok(outputData === reallyLong);
|
||||
input.close();
|
||||
resolve();
|
||||
});
|
||||
}).then(cleanup_files);
|
||||
}
|
||||
|
||||
function cleanup_files() {
|
||||
|
|
|
|||
|
|
@ -50,27 +50,27 @@ async function test_socket_conn() {
|
|||
Assert.equal(settings.host, "127.0.0.1");
|
||||
Assert.equal(settings.port, gPort);
|
||||
|
||||
const closedDeferred = defer();
|
||||
transport.hooks = {
|
||||
onPacket: function(packet) {
|
||||
this.onPacket = function({unicode}) {
|
||||
Assert.equal(unicode, unicodeString);
|
||||
transport.close();
|
||||
};
|
||||
// Verify that things work correctly when bigger than the output
|
||||
// transport buffers and when transporting unicode...
|
||||
transport.send({to: "root",
|
||||
type: "echo",
|
||||
reallylong: really_long(),
|
||||
unicode: unicodeString});
|
||||
Assert.equal(packet.from, "root");
|
||||
},
|
||||
onClosed: function(status) {
|
||||
closedDeferred.resolve();
|
||||
},
|
||||
};
|
||||
transport.ready();
|
||||
return closedDeferred.promise;
|
||||
return new Promise((resolve) => {
|
||||
transport.hooks = {
|
||||
onPacket: function(packet) {
|
||||
this.onPacket = function({unicode}) {
|
||||
Assert.equal(unicode, unicodeString);
|
||||
transport.close();
|
||||
};
|
||||
// Verify that things work correctly when bigger than the output
|
||||
// transport buffers and when transporting unicode...
|
||||
transport.send({to: "root",
|
||||
type: "echo",
|
||||
reallylong: really_long(),
|
||||
unicode: unicodeString});
|
||||
Assert.equal(packet.from, "root");
|
||||
},
|
||||
onClosed: function(status) {
|
||||
resolve();
|
||||
},
|
||||
};
|
||||
transport.ready();
|
||||
});
|
||||
}
|
||||
|
||||
async function test_socket_shutdown() {
|
||||
|
|
|
|||
|
|
@ -60,23 +60,23 @@ var test_helper = async function(payload) {
|
|||
host: "127.0.0.1",
|
||||
port: listener.port
|
||||
});
|
||||
const closedDeferred = defer();
|
||||
transport.hooks = {
|
||||
onPacket: function(packet) {
|
||||
this.onPacket = function() {
|
||||
do_throw(new Error("This connection should be dropped."));
|
||||
transport.close();
|
||||
};
|
||||
return new Promise((resolve) => {
|
||||
transport.hooks = {
|
||||
onPacket: function(packet) {
|
||||
this.onPacket = function() {
|
||||
do_throw(new Error("This connection should be dropped."));
|
||||
transport.close();
|
||||
};
|
||||
|
||||
// Inject the payload directly into the stream.
|
||||
transport._outgoing.push(new RawPacket(transport, payload));
|
||||
transport._flushOutgoing();
|
||||
},
|
||||
onClosed: function(status) {
|
||||
Assert.ok(true);
|
||||
closedDeferred.resolve();
|
||||
},
|
||||
};
|
||||
transport.ready();
|
||||
return closedDeferred.promise;
|
||||
// Inject the payload directly into the stream.
|
||||
transport._outgoing.push(new RawPacket(transport, payload));
|
||||
transport._flushOutgoing();
|
||||
},
|
||||
onClosed: function(status) {
|
||||
Assert.ok(true);
|
||||
resolve();
|
||||
},
|
||||
};
|
||||
transport.ready();
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,8 +25,15 @@ function run_test() {
|
|||
/** * Tests ***/
|
||||
|
||||
var test_transport = async function(transportFactory) {
|
||||
const clientDeferred = defer();
|
||||
const serverDeferred = defer();
|
||||
let clientResolve;
|
||||
const clientDeferred = new Promise((resolve) => {
|
||||
clientResolve = resolve;
|
||||
});
|
||||
|
||||
let serverResolve;
|
||||
const serverDeferred = new Promise((resolve) => {
|
||||
serverResolve = resolve;
|
||||
});
|
||||
|
||||
// Ensure test files are not present from a failed run
|
||||
cleanup_files();
|
||||
|
|
@ -66,7 +73,7 @@ var test_transport = async function(transportFactory) {
|
|||
}).then(() => {
|
||||
// It's now safe to close
|
||||
transport.hooks.onClosed = () => {
|
||||
clientDeferred.resolve();
|
||||
clientResolve();
|
||||
};
|
||||
transport.close();
|
||||
});
|
||||
|
|
@ -114,7 +121,7 @@ var test_transport = async function(transportFactory) {
|
|||
|
||||
DebuggerServer.on("connectionchange", type => {
|
||||
if (type === "closed") {
|
||||
serverDeferred.resolve();
|
||||
serverResolve();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -134,7 +141,7 @@ var test_transport = async function(transportFactory) {
|
|||
|
||||
transport.ready();
|
||||
|
||||
return promise.all([clientDeferred.promise, serverDeferred.promise]);
|
||||
return Promise.all([clientDeferred, serverDeferred]);
|
||||
};
|
||||
|
||||
/** * Test Utils ***/
|
||||
|
|
@ -149,19 +156,19 @@ function verify() {
|
|||
Assert.equal(outputFile.fileSize, reallyLong.length);
|
||||
|
||||
// Ensure output file contents actually match
|
||||
const compareDeferred = defer();
|
||||
NetUtil.asyncFetch({
|
||||
uri: NetUtil.newURI(getTestTempFile("bulk-output")),
|
||||
loadUsingSystemPrincipal: true
|
||||
}, input => {
|
||||
const outputData = NetUtil.readInputStreamToString(input, reallyLong.length);
|
||||
return new Promise((resolve) => {
|
||||
NetUtil.asyncFetch({
|
||||
uri: NetUtil.newURI(getTestTempFile("bulk-output")),
|
||||
loadUsingSystemPrincipal: true
|
||||
}, input => {
|
||||
const outputData = NetUtil.readInputStreamToString(input, reallyLong.length);
|
||||
// Avoid do_check_eq here so we don't log the contents
|
||||
Assert.ok(outputData === reallyLong);
|
||||
input.close();
|
||||
compareDeferred.resolve();
|
||||
});
|
||||
|
||||
return compareDeferred.promise.then(cleanup_files);
|
||||
Assert.ok(outputData === reallyLong);
|
||||
input.close();
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
.then(cleanup_files);
|
||||
}
|
||||
|
||||
function cleanup_files() {
|
||||
|
|
|
|||
|
|
@ -25,8 +25,15 @@ function run_test() {
|
|||
var test_bulk_transfer_transport = async function(transportFactory) {
|
||||
info("Starting bulk transfer test at " + new Date().toTimeString());
|
||||
|
||||
const clientDeferred = defer();
|
||||
const serverDeferred = defer();
|
||||
let clientResolve;
|
||||
const clientDeferred = new Promise((resolve) => {
|
||||
clientResolve = resolve;
|
||||
});
|
||||
|
||||
let serverResolve;
|
||||
const serverDeferred = new Promise((resolve) => {
|
||||
serverResolve = resolve;
|
||||
});
|
||||
|
||||
// Ensure test files are not present from a failed run
|
||||
cleanup_files();
|
||||
|
|
@ -66,7 +73,7 @@ var test_bulk_transfer_transport = async function(transportFactory) {
|
|||
}).then(() => {
|
||||
// It's now safe to close
|
||||
transport.hooks.onClosed = () => {
|
||||
clientDeferred.resolve();
|
||||
clientResolve();
|
||||
};
|
||||
transport.close();
|
||||
});
|
||||
|
|
@ -87,7 +94,7 @@ var test_bulk_transfer_transport = async function(transportFactory) {
|
|||
|
||||
DebuggerServer.on("connectionchange", type => {
|
||||
if (type === "closed") {
|
||||
serverDeferred.resolve();
|
||||
serverResolve();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -105,7 +112,7 @@ var test_bulk_transfer_transport = async function(transportFactory) {
|
|||
|
||||
transport.ready();
|
||||
|
||||
return promise.all([clientDeferred.promise, serverDeferred.promise]);
|
||||
return Promise.all([clientDeferred, serverDeferred]);
|
||||
};
|
||||
|
||||
/** * Test Utils ***/
|
||||
|
|
@ -120,19 +127,19 @@ function verify() {
|
|||
Assert.equal(outputFile.fileSize, reallyLong.length);
|
||||
|
||||
// Ensure output file contents actually match
|
||||
const compareDeferred = defer();
|
||||
NetUtil.asyncFetch({
|
||||
uri: NetUtil.newURI(getTestTempFile("bulk-output")),
|
||||
loadUsingSystemPrincipal: true
|
||||
}, input => {
|
||||
const outputData = NetUtil.readInputStreamToString(input, reallyLong.length);
|
||||
// Avoid do_check_eq here so we don't log the contents
|
||||
Assert.ok(outputData === reallyLong);
|
||||
input.close();
|
||||
compareDeferred.resolve();
|
||||
});
|
||||
|
||||
return compareDeferred.promise.then(cleanup_files);
|
||||
return new Promise((resolve) => {
|
||||
NetUtil.asyncFetch({
|
||||
uri: NetUtil.newURI(getTestTempFile("bulk-output")),
|
||||
loadUsingSystemPrincipal: true
|
||||
}, input => {
|
||||
const outputData = NetUtil.readInputStreamToString(input, reallyLong.length);
|
||||
// Avoid do_check_eq here so we don't log the contents
|
||||
Assert.ok(outputData === reallyLong);
|
||||
input.close();
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
.then(cleanup_files);
|
||||
}
|
||||
|
||||
function cleanup_files() {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ const { ActorPool, appendExtraActors, createExtraActors } =
|
|||
const { RootActor } = require("devtools/server/actors/root");
|
||||
const { ThreadActor } = require("devtools/server/actors/thread");
|
||||
const { DebuggerServer } = require("devtools/server/main");
|
||||
const promise = require("promise");
|
||||
|
||||
var gTestGlobals = [];
|
||||
DebuggerServer.addTestGlobal = function(global) {
|
||||
|
|
@ -47,7 +46,7 @@ function TestTabList(connection) {
|
|||
TestTabList.prototype = {
|
||||
constructor: TestTabList,
|
||||
getList: function() {
|
||||
return promise.resolve([...this._targetActors]);
|
||||
return Promise.resolve([...this._targetActors]);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@
|
|||
#endif
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
#include "../../gfx/vr/gfxVRExternal.h"
|
||||
#include "mozilla/layers/ImageBridgeChild.h"
|
||||
#endif
|
||||
|
||||
// Generated
|
||||
|
|
@ -236,6 +236,9 @@ WebGLContext::DestroyResourcesAndContext()
|
|||
mDefaultVertexArray = nullptr;
|
||||
mBoundTransformFeedback = nullptr;
|
||||
mDefaultTransformFeedback = nullptr;
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
mVRScreen = nullptr;
|
||||
#endif
|
||||
|
||||
mQuerySlot_SamplesPassed = nullptr;
|
||||
mQuerySlot_TFPrimsWritten = nullptr;
|
||||
|
|
@ -788,7 +791,7 @@ WebGLContext::SetDimensions(int32_t signedWidth, int32_t signedHeight)
|
|||
return NS_OK;
|
||||
|
||||
// If we've already drawn, we should commit the current buffer.
|
||||
PresentScreenBuffer();
|
||||
PresentScreenBuffer(gl->Screen());
|
||||
|
||||
if (IsContextLost()) {
|
||||
GenerateWarning("WebGL context was lost due to swap failure.");
|
||||
|
|
@ -1463,7 +1466,7 @@ WebGLContext::BlitBackbufferToCurDriverFB() const
|
|||
// For an overview of how WebGL compositing works, see:
|
||||
// https://wiki.mozilla.org/Platform/GFX/WebGL/Compositing
|
||||
bool
|
||||
WebGLContext::PresentScreenBuffer()
|
||||
WebGLContext::PresentScreenBuffer(GLScreenBuffer* const targetScreen)
|
||||
{
|
||||
const FuncScope funcScope(*this, "<PresentScreenBuffer>");
|
||||
if (IsContextLost())
|
||||
|
|
@ -1475,8 +1478,8 @@ WebGLContext::PresentScreenBuffer()
|
|||
if (!ValidateAndInitFB(nullptr))
|
||||
return false;
|
||||
|
||||
const auto& screen = gl->Screen();
|
||||
if (screen->Size() != mDefaultFB->mSize &&
|
||||
const auto& screen = targetScreen ? targetScreen : gl->Screen();
|
||||
if ((!screen->IsReadBufferReady() || screen->Size() != mDefaultFB->mSize) &&
|
||||
!screen->Resize(mDefaultFB->mSize))
|
||||
{
|
||||
GenerateWarning("screen->Resize failed. Losing context.");
|
||||
|
|
@ -1520,10 +1523,10 @@ WebGLContext::PresentScreenBuffer()
|
|||
|
||||
// Prepare the context for capture before compositing
|
||||
void
|
||||
WebGLContext::BeginComposition()
|
||||
WebGLContext::BeginComposition(GLScreenBuffer* const screen)
|
||||
{
|
||||
// Present our screenbuffer, if needed.
|
||||
PresentScreenBuffer();
|
||||
PresentScreenBuffer(screen);
|
||||
mDrawCallsSinceLastFlush = 0;
|
||||
}
|
||||
|
||||
|
|
@ -2301,47 +2304,40 @@ WebGLContext::GetUnpackSize(bool isFunc3D, uint32_t width, uint32_t height,
|
|||
already_AddRefed<layers::SharedSurfaceTextureClient>
|
||||
WebGLContext::GetVRFrame()
|
||||
{
|
||||
if (!gl)
|
||||
return nullptr;
|
||||
if (!gl)
|
||||
return nullptr;
|
||||
|
||||
// Create a custom GLScreenBuffer for VR.
|
||||
if (!mVRScreen) {
|
||||
auto caps = gl->Screen()->mCaps;
|
||||
mVRScreen = GLScreenBuffer::Create(gl, gfx::IntSize(1, 1), caps);
|
||||
|
||||
int frameId = gfx::impl::VRDisplayExternal::sPushIndex;
|
||||
static int lastFrameId = -1;
|
||||
/**
|
||||
* Android doesn't like duplicated GetVRFrame within the same gfxVRExternal frame.
|
||||
* Ballout forced composition calls if we are in the same VRExternal push frame index.
|
||||
* Also discard frameId 0 because sometimes compositor is not paused yet due to channel communication delays.
|
||||
*/
|
||||
const bool ignoreFrame = lastFrameId == frameId || frameId == 0;
|
||||
lastFrameId = frameId;
|
||||
if (!ignoreFrame) {
|
||||
BeginComposition();
|
||||
EndComposition();
|
||||
}
|
||||
RefPtr<ImageBridgeChild> imageBridge = ImageBridgeChild::GetSingleton();
|
||||
if (imageBridge) {
|
||||
TextureFlags flags = TextureFlags::ORIGIN_BOTTOM_LEFT;
|
||||
UniquePtr<gl::SurfaceFactory> factory = gl::GLScreenBuffer::CreateFactory(gl, caps, imageBridge.get(), flags);
|
||||
mVRScreen->Morph(std::move(factory));
|
||||
}
|
||||
}
|
||||
|
||||
if (!gl) {
|
||||
return nullptr;
|
||||
}
|
||||
// Swap buffers as though composition has occurred.
|
||||
// We will then share the resulting front buffer to be submitted to the VR compositor.
|
||||
BeginComposition(mVRScreen.get());
|
||||
EndComposition();
|
||||
|
||||
gl::GLScreenBuffer* screen = gl->Screen();
|
||||
if (!screen) {
|
||||
return nullptr;
|
||||
}
|
||||
if (IsContextLost())
|
||||
return nullptr;
|
||||
|
||||
RefPtr<SharedSurfaceTextureClient> sharedSurface = screen->Front();
|
||||
if (!sharedSurface || !sharedSurface->Surf()) {
|
||||
return nullptr;
|
||||
}
|
||||
RefPtr<SharedSurfaceTextureClient> sharedSurface = mVRScreen->Front();
|
||||
if (!sharedSurface || !sharedSurface->Surf())
|
||||
return nullptr;
|
||||
|
||||
/**
|
||||
* Make sure that the WebGL buffer is committed to the attached SurfaceTexture on Android.
|
||||
*/
|
||||
if (!ignoreFrame) {
|
||||
// Make sure that the WebGL buffer is committed to the attached SurfaceTexture on Android.
|
||||
sharedSurface->Surf()->ProducerAcquire();
|
||||
sharedSurface->Surf()->Commit();
|
||||
sharedSurface->Surf()->ProducerRelease();
|
||||
}
|
||||
|
||||
return sharedSurface.forget();
|
||||
return sharedSurface.forget();
|
||||
}
|
||||
#else
|
||||
already_AddRefed<layers::SharedSurfaceTextureClient>
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ class VRLayerChild;
|
|||
} // namespace gfx
|
||||
|
||||
namespace gl {
|
||||
class GLScreenBuffer;
|
||||
class MozFramebuffer;
|
||||
} // namespace gl
|
||||
|
||||
|
|
@ -498,10 +499,10 @@ public:
|
|||
|
||||
bool IsPreservingDrawingBuffer() const { return mOptions.preserveDrawingBuffer; }
|
||||
|
||||
bool PresentScreenBuffer();
|
||||
bool PresentScreenBuffer(gl::GLScreenBuffer* const screen = nullptr);
|
||||
|
||||
// Prepare the context for capture before compositing
|
||||
void BeginComposition();
|
||||
void BeginComposition(gl::GLScreenBuffer* const screen = nullptr);
|
||||
// Clean up the context after captured for compositing
|
||||
void EndComposition();
|
||||
|
||||
|
|
@ -1980,6 +1981,9 @@ protected:
|
|||
bool mNeedsIndexValidation = false;
|
||||
|
||||
const bool mAllowFBInvalidation;
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
UniquePtr<gl::GLScreenBuffer> mVRScreen;
|
||||
#endif
|
||||
|
||||
bool Has64BitTimestamps() const;
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,6 @@ PresentationControlService.prototype = {
|
|||
|
||||
if (aCert) {
|
||||
this._serverSocket.serverCert = aCert;
|
||||
this._serverSocket.setSessionCache(false);
|
||||
this._serverSocket.setSessionTickets(false);
|
||||
let requestCert = Ci.nsITLSServerSocket.REQUEST_NEVER;
|
||||
this._serverSocket.setRequestClientCertificate(requestCert);
|
||||
|
|
|
|||
|
|
@ -2350,18 +2350,21 @@ HTMLEditRules::WillDeleteSelection(nsIEditor::EDirection aAction,
|
|||
}
|
||||
|
||||
// First check for table selection mode. If so, hand off to table editor.
|
||||
RefPtr<Element> cell;
|
||||
nsresult rv =
|
||||
HTMLEditorRef().GetFirstSelectedCell(nullptr, getter_AddRefs(cell));
|
||||
if (NS_SUCCEEDED(rv) && cell) {
|
||||
rv = HTMLEditorRef().DeleteTableCellContents();
|
||||
ErrorResult error;
|
||||
RefPtr<Element> cellElement =
|
||||
HTMLEditorRef().GetFirstSelectedTableCellElement(SelectionRef(),
|
||||
error);
|
||||
if (cellElement) {
|
||||
error.SuppressException();
|
||||
nsresult rv = HTMLEditorRef().DeleteTableCellContents();
|
||||
if (NS_WARN_IF(!CanHandleEditAction())) {
|
||||
return NS_ERROR_EDITOR_DESTROYED;
|
||||
}
|
||||
*aHandled = true;
|
||||
return rv;
|
||||
}
|
||||
cell = nullptr;
|
||||
nsresult rv = error.StealNSResult();
|
||||
cellElement = nullptr;
|
||||
|
||||
// origCollapsed is used later to determine whether we should join blocks. We
|
||||
// don't really care about bCollapsed because it will be modified by
|
||||
|
|
@ -2443,7 +2446,8 @@ HTMLEditRules::WillDeleteSelection(nsIEditor::EDirection aAction,
|
|||
if (!visNode) {
|
||||
// Can't find anything to delete!
|
||||
*aCancel = true;
|
||||
// XXX This is the result of HTMLEditorRef().GetFirstSelectedCell().
|
||||
// XXX This is the result of
|
||||
// HTMLEditorRef().GetFirstSelectedTableCellElement().
|
||||
// The value could be both an error and NS_OK.
|
||||
return rv;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3003,18 +3003,31 @@ HTMLEditor::SetHTMLBackgroundColorWithTransaction(const nsAString& aColor)
|
|||
RefPtr<nsAtom> bgColorAtom = NS_Atomize("bgcolor");
|
||||
if (element) {
|
||||
if (selectedCount > 0) {
|
||||
// Traverse all selected cells
|
||||
RefPtr<Element> cell;
|
||||
rv = GetFirstSelectedCell(nullptr, getter_AddRefs(cell));
|
||||
if (NS_SUCCEEDED(rv) && cell) {
|
||||
while (cell) {
|
||||
rv = setColor ?
|
||||
SetAttributeWithTransaction(*cell, *bgColorAtom, aColor) :
|
||||
RemoveAttributeWithTransaction(*cell, *bgColorAtom);
|
||||
RefPtr<Selection> selection = GetSelection();
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
IgnoredErrorResult ignoredError;
|
||||
RefPtr<Element> cellElement =
|
||||
GetFirstSelectedTableCellElement(*selection, ignoredError);
|
||||
if (cellElement) {
|
||||
if (setColor) {
|
||||
while (cellElement) {
|
||||
rv =
|
||||
SetAttributeWithTransaction(*cellElement, *bgColorAtom, aColor);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
GetNextSelectedCell(nullptr, getter_AddRefs(cellElement));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
while (cellElement) {
|
||||
rv = RemoveAttributeWithTransaction(*cellElement, *bgColorAtom);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
GetNextSelectedCell(nullptr, getter_AddRefs(cell));
|
||||
GetNextSelectedCell(nullptr, getter_AddRefs(cellElement));
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -530,6 +530,28 @@ protected: // May be called by friends.
|
|||
*/
|
||||
Element* GetSelectionContainerElement(Selection& aSelection) const;
|
||||
|
||||
/**
|
||||
* GetFirstSelectedTableCellElement() returns a <td> or <th> element if
|
||||
* first range of Selection (i.e., result of Selection::GetRangeAt(0))
|
||||
* selects a <td> element or <th> element. Even if Selection is in
|
||||
* a cell element, this returns nullptr. And even if 2nd or later
|
||||
* range of Selection selects a cell element, also returns nullptr.
|
||||
* Note that when this looks for a cell element, this resets the internal
|
||||
* index of ranges of Selection. When you call GetNextSelectedCell() after
|
||||
* a call of this, it'll return 2nd selected cell if there is.
|
||||
*
|
||||
* @param aSelection Selection for this editor.
|
||||
* @param aRv Returns error if there is no selection or
|
||||
* first range of Selection is unexpected.
|
||||
* @return A <td> or <th> element is selected by first
|
||||
* range of Selection. Note that the range must
|
||||
* be: startContaienr and endContainer are same
|
||||
* <tr> element, startOffset + 1 equals endOffset.
|
||||
*/
|
||||
already_AddRefed<Element>
|
||||
GetFirstSelectedTableCellElement(Selection& aSelection,
|
||||
ErrorResult& aRv) const;
|
||||
|
||||
void IsNextCharInNodeWhitespace(nsIContent* aContent,
|
||||
int32_t aOffset,
|
||||
bool* outIsSpace,
|
||||
|
|
@ -1214,7 +1236,7 @@ protected: // Shouldn't be used by friend classes
|
|||
nsresult GetLastCellInRow(nsINode* aRowNode,
|
||||
nsINode** aCellNode);
|
||||
|
||||
nsresult GetCellFromRange(nsRange* aRange, Element** aCell);
|
||||
static nsresult GetCellFromRange(nsRange* aRange, Element** aCell);
|
||||
|
||||
/**
|
||||
* This sets background on the appropriate container element (table, cell,)
|
||||
|
|
@ -1855,8 +1877,9 @@ protected:
|
|||
bool mCSSAware;
|
||||
UniquePtr<CSSEditUtils> mCSSEditUtils;
|
||||
|
||||
// Used by GetFirstSelectedCell and GetNextSelectedCell
|
||||
int32_t mSelectedCellIndex;
|
||||
// mSelectedCellIndex is reset by GetFirstSelectedTableCellElement(),
|
||||
// then, it'll be referred and incremented by GetNextSelectedCell().
|
||||
mutable int32_t mSelectedCellIndex;
|
||||
|
||||
nsString mLastStyleSheetURL;
|
||||
nsString mLastOverrideStyleSheetURL;
|
||||
|
|
|
|||
|
|
@ -203,7 +203,9 @@ HTMLEditor::DoInsertHTMLWithContext(const nsAString& aInputString,
|
|||
|
||||
// Get selection
|
||||
RefPtr<Selection> selection = GetSelection();
|
||||
NS_ENSURE_STATE(selection);
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// create a dom document fragment that represents the structure to paste
|
||||
nsCOMPtr<nsINode> fragmentAsNode, streamStartParent, streamEndParent;
|
||||
|
|
@ -282,9 +284,10 @@ HTMLEditor::DoInsertHTMLWithContext(const nsAString& aInputString,
|
|||
// Are there any table elements in the list?
|
||||
// check for table cell selection mode
|
||||
bool cellSelectionMode = false;
|
||||
RefPtr<Element> cell;
|
||||
rv = GetFirstSelectedCell(nullptr, getter_AddRefs(cell));
|
||||
if (NS_SUCCEEDED(rv) && cell) {
|
||||
IgnoredErrorResult ignoredError;
|
||||
RefPtr<Element> cellElement =
|
||||
GetFirstSelectedTableCellElement(*selection, ignoredError);
|
||||
if (cellElement) {
|
||||
cellSelectionMode = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -764,23 +764,26 @@ HTMLEditor::DeleteTableCell(int32_t aNumber)
|
|||
*this, EditSubAction::eDeleteNode,
|
||||
nsIEditor::eNext);
|
||||
|
||||
RefPtr<Element> firstCell;
|
||||
rv = GetFirstSelectedCell(nullptr, getter_AddRefs(firstCell));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
ErrorResult error;
|
||||
RefPtr<Element> firstSelectedCellElement =
|
||||
GetFirstSelectedTableCellElement(*selection, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
// When 2 or more cells are selected, ignore aNumber and use selected cells.
|
||||
if (firstCell && selection->RangeCount() > 1) {
|
||||
if (firstSelectedCellElement && selection->RangeCount() > 1) {
|
||||
ErrorResult error;
|
||||
TableSize tableSize(*this, *table, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
CellIndexes firstCellIndexes(*firstCell, error);
|
||||
CellIndexes firstCellIndexes(*firstSelectedCellElement, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
cell = firstCell;
|
||||
cell = firstSelectedCellElement;
|
||||
startRowIndex = firstCellIndexes.mRow;
|
||||
startColIndex = firstCellIndexes.mColumn;
|
||||
|
||||
|
|
@ -976,19 +979,20 @@ HTMLEditor::DeleteTableCellContents()
|
|||
//Don't let Rules System change the selection
|
||||
AutoTransactionsConserveSelection dontChangeSelection(*this);
|
||||
|
||||
ErrorResult error;
|
||||
RefPtr<Element> firstSelectedCellElement =
|
||||
GetFirstSelectedTableCellElement(*selection, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
RefPtr<Element> firstCell;
|
||||
rv = GetFirstSelectedCell(nullptr, getter_AddRefs(firstCell));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
|
||||
if (firstCell) {
|
||||
if (firstSelectedCellElement) {
|
||||
ErrorResult error;
|
||||
CellIndexes firstCellIndexes(*firstCell, error);
|
||||
CellIndexes firstCellIndexes(*firstSelectedCellElement, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
cell = firstCell;
|
||||
cell = firstSelectedCellElement;
|
||||
startRowIndex = firstCellIndexes.mRow;
|
||||
startColIndex = firstCellIndexes.mColumn;
|
||||
}
|
||||
|
|
@ -999,10 +1003,12 @@ HTMLEditor::DeleteTableCellContents()
|
|||
|
||||
while (cell) {
|
||||
DeleteCellContents(cell);
|
||||
if (firstCell) {
|
||||
if (firstSelectedCellElement) {
|
||||
// We doing a selected cells, so do all of them
|
||||
rv = GetNextSelectedCell(nullptr, getter_AddRefs(cell));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsresult rv = GetNextSelectedCell(nullptr, getter_AddRefs(cell));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
cell = nullptr;
|
||||
}
|
||||
|
|
@ -1065,14 +1071,16 @@ HTMLEditor::DeleteTableColumn(int32_t aNumber)
|
|||
nsIEditor::eNext);
|
||||
|
||||
// Test if deletion is controlled by selected cells
|
||||
RefPtr<Element> firstCell;
|
||||
rv = GetFirstSelectedCell(nullptr, getter_AddRefs(firstCell));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
RefPtr<Element> firstSelectedCellElement =
|
||||
GetFirstSelectedTableCellElement(*selection, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
uint32_t rangeCount = selection->RangeCount();
|
||||
|
||||
if (firstCell && rangeCount > 1) {
|
||||
CellIndexes firstCellIndexes(*firstCell, error);
|
||||
if (firstSelectedCellElement && rangeCount > 1) {
|
||||
CellIndexes firstCellIndexes(*firstSelectedCellElement, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
|
@ -1084,12 +1092,12 @@ HTMLEditor::DeleteTableColumn(int32_t aNumber)
|
|||
startColIndex, ePreviousRow,
|
||||
false);
|
||||
|
||||
if (firstCell && rangeCount > 1) {
|
||||
if (firstSelectedCellElement && rangeCount > 1) {
|
||||
// Use selected cells to determine what rows to delete
|
||||
cell = firstCell;
|
||||
cell = firstSelectedCellElement;
|
||||
|
||||
while (cell) {
|
||||
if (cell != firstCell) {
|
||||
if (cell != firstSelectedCellElement) {
|
||||
CellIndexes cellIndexes(*cell, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
|
|
@ -1250,14 +1258,16 @@ HTMLEditor::DeleteTableRow(int32_t aNumber)
|
|||
*this, EditSubAction::eDeleteNode,
|
||||
nsIEditor::eNext);
|
||||
|
||||
RefPtr<Element> firstCell;
|
||||
rv = GetFirstSelectedCell(nullptr, getter_AddRefs(firstCell));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
RefPtr<Element> firstSelectedCellElement =
|
||||
GetFirstSelectedTableCellElement(*selection, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
uint32_t rangeCount = selection->RangeCount();
|
||||
if (firstCell && rangeCount > 1) {
|
||||
if (firstSelectedCellElement && rangeCount > 1) {
|
||||
// Fetch indexes again - may be different for selected cells
|
||||
CellIndexes firstCellIndexes(*firstCell, error);
|
||||
CellIndexes firstCellIndexes(*firstSelectedCellElement, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
|
@ -1272,12 +1282,12 @@ HTMLEditor::DeleteTableRow(int32_t aNumber)
|
|||
// Don't change selection during deletions
|
||||
AutoTransactionsConserveSelection dontChangeSelection(*this);
|
||||
|
||||
if (firstCell && rangeCount > 1) {
|
||||
if (firstSelectedCellElement && rangeCount > 1) {
|
||||
// Use selected cells to determine what rows to delete
|
||||
cell = firstCell;
|
||||
cell = firstSelectedCellElement;
|
||||
|
||||
while (cell) {
|
||||
if (cell != firstCell) {
|
||||
if (cell != firstSelectedCellElement) {
|
||||
CellIndexes cellIndexes(*cell, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
|
|
@ -1289,7 +1299,7 @@ HTMLEditor::DeleteTableRow(int32_t aNumber)
|
|||
// to continue after we delete this row
|
||||
int32_t nextRow = startRowIndex;
|
||||
while (nextRow == startRowIndex) {
|
||||
rv = GetNextSelectedCell(nullptr, getter_AddRefs(cell));
|
||||
nsresult rv = GetNextSelectedCell(nullptr, getter_AddRefs(cell));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!cell) {
|
||||
break;
|
||||
|
|
@ -1309,7 +1319,7 @@ HTMLEditor::DeleteTableRow(int32_t aNumber)
|
|||
// Check for counts too high
|
||||
aNumber = std::min(aNumber, (tableSize.mRowCount - startRowIndex));
|
||||
for (int32_t i = 0; i < aNumber; i++) {
|
||||
rv = DeleteRow(table, startRowIndex);
|
||||
nsresult rv = DeleteRow(table, startRowIndex);
|
||||
// If failed in current row, try the next
|
||||
if (NS_FAILED(rv)) {
|
||||
startRowIndex++;
|
||||
|
|
@ -1536,14 +1546,15 @@ HTMLEditor::SelectBlockOfCells(Element* aStartCell,
|
|||
|
||||
RefPtr<Element> cell;
|
||||
int32_t currentRowIndex, currentColIndex;
|
||||
RefPtr<nsRange> range;
|
||||
nsresult rv =
|
||||
GetFirstSelectedCell(getter_AddRefs(range), getter_AddRefs(cell));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (rv == NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND) {
|
||||
cell = GetFirstSelectedTableCellElement(*selection, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
if (!cell) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<nsRange> range = selection->GetRangeAt(0);
|
||||
MOZ_ASSERT(range);
|
||||
while (cell) {
|
||||
CellIndexes currentCellIndexes(*cell, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
|
|
@ -1557,12 +1568,16 @@ HTMLEditor::SelectBlockOfCells(Element* aStartCell,
|
|||
// Since we've removed the range, decrement pointer to next range
|
||||
mSelectedCellIndex--;
|
||||
}
|
||||
rv = GetNextSelectedCell(getter_AddRefs(range), getter_AddRefs(cell));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsresult rv =
|
||||
GetNextSelectedCell(getter_AddRefs(range), getter_AddRefs(cell));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t rowSpan, colSpan, actualRowSpan, actualColSpan;
|
||||
bool isSelected;
|
||||
nsresult rv = NS_OK;
|
||||
for (int32_t row = minRow; row <= maxRow; row++) {
|
||||
for (int32_t col = minColumn; col <= maxColumn;
|
||||
col += std::max(actualColSpan, 1)) {
|
||||
|
|
@ -2365,7 +2380,7 @@ HTMLEditor::JoinTableCells(bool aMergeNonContiguousContents)
|
|||
NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
|
||||
|
||||
RefPtr<Element> deletedCell;
|
||||
GetCellFromRange(range, getter_AddRefs(deletedCell));
|
||||
HTMLEditor::GetCellFromRange(range, getter_AddRefs(deletedCell));
|
||||
if (!deletedCell) {
|
||||
selection->RemoveRange(*range, IgnoreErrors());
|
||||
rangeCount--;
|
||||
|
|
@ -3220,6 +3235,7 @@ HTMLEditor::GetCellContext(Selection** aSelection,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
HTMLEditor::GetCellFromRange(nsRange* aRange,
|
||||
Element** aCell)
|
||||
|
|
@ -3264,44 +3280,87 @@ HTMLEditor::GetCellFromRange(nsRange* aRange,
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLEditor::GetFirstSelectedCell(nsRange** aRange,
|
||||
Element** aCell)
|
||||
HTMLEditor::GetFirstSelectedCell(nsRange** aFirstSelectedRange,
|
||||
Element** aFirstSelectedCellElement)
|
||||
{
|
||||
NS_ENSURE_TRUE(aCell, NS_ERROR_NULL_POINTER);
|
||||
*aCell = nullptr;
|
||||
if (aRange) {
|
||||
*aRange = nullptr;
|
||||
if (NS_WARN_IF(!aFirstSelectedCellElement)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*aFirstSelectedCellElement = nullptr;
|
||||
if (aFirstSelectedRange) {
|
||||
*aFirstSelectedRange = nullptr;
|
||||
}
|
||||
|
||||
// XXX Oddly, when there is no ranges of Selection, we return error.
|
||||
// However, despite of that we return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND
|
||||
// when first range of Selection does not select a table cell element.
|
||||
RefPtr<Selection> selection = GetSelection();
|
||||
NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
|
||||
|
||||
RefPtr<nsRange> range = selection->GetRangeAt(0);
|
||||
NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
|
||||
|
||||
mSelectedCellIndex = 0;
|
||||
|
||||
nsresult rv = GetCellFromRange(range, aCell);
|
||||
// Failure here probably means selection is in a text node,
|
||||
// so there's no selected cell
|
||||
if (NS_FAILED(rv)) {
|
||||
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
|
||||
}
|
||||
// No cell means range was collapsed (cell was deleted)
|
||||
if (!*aCell) {
|
||||
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (aRange) {
|
||||
range.forget(aRange);
|
||||
ErrorResult error;
|
||||
RefPtr<Element> firstSelectedCellElement =
|
||||
GetFirstSelectedTableCellElement(*selection, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
// Setup for next cell
|
||||
mSelectedCellIndex = 1;
|
||||
if (!firstSelectedCellElement) {
|
||||
// Just not found. Don't return error.
|
||||
return NS_OK;
|
||||
}
|
||||
firstSelectedCellElement.forget(aFirstSelectedCellElement);
|
||||
|
||||
if (aFirstSelectedRange) {
|
||||
// Returns the first range only when the caller requested the range.
|
||||
RefPtr<nsRange> firstRange = selection->GetRangeAt(0);
|
||||
MOZ_ASSERT(firstRange);
|
||||
firstRange.forget(aFirstSelectedRange);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<Element>
|
||||
HTMLEditor::GetFirstSelectedTableCellElement(Selection& aSelection,
|
||||
ErrorResult& aRv) const
|
||||
{
|
||||
MOZ_ASSERT(!aRv.Failed());
|
||||
|
||||
nsRange* firstRange = aSelection.GetRangeAt(0);
|
||||
if (NS_WARN_IF(!firstRange)) {
|
||||
// XXX Why don't we treat "not found" in this case?
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// XXX It must be unclear when this is reset...
|
||||
mSelectedCellIndex = 0;
|
||||
|
||||
RefPtr<Element> selectedCell;
|
||||
nsresult rv =
|
||||
HTMLEditor::GetCellFromRange(firstRange, getter_AddRefs(selectedCell));
|
||||
if (NS_FAILED(rv)) {
|
||||
// This case occurs only when Selection is in a text node in normal cases.
|
||||
return nullptr;
|
||||
}
|
||||
if (!selectedCell) {
|
||||
// This case means that the range does not select only a cell.
|
||||
// E.g., selects non-table cell element, selects two or more cells, or
|
||||
// does not select any cell element.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Setup for GetNextSelectedCell()
|
||||
// XXX Oh, increment it now? Rather than when GetNextSelectedCell() is
|
||||
// called?
|
||||
mSelectedCellIndex = 1;
|
||||
|
||||
return selectedCell.forget();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HTMLEditor::GetNextSelectedCell(nsRange** aRange,
|
||||
Element** aCell)
|
||||
|
|
@ -3328,7 +3387,7 @@ HTMLEditor::GetNextSelectedCell(nsRange** aRange,
|
|||
range = selection->GetRangeAt(mSelectedCellIndex);
|
||||
NS_ENSURE_TRUE(range, NS_ERROR_FAILURE);
|
||||
|
||||
nsresult rv = GetCellFromRange(range, aCell);
|
||||
nsresult rv = HTMLEditor::GetCellFromRange(range, aCell);
|
||||
// Failure here means the range doesn't contain a cell
|
||||
NS_ENSURE_SUCCESS(rv, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
|
||||
|
||||
|
|
@ -3366,21 +3425,30 @@ HTMLEditor::GetFirstSelectedCellInTable(int32_t* aRowIndex,
|
|||
*aColumnIndex = 0;
|
||||
}
|
||||
|
||||
RefPtr<Element> cell;
|
||||
nsresult rv = GetFirstSelectedCell(nullptr, getter_AddRefs(cell));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
NS_ENSURE_TRUE(cell, NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND);
|
||||
RefPtr<Selection> selection = GetSelection();
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
ErrorResult error;
|
||||
RefPtr<Element> firstSelectedCellElement =
|
||||
GetFirstSelectedTableCellElement(*selection, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
if (NS_WARN_IF(!firstSelectedCellElement)) {
|
||||
return NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND;
|
||||
}
|
||||
|
||||
// We don't want to cell.forget() here, because we use "cell" below.
|
||||
*aCell = do_AddRef(cell).take();
|
||||
firstSelectedCellElement.forget(aCell);
|
||||
|
||||
if (!aRowIndex && !aColumnIndex) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Also return the row and/or column if requested
|
||||
ErrorResult error;
|
||||
CellIndexes cellIndexes(*cell, error);
|
||||
CellIndexes cellIndexes(*firstSelectedCellElement, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
|
@ -3488,13 +3556,17 @@ HTMLEditor::GetSelectedOrParentTableElement(nsAString& aTagName,
|
|||
*aSelectedCount = 0;
|
||||
|
||||
RefPtr<Selection> selection = GetSelection();
|
||||
NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Try to get the first selected cell
|
||||
RefPtr<Element> tableOrCellElement;
|
||||
nsresult rv = GetFirstSelectedCell(nullptr,
|
||||
getter_AddRefs(tableOrCellElement));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
ErrorResult error;
|
||||
RefPtr<Element> tableOrCellElement =
|
||||
GetFirstSelectedTableCellElement(*selection, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
|
||||
if (tableOrCellElement) {
|
||||
// Each cell is in its own selection range,
|
||||
|
|
@ -3550,6 +3622,11 @@ HTMLEditor::GetSelectedCellsType(Element* aElement,
|
|||
NS_ENSURE_ARG_POINTER(aSelectionType);
|
||||
*aSelectionType = 0;
|
||||
|
||||
RefPtr<Selection> selection = GetSelection();
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Be sure we have a table element
|
||||
// (if aElement is null, this uses selection's anchor node)
|
||||
RefPtr<Element> table;
|
||||
|
|
@ -3559,10 +3636,6 @@ HTMLEditor::GetSelectedCellsType(Element* aElement,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
} else {
|
||||
RefPtr<Selection> selection = GetSelection();
|
||||
if (NS_WARN_IF(!selection)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
table =
|
||||
GetElementOrParentByTagNameAtSelection(*selection, *nsGkAtoms::table);
|
||||
if (NS_WARN_IF(!table)) {
|
||||
|
|
@ -3577,10 +3650,12 @@ HTMLEditor::GetSelectedCellsType(Element* aElement,
|
|||
}
|
||||
|
||||
// Traverse all selected cells
|
||||
RefPtr<Element> selectedCell;
|
||||
nsresult rv = GetFirstSelectedCell(nullptr, getter_AddRefs(selectedCell));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (rv == NS_SUCCESS_EDITOR_ELEMENT_NOT_FOUND) {
|
||||
RefPtr<Element> selectedCell =
|
||||
GetFirstSelectedTableCellElement(*selection, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
}
|
||||
if (!selectedCell) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
@ -3592,7 +3667,7 @@ HTMLEditor::GetSelectedCellsType(Element* aElement,
|
|||
|
||||
bool allCellsInRowAreSelected = false;
|
||||
bool allCellsInColAreSelected = false;
|
||||
while (NS_SUCCEEDED(rv) && selectedCell) {
|
||||
while (selectedCell) {
|
||||
CellIndexes selectedCellIndexes(*selectedCell, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
|
|
@ -3607,7 +3682,10 @@ HTMLEditor::GetSelectedCellsType(Element* aElement,
|
|||
break;
|
||||
}
|
||||
}
|
||||
rv = GetNextSelectedCell(nullptr, getter_AddRefs(selectedCell));
|
||||
DebugOnly<nsresult> rv =
|
||||
GetNextSelectedCell(nullptr, getter_AddRefs(selectedCell));
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Failed to get next selected table cell element");
|
||||
}
|
||||
|
||||
if (allCellsInRowAreSelected) {
|
||||
|
|
@ -3620,8 +3698,9 @@ HTMLEditor::GetSelectedCellsType(Element* aElement,
|
|||
indexArray.Clear();
|
||||
|
||||
// Start at first cell again
|
||||
rv = GetFirstSelectedCell(nullptr, getter_AddRefs(selectedCell));
|
||||
while (NS_SUCCEEDED(rv) && selectedCell) {
|
||||
IgnoredErrorResult ignoredError;
|
||||
selectedCell = GetFirstSelectedTableCellElement(*selection, ignoredError);
|
||||
while (selectedCell) {
|
||||
CellIndexes selectedCellIndexes(*selectedCell, error);
|
||||
if (NS_WARN_IF(error.Failed())) {
|
||||
return error.StealNSResult();
|
||||
|
|
@ -3637,7 +3716,10 @@ HTMLEditor::GetSelectedCellsType(Element* aElement,
|
|||
break;
|
||||
}
|
||||
}
|
||||
rv = GetNextSelectedCell(nullptr, getter_AddRefs(selectedCell));
|
||||
DebugOnly<nsresult> rv =
|
||||
GetNextSelectedCell(nullptr, getter_AddRefs(selectedCell));
|
||||
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Failed to get next selected table cell element");
|
||||
}
|
||||
if (allCellsInColAreSelected) {
|
||||
*aSelectionType = static_cast<uint32_t>(TableSelection::Column);
|
||||
|
|
|
|||
|
|
@ -292,10 +292,11 @@ skip-if = toolkit == 'android' && debug # bug 1480702, causes permanent failure
|
|||
[test_nsITableEditor_getCellAt.html]
|
||||
[test_nsITableEditor_getCellIndexes.html]
|
||||
[test_nsITableEditor_getFirstRow.html]
|
||||
[test_nsITableEditor_getFirstSelectedCell.html]
|
||||
[test_nsITableEditor_getTableSize.html]
|
||||
[test_resizers_appearance.html]
|
||||
[test_resizers_resizing_elements.html]
|
||||
skip-if = android_version == '18' || (verify && debug && os == 'win') # bug 1147989
|
||||
skip-if = toolkit == 'android' || (verify && debug && os == 'win') # bug 1147989 and bug 1485293
|
||||
[test_root_element_replacement.html]
|
||||
[test_select_all_without_body.html]
|
||||
[test_spellcheck_pref.html]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,198 @@
|
|||
<!DOCTYPE>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for nsITableEditor.getFirstSelectedCell()</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="display">
|
||||
</div>
|
||||
<div id="content" contenteditable></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.waitForFocus(function() {
|
||||
let editor = document.getElementById("content");
|
||||
let selection = document.getSelection();
|
||||
|
||||
selection.collapse(editor, 0);
|
||||
let rangeWrapper = {};
|
||||
let cell = SpecialPowers.unwrap(getTableEditor().getFirstSelectedCell(rangeWrapper));
|
||||
is(cell, null,
|
||||
"nsITableEditor.getFirstSelectedCell() should return null if Selection does not select cells");
|
||||
is(rangeWrapper.value, null,
|
||||
"nsITableEditor.getFirstSelectedCell() should return null range if Selection does not select cells");
|
||||
|
||||
editor.innerHTML =
|
||||
'<table id="table">' +
|
||||
'<tr id="r1"><td id="c1-1">cell1-1</td><td id="c1-2">cell1-2</td><td id="c1-3">cell1-3</td><td id="c1-4" colspan="2" rowspan="2">cell1-4</td></tr>' +
|
||||
'<tr id="r2"><th id="c2-1" rowspan="2">cell2-1</th><td id="c2-2">cell2-2<td id="c2-3">cell2-3</td></tr>' +
|
||||
'<tr id="r3"><td id="c3-2">cell3-2</td><td id="c3-3">cell3-3</td><td id="c3-4" colspan="2">cell3-4</td></tr>' +
|
||||
'<tr id="r4"><td id="c4-1" rowspan="4">cell4-1</td><td id="c4-2">cell4-2</td><td id="c4-3">cell4-3</td><th id="c4-4">cell4-4</th><td id="c4-5">cell4-5</td></tr>' +
|
||||
'<tr id="r5"><th id="c5-2">cell5-2</th><th id="c5-3" colspan="2">cell5-3</th><td id="c5-5">cell5-5</td></tr>' +
|
||||
'<tr id="r6"><td id="c6-2">cell6-2</td><td id="c6-3">cell6-3</td><td id="c6-4"><p>cell6-4</p></td><td id="c6-5">cell6-5</td></tr>' +
|
||||
'<tr id="r7"><td id="c7-2" colspan="4">cell7-2</td></tr>' +
|
||||
'</table>';
|
||||
|
||||
let tr = document.getElementById("r1");
|
||||
selection.setBaseAndExtent(tr, 0, tr, 1);
|
||||
cell = SpecialPowers.unwrap(getTableEditor().getFirstSelectedCell(rangeWrapper));
|
||||
is(cell, document.getElementById("c1-1"),
|
||||
"#1-1 nsITableEditor.getFirstSelectedCell() should return the first cell element in the first row");
|
||||
is(rangeWrapper.value.startContainer, tr,
|
||||
"#1-1 nsITableEditor.getFirstSelectedCell() should return the first <tr> element as start container of the range");
|
||||
is(rangeWrapper.value.startOffset, 0,
|
||||
"#1-1 nsITableEditor.getFirstSelectedCell() should return 0 as start offset of the range");
|
||||
is(rangeWrapper.value.endContainer, tr,
|
||||
"#1-1 nsITableEditor.getFirstSelectedCell() should return the first <tr> element as end container of the range");
|
||||
is(rangeWrapper.value.endOffset, 1,
|
||||
"#1-1 nsITableEditor.getFirstSelectedCell() should return 1 as end offset of the range");
|
||||
|
||||
tr = document.getElementById("r1");
|
||||
selection.setBaseAndExtent(tr, 3, tr, 4);
|
||||
cell = SpecialPowers.unwrap(getTableEditor().getFirstSelectedCell(rangeWrapper));
|
||||
is(cell, document.getElementById("c1-4"),
|
||||
"#1-4 nsITableEditor.getFirstSelectedCell() should return the last cell element whose colspan and rowspan are 2 in the first row");
|
||||
is(rangeWrapper.value.startContainer, tr,
|
||||
"#1-4 nsITableEditor.getFirstSelectedCell() should return the first <tr> element as start container of the range");
|
||||
is(rangeWrapper.value.startOffset, 3,
|
||||
"#1-4 nsITableEditor.getFirstSelectedCell() should return 3 as start offset of the range");
|
||||
is(rangeWrapper.value.endContainer, tr,
|
||||
"#1-4 nsITableEditor.getFirstSelectedCell() should return the first <tr> element as end container of the range");
|
||||
is(rangeWrapper.value.endOffset, 4,
|
||||
"#1-4 nsITableEditor.getFirstSelectedCell() should return 4 as end offset of the range");
|
||||
|
||||
tr = document.getElementById("r2");
|
||||
selection.setBaseAndExtent(tr, 0, tr, 1);
|
||||
cell = SpecialPowers.unwrap(getTableEditor().getFirstSelectedCell(rangeWrapper));
|
||||
is(cell, document.getElementById("c2-1"),
|
||||
"#2-1 nsITableEditor.getFirstSelectedCell() should return the first cell element in the second row");
|
||||
is(rangeWrapper.value.startContainer, tr,
|
||||
"#2-1 nsITableEditor.getFirstSelectedCell() should return the second <tr> element as start container of the range");
|
||||
is(rangeWrapper.value.startOffset, 0,
|
||||
"#2-1 nsITableEditor.getFirstSelectedCell() should return 0 as start offset of the range");
|
||||
is(rangeWrapper.value.endContainer, tr,
|
||||
"#2-1 nsITableEditor.getFirstSelectedCell() should return the second <tr> element as end container of the range");
|
||||
is(rangeWrapper.value.endOffset, 1,
|
||||
"#2-1 nsITableEditor.getFirstSelectedCell() should return 1 as end offset of the range");
|
||||
|
||||
tr = document.getElementById("r7");
|
||||
selection.setBaseAndExtent(tr, 0, tr, 1);
|
||||
cell = SpecialPowers.unwrap(getTableEditor().getFirstSelectedCell(rangeWrapper));
|
||||
is(cell, document.getElementById("c7-2"),
|
||||
"#7-2 nsITableEditor.getFirstSelectedCell() should return the second cell element in the last row");
|
||||
is(rangeWrapper.value.startContainer, tr,
|
||||
"#7-2 nsITableEditor.getFirstSelectedCell() should return the last <tr> element as start container of the range");
|
||||
is(rangeWrapper.value.startOffset, 0,
|
||||
"#7-2 nsITableEditor.getFirstSelectedCell() should return 0 as start offset of the range");
|
||||
is(rangeWrapper.value.endContainer, tr,
|
||||
"#7-2 nsITableEditor.getFirstSelectedCell() should return the last <tr> element as end container of the range");
|
||||
is(rangeWrapper.value.endOffset, 1,
|
||||
"#7-2 nsITableEditor.getFirstSelectedCell() should return 1 as end offset of the range");
|
||||
|
||||
tr = document.getElementById("r2");
|
||||
selection.removeAllRanges();
|
||||
let range = document.createRange();
|
||||
range.setStart(tr, 1);
|
||||
range.setEnd(tr, 2);
|
||||
selection.addRange(range);
|
||||
range = document.createRange();
|
||||
range.setStart(tr, 2);
|
||||
range.setEnd(tr, 3);
|
||||
selection.addRange(range);
|
||||
cell = SpecialPowers.unwrap(getTableEditor().getFirstSelectedCell(rangeWrapper));
|
||||
is(cell, document.getElementById("c2-2"),
|
||||
"#2-2 nsITableEditor.getFirstSelectedCell() should return the second cell element in the second row");
|
||||
is(rangeWrapper.value.startContainer, tr,
|
||||
"#2-2 nsITableEditor.getFirstSelectedCell() should return the second <tr> element as start container of the range");
|
||||
is(rangeWrapper.value.startOffset, 1,
|
||||
"#2-2 nsITableEditor.getFirstSelectedCell() should return 1 as start offset of the range");
|
||||
is(rangeWrapper.value.endContainer, tr,
|
||||
"#2-2 nsITableEditor.getFirstSelectedCell() should return the second <tr> element as end container of the range");
|
||||
is(rangeWrapper.value.endOffset, 2,
|
||||
"#2-2 nsITableEditor.getFirstSelectedCell() should return 2 as end offset of the range");
|
||||
|
||||
tr = document.getElementById("r3");
|
||||
selection.removeAllRanges();
|
||||
range = document.createRange();
|
||||
range.setStart(tr, 2);
|
||||
range.setEnd(tr, 3);
|
||||
selection.addRange(range);
|
||||
range = document.createRange();
|
||||
range.setStart(document.getElementById("r5"), 0);
|
||||
range.setEnd(document.getElementById("r5"), 1);
|
||||
selection.addRange(range);
|
||||
cell = SpecialPowers.unwrap(getTableEditor().getFirstSelectedCell(rangeWrapper));
|
||||
is(cell, document.getElementById("c3-4"),
|
||||
"#3-4 nsITableEditor.getFirstSelectedCell() should return the last cell element in the third row");
|
||||
is(rangeWrapper.value.startContainer, tr,
|
||||
"#3-4 nsITableEditor.getFirstSelectedCell() should return the third <tr> element as start container of the range");
|
||||
is(rangeWrapper.value.startOffset, 2,
|
||||
"#3-4 nsITableEditor.getFirstSelectedCell() should return 2 as start offset of the range");
|
||||
is(rangeWrapper.value.endContainer, tr,
|
||||
"#3-4 nsITableEditor.getFirstSelectedCell() should return the third <tr> element as end container of the range");
|
||||
is(rangeWrapper.value.endOffset, 3,
|
||||
"#3-4 nsITableEditor.getFirstSelectedCell() should return 3 as end offset of the range");
|
||||
|
||||
cell = document.getElementById("c6-4");
|
||||
selection.selectAllChildren(cell);
|
||||
cell = SpecialPowers.unwrap(getTableEditor().getFirstSelectedCell(rangeWrapper));
|
||||
is(cell, null,
|
||||
"nsITableEditor.getFirstSelectedCell() should return null if neither <td> nor <th> element node is selected");
|
||||
is(rangeWrapper.value, null,
|
||||
"nsITableEditor.getFirstSelectedCell() should return null for the range if neither <td> nor <th> element node is selected");
|
||||
|
||||
cell = document.getElementById("c6-5");
|
||||
selection.setBaseAndExtent(cell.firstChild, 0, cell.firstChild, 0);
|
||||
cell = SpecialPowers.unwrap(getTableEditor().getFirstSelectedCell(rangeWrapper));
|
||||
is(cell, null,
|
||||
"nsITableEditor.getFirstSelectedCell() should return null if a text node is selected");
|
||||
is(rangeWrapper.value, null,
|
||||
"nsITableEditor.getFirstSelectedCell() should return null for the range if a text node is selected");
|
||||
|
||||
// XXX If cell is not selected, nsITableEditor.getFirstSelectedCell() returns null
|
||||
// without throwing exception, however, if there is no selection ranges,
|
||||
// throwing an exception. This inconsistency is odd.
|
||||
selection.removeAllRanges();
|
||||
try {
|
||||
cell = SpecialPowers.unwrap(getTableEditor().getFirstSelectedCell(rangeWrapper));
|
||||
ok(false, "nsITableEditor.getFirstSelectedCell() should throw an exception if there is no selection ranges");
|
||||
} catch (e) {
|
||||
ok(true, "nsITableEditor.getFirstSelectedCell() should throw an exception if there is no selection ranges");
|
||||
}
|
||||
|
||||
tr = document.getElementById("r6");
|
||||
selection.setBaseAndExtent(tr, 0, tr, 1);
|
||||
try {
|
||||
cell = SpecialPowers.unwrap(getTableEditor().getFirstSelectedCell());
|
||||
ok(false, "nsITableEditor.getFirstSelectedCell() should throw an exception if it does not have argument");
|
||||
} catch (e) {
|
||||
ok(true, "nsITableEditor.getFirstSelectedCell() should throw an exception if it does not have argument");
|
||||
}
|
||||
|
||||
tr = document.getElementById("r6");
|
||||
selection.setBaseAndExtent(tr, 0, tr, 1);
|
||||
try {
|
||||
cell = SpecialPowers.unwrap(getTableEditor().getFirstSelectedCell(null));
|
||||
ok(false, "nsITableEditor.getFirstSelectedCell() should throw an exception if its argument is null");
|
||||
} catch (e) {
|
||||
ok(true, "nsITableEditor.getFirstSelectedCell() should throw an exception if its argument is null");
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
function getTableEditor() {
|
||||
var Ci = SpecialPowers.Ci;
|
||||
var editingSession = SpecialPowers.wrap(window).docShell.editingSession;
|
||||
return editingSession.getEditorForWindow(window).QueryInterface(Ci.nsITableEditor);
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
@ -76,6 +76,7 @@ SimpleTest.waitForFocus(async function() {
|
|||
is(rect.height, 150, description + "Sanity check the height");
|
||||
|
||||
// Click on the target to show the resizers
|
||||
ok(true, "waiting selectionchange to select the target element");
|
||||
let promiseSelectionChangeEvent = waitForSelectionChange();
|
||||
synthesizeMouseAtCenter(target, {});
|
||||
await promiseSelectionChangeEvent;
|
||||
|
|
@ -97,9 +98,12 @@ SimpleTest.waitForFocus(async function() {
|
|||
synthesizeMouseAtCenter(outOfEditor, {});
|
||||
|
||||
// Get the new dimensions for the target
|
||||
// XXX I don't know why we need 2px margin to check this on Android.
|
||||
// Fortunately, this test checks whether objects are resizable
|
||||
// actually. So, bigger difference is okay.
|
||||
let newRect = target.getBoundingClientRect();
|
||||
isfuzzy(newRect.width, rect.width + expectedDeltaX, 1, description + "The width should be increased by " + expectedDeltaX + " pixels");
|
||||
isfuzzy(newRect.height, rect.height + expectedDeltaY, 1, description + "The height should be increased by " + expectedDeltaY + "pixels");
|
||||
isfuzzy(newRect.width, rect.width + expectedDeltaX, 2, description + "The width should be increased by " + expectedDeltaX + " pixels");
|
||||
isfuzzy(newRect.height, rect.height + expectedDeltaY, 2, description + "The height should be increased by " + expectedDeltaY + "pixels");
|
||||
}
|
||||
|
||||
// Account for changes in the resizing behavior when we're trying to preserve
|
||||
|
|
|
|||
|
|
@ -303,19 +303,22 @@ interface nsITableEditor : nsISupports
|
|||
*/
|
||||
uint32_t getSelectedCellsType(in Element aElement);
|
||||
|
||||
/** Get first selected element from first selection range.
|
||||
* (If multiple cells were selected this is the first in the order they were selected)
|
||||
* Assumes cell-selection model where each cell
|
||||
* is in a separate range (selection parent node is table row)
|
||||
* @param aCell [OUT] Selected cell or null if ranges don't contain
|
||||
* cell selections
|
||||
* @param aRange [OUT] Optional: if not null, return the selection range
|
||||
* associated with the cell
|
||||
* Returns the DOM cell element
|
||||
* (in C++: returns NS_EDITOR_ELEMENT_NOT_FOUND if an element is not found
|
||||
* passes NS_SUCCEEDED macro)
|
||||
*/
|
||||
Element getFirstSelectedCell(out Range aRange);
|
||||
/**
|
||||
* getFirstSelectedCell() returns a <td> or <th> element if first range of
|
||||
* Selection selects only one table cell element (i.e., startContainer and
|
||||
* endContainer are same <tr> element and startOffset + 1 equals endOffset).
|
||||
* If first range of Selection does not select a table cell element, this
|
||||
* returns null. However, if Selection has no range, this throws an
|
||||
* exception.
|
||||
*
|
||||
* @param aFirstRangeOfSelection [OUT] Returns the first range of Selection
|
||||
* only when this returns a <td> or <th>
|
||||
* element. Otherwise, returns null.
|
||||
* @return A <td> or <th> element if first range of
|
||||
* Selection selects only one table cell
|
||||
* element.
|
||||
*/
|
||||
Element getFirstSelectedCell(out Range aFirstRangeOfSelection);
|
||||
|
||||
/** Get first selected element in the table
|
||||
* This is the upper-left-most selected cell in table,
|
||||
|
|
|
|||
|
|
@ -222,6 +222,10 @@ public:
|
|||
return mRead->Size();
|
||||
}
|
||||
|
||||
bool IsReadBufferReady() const {
|
||||
return mRead.get() != nullptr;
|
||||
}
|
||||
|
||||
void BindAsFramebuffer(GLContext* const gl, GLenum target) const;
|
||||
|
||||
void RequireBlit();
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@
|
|||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
#include "mozilla/layers/CompositorThread.h"
|
||||
// Max frame duration on Android before the watchdog submits a new one.
|
||||
// Probably we can get rid of this when we enforce that SubmitFrame can only be called in a VRDisplay loop.
|
||||
#define ANDROID_MAX_FRAME_DURATION 4000
|
||||
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||
|
||||
|
||||
|
|
@ -79,6 +82,11 @@ VRDisplayHost::VRDisplayHost(VRDeviceType aType)
|
|||
mDisplayInfo.mFrameId = 0;
|
||||
mDisplayInfo.mDisplayState.mPresentingGeneration = 0;
|
||||
mDisplayInfo.mDisplayState.mDisplayName[0] = '\0';
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
mLastSubmittedFrameId = 0;
|
||||
mLastStartedFrame = 0;
|
||||
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||
}
|
||||
|
||||
VRDisplayHost::~VRDisplayHost()
|
||||
|
|
@ -200,10 +208,24 @@ VRDisplayHost::StartFrame()
|
|||
{
|
||||
AUTO_PROFILER_TRACING("VR", "GetSensorState");
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
const bool isPresenting = mLastUpdateDisplayInfo.GetPresentingGroups() != 0;
|
||||
double duration = mLastFrameStart.IsNull() ? 0.0 : (TimeStamp::Now() - mLastFrameStart).ToMilliseconds();
|
||||
/**
|
||||
* Do not start more VR frames until the last submitted frame is already processed.
|
||||
*/
|
||||
if (isPresenting && mLastStartedFrame > 0 && mDisplayInfo.mDisplayState.mLastSubmittedFrameId < mLastStartedFrame && duration < (double)ANDROID_MAX_FRAME_DURATION) {
|
||||
return;
|
||||
}
|
||||
#endif // !defined(MOZ_WIDGET_ANDROID)
|
||||
|
||||
mLastFrameStart = TimeStamp::Now();
|
||||
++mDisplayInfo.mFrameId;
|
||||
mDisplayInfo.mLastSensorState[mDisplayInfo.mFrameId % kVRMaxLatencyFrames] = GetSensorState();
|
||||
mFrameStarted = true;
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
mLastStartedFrame = mDisplayInfo.mFrameId;
|
||||
#endif // !defined(MOZ_WIDGET_ANDROID)
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -316,6 +338,19 @@ VRDisplayHost::SubmitFrame(VRLayerParent* aLayer,
|
|||
return;
|
||||
}
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
/**
|
||||
* Do not queue more submit frames until the last submitted frame is already processed
|
||||
* and the new WebGL texture is ready.
|
||||
*/
|
||||
if (mLastSubmittedFrameId > 0 && mLastSubmittedFrameId != mDisplayInfo.mDisplayState.mLastSubmittedFrameId) {
|
||||
mLastStartedFrame = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
mLastSubmittedFrameId = aFrameId;
|
||||
#endif // !defined(MOZ_WIDGET_ANDROID)
|
||||
|
||||
mFrameStarted = false;
|
||||
|
||||
RefPtr<Runnable> submit =
|
||||
|
|
|
|||
|
|
@ -101,6 +101,11 @@ private:
|
|||
VRDisplayInfo mLastUpdateDisplayInfo;
|
||||
TimeStamp mLastFrameStart;
|
||||
bool mFrameStarted;
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
protected:
|
||||
uint64_t mLastSubmittedFrameId;
|
||||
uint64_t mLastStartedFrame;
|
||||
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||
|
||||
#if defined(XP_WIN)
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ VRDisplayPresentation::~VRDisplayPresentation()
|
|||
void VRDisplayPresentation::SubmitFrame()
|
||||
{
|
||||
for (VRLayerChild *layer : mLayers) {
|
||||
layer->SubmitFrame(mDisplayClient->GetDisplayInfo().GetFrameId());
|
||||
layer->SubmitFrame(mDisplayClient->GetDisplayInfo());
|
||||
break; // Currently only one layer supported, submit only the first
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,8 +52,6 @@ using namespace mozilla::gfx::impl;
|
|||
using namespace mozilla::layers;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
int VRDisplayExternal::sPushIndex = 0;
|
||||
|
||||
VRDisplayExternal::VRDisplayExternal(const VRDisplayState& aDisplayState)
|
||||
: VRDisplayHost(VRDeviceType::External)
|
||||
, mBrowserState{}
|
||||
|
|
@ -108,7 +106,6 @@ VRDisplayExternal::StartPresentation()
|
|||
if (mBrowserState.presentationActive) {
|
||||
return;
|
||||
}
|
||||
sPushIndex = 0;
|
||||
mTelemetry.Clear();
|
||||
mTelemetry.mPresentationStart = TimeStamp::Now();
|
||||
|
||||
|
|
@ -118,6 +115,8 @@ VRDisplayExternal::StartPresentation()
|
|||
PushState();
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
mLastSubmittedFrameId = 0;
|
||||
mLastStartedFrame = 0;
|
||||
/**
|
||||
* Android compositor is paused when presentation starts. That causes VRManager::NotifyVsync() not to be called.
|
||||
* We post a VRTask to call VRManager::NotifyVsync() while the compositor is paused on Android.
|
||||
|
|
@ -162,7 +161,6 @@ VRDisplayExternal::StopPresentation()
|
|||
if (!mBrowserState.presentationActive) {
|
||||
return;
|
||||
}
|
||||
sPushIndex = 0;
|
||||
|
||||
// Indicate that we have stopped immersive mode
|
||||
mBrowserState.presentationActive = false;
|
||||
|
|
@ -276,7 +274,6 @@ VRDisplayExternal::SubmitFrame(const layers::SurfaceDescriptor& aTexture,
|
|||
layer.mRightEyeRect.height = aRightEyeRect.height;
|
||||
|
||||
PushState(true);
|
||||
sPushIndex++;
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
PullState([&]() {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ class VRDisplayExternal : public VRDisplayHost
|
|||
{
|
||||
public:
|
||||
void ZeroSensor() override;
|
||||
static int sPushIndex;
|
||||
|
||||
protected:
|
||||
VRHMDSensorState GetSensorState() override;
|
||||
|
|
|
|||
|
|
@ -50,22 +50,38 @@ VRLayerChild::Initialize(dom::HTMLCanvasElement* aCanvasElement,
|
|||
}
|
||||
|
||||
void
|
||||
VRLayerChild::SubmitFrame(uint64_t aFrameId)
|
||||
VRLayerChild::SubmitFrame(const VRDisplayInfo& aDisplayInfo)
|
||||
{
|
||||
uint64_t frameId = aDisplayInfo.GetFrameId();
|
||||
|
||||
// aFrameId will not increment unless the previuosly submitted
|
||||
// frame was received by the VR thread and submitted to the VR
|
||||
// compositor. We early-exit here in the event that SubmitFrame
|
||||
// was called twice for the same aFrameId.
|
||||
if (!mCanvasElement || aFrameId == mLastSubmittedFrameId) {
|
||||
if (!mCanvasElement || frameId == mLastSubmittedFrameId) {
|
||||
return;
|
||||
}
|
||||
mLastSubmittedFrameId = aFrameId;
|
||||
|
||||
// Keep the SharedSurfaceTextureClient alive long enough for
|
||||
// 1 extra frame, accomodating overlapped asynchronous rendering.
|
||||
mLastFrameTexture = mThisFrameTexture;
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
/**
|
||||
* Do not blit WebGL to a SurfaceTexture until the last submitted frame is already processed
|
||||
* and the new frame poses are ready. SurfaceTextures need to be released in the VR render thread
|
||||
* in order to allow to be used again in the WebGLContext GLScreenBuffer producer.
|
||||
* Not doing so causes some freezes, crashes or other undefined behaviour.
|
||||
*/
|
||||
if (!mThisFrameTexture || aDisplayInfo.mDisplayState.mLastSubmittedFrameId == mLastSubmittedFrameId) {
|
||||
mThisFrameTexture = mCanvasElement->GetVRFrame();
|
||||
}
|
||||
#else
|
||||
mThisFrameTexture = mCanvasElement->GetVRFrame();
|
||||
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||
|
||||
mLastSubmittedFrameId = frameId;
|
||||
|
||||
if (!mThisFrameTexture) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -90,7 +106,7 @@ VRLayerChild::SubmitFrame(uint64_t aFrameId)
|
|||
return;
|
||||
}
|
||||
|
||||
SendSubmitFrame(desc, aFrameId, mLeftEyeRect, mRightEyeRect);
|
||||
SendSubmitFrame(desc, frameId, mLeftEyeRect, mRightEyeRect);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public:
|
|||
|
||||
void Initialize(dom::HTMLCanvasElement* aCanvasElement,
|
||||
const gfx::Rect& aLeftEyeRect, const gfx::Rect& aRightEyeRect);
|
||||
void SubmitFrame(uint64_t aFrameId);
|
||||
void SubmitFrame(const VRDisplayInfo& aDisplayInfo);
|
||||
bool IsIPCOpen();
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
use std::ffi::{CStr, CString};
|
||||
use std::{mem, slice};
|
||||
use std::{mem, slice, ptr, env};
|
||||
use std::path::PathBuf;
|
||||
use std::ptr;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::os::raw::{c_void, c_char, c_float};
|
||||
|
|
@ -884,6 +883,10 @@ pub extern "C" fn wr_renderer_update_program_cache(renderer: &mut Renderer, prog
|
|||
renderer.update_program_cache(program_cache);
|
||||
}
|
||||
|
||||
fn env_var_to_bool(key: &'static str) -> bool {
|
||||
env::var(key).ok().map_or(false, |v| v.parse::<usize>().unwrap_or(1) != 0)
|
||||
}
|
||||
|
||||
// Call MakeCurrent before this.
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wr_window_new(window_id: WrWindowId,
|
||||
|
|
@ -951,6 +954,7 @@ pub extern "C" fn wr_window_new(window_id: WrWindowId,
|
|||
sampler: Some(Box::new(SamplerCallback::new(window_id))),
|
||||
max_texture_size: Some(8192), // Moz2D doesn't like textures bigger than this
|
||||
clear_color: Some(ColorF::new(0.0, 0.0, 0.0, 0.0)),
|
||||
precache_shaders: env_var_to_bool("MOZ_WR_PRECACHE_SHADERS"),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
|
@ -1770,12 +1774,12 @@ pub extern "C" fn wr_dp_define_clipchain(state: &mut WrState,
|
|||
-> u64 {
|
||||
debug_assert!(unsafe { is_in_main_thread() });
|
||||
let parent = unsafe { parent_clipchain_id.as_ref() }.map(|id| ClipChainId(*id, state.pipeline_id));
|
||||
let clips_slice : Vec<ClipId> = make_slice(clips, clips_count)
|
||||
let pipeline_id = state.pipeline_id;
|
||||
let clips = make_slice(clips, clips_count)
|
||||
.iter()
|
||||
.map(|id| unpack_clip_id(*id, state.pipeline_id))
|
||||
.collect();
|
||||
.map(|id| unpack_clip_id(*id, pipeline_id));
|
||||
|
||||
let clipchain_id = state.frame_builder.dl_builder.define_clip_chain(parent, clips_slice);
|
||||
let clipchain_id = state.frame_builder.dl_builder.define_clip_chain(parent, clips);
|
||||
assert!(clipchain_id.1 == state.pipeline_id);
|
||||
clipchain_id.0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1799,8 +1799,8 @@ Parser<FullParseHandler, CharT>::checkStatementsEOF()
|
|||
// This is designed to be paired with parsing a statement list at the top
|
||||
// level.
|
||||
//
|
||||
// The statementList() call breaks on TokenKind::Rc, so make sure we've
|
||||
// reached EOF here.
|
||||
// The statementList() call breaks on TokenKind::RightCurly, so make sure
|
||||
// we've reached EOF here.
|
||||
TokenKind tt;
|
||||
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
|
||||
return false;
|
||||
|
|
@ -2980,7 +2980,7 @@ GeneralParser<ParseHandler, CharT>::matchOrInsertSemicolon()
|
|||
if (tt != TokenKind::Eof &&
|
||||
tt != TokenKind::Eol &&
|
||||
tt != TokenKind::Semi &&
|
||||
tt != TokenKind::Rc)
|
||||
tt != TokenKind::RightCurly)
|
||||
{
|
||||
/*
|
||||
* When current token is `await` and it's outside of async function,
|
||||
|
|
@ -3113,7 +3113,7 @@ GeneralParser<ParseHandler, CharT>::functionArguments(YieldHandling yieldHandlin
|
|||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt, firstTokenModifier))
|
||||
return false;
|
||||
if (tt != TokenKind::Lp) {
|
||||
if (tt != TokenKind::LeftParen) {
|
||||
error(kind == FunctionSyntaxKind::Arrow
|
||||
? JSMSG_BAD_ARROW_ARGS
|
||||
: JSMSG_PAREN_BEFORE_FORMAL);
|
||||
|
|
@ -3142,7 +3142,7 @@ GeneralParser<ParseHandler, CharT>::functionArguments(YieldHandling yieldHandlin
|
|||
hasArguments = true;
|
||||
} else {
|
||||
bool matched;
|
||||
if (!tokenStream.matchToken(&matched, TokenKind::Rp, TokenStream::Operand))
|
||||
if (!tokenStream.matchToken(&matched, TokenKind::RightParen, TokenStream::Operand))
|
||||
return false;
|
||||
if (!matched)
|
||||
hasArguments = true;
|
||||
|
|
@ -3193,8 +3193,8 @@ GeneralParser<ParseHandler, CharT>::functionArguments(YieldHandling yieldHandlin
|
|||
return false;
|
||||
|
||||
if (!TokenKindIsPossibleIdentifier(tt) &&
|
||||
tt != TokenKind::Lb &&
|
||||
tt != TokenKind::Lc)
|
||||
tt != TokenKind::LeftBracket &&
|
||||
tt != TokenKind::LeftCurly)
|
||||
{
|
||||
error(JSMSG_NO_REST_NAME);
|
||||
return false;
|
||||
|
|
@ -3202,8 +3202,8 @@ GeneralParser<ParseHandler, CharT>::functionArguments(YieldHandling yieldHandlin
|
|||
}
|
||||
|
||||
switch (tt) {
|
||||
case TokenKind::Lb:
|
||||
case TokenKind::Lc: {
|
||||
case TokenKind::LeftBracket:
|
||||
case TokenKind::LeftCurly: {
|
||||
disallowDuplicateParams = true;
|
||||
if (duplicatedParam) {
|
||||
// Has duplicated args before the destructuring parameter.
|
||||
|
|
@ -3312,7 +3312,7 @@ GeneralParser<ParseHandler, CharT>::functionArguments(YieldHandling yieldHandlin
|
|||
if (!hasRest) {
|
||||
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
|
||||
return null();
|
||||
if (tt == TokenKind::Rp)
|
||||
if (tt == TokenKind::RightParen)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -3321,7 +3321,7 @@ GeneralParser<ParseHandler, CharT>::functionArguments(YieldHandling yieldHandlin
|
|||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt, TokenStream::Operand))
|
||||
return false;
|
||||
if (tt != TokenKind::Rp) {
|
||||
if (tt != TokenKind::RightParen) {
|
||||
if (kind == FunctionSyntaxKind::Setter) {
|
||||
error(JSMSG_ACCESSOR_WRONG_ARGS, "setter", "one", "");
|
||||
return false;
|
||||
|
|
@ -3412,7 +3412,7 @@ GeneralParser<ParseHandler, CharT>::addExprAndGetNextTemplStrToken(YieldHandling
|
|||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt, TokenStream::Operand))
|
||||
return false;
|
||||
if (tt != TokenKind::Rc) {
|
||||
if (tt != TokenKind::RightCurly) {
|
||||
error(JSMSG_TEMPLSTR_UNTERM_EXPR);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -3884,7 +3884,7 @@ GeneralParser<ParseHandler, CharT>::functionFormalParametersAndBody(InHandling i
|
|||
if (!tokenStream.getToken(&tt, TokenStream::Operand))
|
||||
return false;
|
||||
uint32_t openedPos = 0;
|
||||
if (tt != TokenKind::Lc) {
|
||||
if (tt != TokenKind::LeftCurly) {
|
||||
if (kind != FunctionSyntaxKind::Arrow) {
|
||||
error(JSMSG_CURLY_BEFORE_BODY);
|
||||
return false;
|
||||
|
|
@ -3945,7 +3945,7 @@ GeneralParser<ParseHandler, CharT>::functionFormalParametersAndBody(InHandling i
|
|||
}
|
||||
|
||||
if (bodyType == StatementListBody) {
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::Rc, TokenStream::Operand,
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::RightCurly, TokenStream::Operand,
|
||||
reportMissingClosing(JSMSG_CURLY_AFTER_BODY,
|
||||
JSMSG_CURLY_OPENED, openedPos));
|
||||
funbox->setEnd(anyChars);
|
||||
|
|
@ -4305,7 +4305,7 @@ GeneralParser<ParseHandler, CharT>::statementList(YieldHandling yieldHandling)
|
|||
isUnexpectedEOF_ = true;
|
||||
return null();
|
||||
}
|
||||
if (tt == TokenKind::Eof || tt == TokenKind::Rc) {
|
||||
if (tt == TokenKind::Eof || tt == TokenKind::RightCurly) {
|
||||
TokenPos pos;
|
||||
if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand)) {
|
||||
return null();
|
||||
|
|
@ -4351,13 +4351,13 @@ template <class ParseHandler, typename CharT>
|
|||
typename ParseHandler::Node
|
||||
GeneralParser<ParseHandler, CharT>::condition(InHandling inHandling, YieldHandling yieldHandling)
|
||||
{
|
||||
MUST_MATCH_TOKEN(TokenKind::Lp, JSMSG_PAREN_BEFORE_COND);
|
||||
MUST_MATCH_TOKEN(TokenKind::LeftParen, JSMSG_PAREN_BEFORE_COND);
|
||||
|
||||
Node pn = exprInParens(inHandling, yieldHandling, TripledotProhibited);
|
||||
if (!pn)
|
||||
return null();
|
||||
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::Rp, TokenStream::Operand, JSMSG_PAREN_AFTER_COND);
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::RightParen, TokenStream::Operand, JSMSG_PAREN_AFTER_COND);
|
||||
|
||||
/* Check for (a = b) and warn about possible (a == b) mistype. */
|
||||
if (handler.isUnparenthesizedAssignment(pn)) {
|
||||
|
|
@ -4589,10 +4589,10 @@ GeneralParser<ParseHandler, CharT>::bindingIdentifierOrPattern(DeclarationKind k
|
|||
YieldHandling yieldHandling,
|
||||
TokenKind tt)
|
||||
{
|
||||
if (tt == TokenKind::Lb)
|
||||
if (tt == TokenKind::LeftBracket)
|
||||
return arrayBindingPattern(kind, yieldHandling);
|
||||
|
||||
if (tt == TokenKind::Lc)
|
||||
if (tt == TokenKind::LeftCurly)
|
||||
return objectBindingPattern(kind, yieldHandling);
|
||||
|
||||
if (!TokenKindIsPossibleIdentifierName(tt)) {
|
||||
|
|
@ -4608,7 +4608,7 @@ typename ParseHandler::Node
|
|||
GeneralParser<ParseHandler, CharT>::objectBindingPattern(DeclarationKind kind,
|
||||
YieldHandling yieldHandling)
|
||||
{
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Lc));
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
|
||||
|
||||
if (!CheckRecursionLimit(context))
|
||||
return null();
|
||||
|
|
@ -4624,7 +4624,7 @@ GeneralParser<ParseHandler, CharT>::objectBindingPattern(DeclarationKind kind,
|
|||
TokenKind tt;
|
||||
if (!tokenStream.peekToken(&tt))
|
||||
return null();
|
||||
if (tt == TokenKind::Rc) {
|
||||
if (tt == TokenKind::RightCurly) {
|
||||
anyChars.addModifierException(TokenStream::OperandIsNone);
|
||||
break;
|
||||
}
|
||||
|
|
@ -4723,7 +4723,7 @@ GeneralParser<ParseHandler, CharT>::objectBindingPattern(DeclarationKind kind,
|
|||
}
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::Rc, TokenStream::Operand,
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::RightCurly, TokenStream::Operand,
|
||||
reportMissingClosing(JSMSG_CURLY_AFTER_LIST,
|
||||
JSMSG_CURLY_OPENED, begin));
|
||||
|
||||
|
|
@ -4736,7 +4736,7 @@ typename ParseHandler::Node
|
|||
GeneralParser<ParseHandler, CharT>::arrayBindingPattern(DeclarationKind kind,
|
||||
YieldHandling yieldHandling)
|
||||
{
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Lb));
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket));
|
||||
|
||||
if (!CheckRecursionLimit(context))
|
||||
return null();
|
||||
|
|
@ -4757,7 +4757,7 @@ GeneralParser<ParseHandler, CharT>::arrayBindingPattern(DeclarationKind kind,
|
|||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
|
||||
if (tt == TokenKind::Rb) {
|
||||
if (tt == TokenKind::RightBracket) {
|
||||
anyChars.ungetToken();
|
||||
anyChars.addModifierException(TokenStream::OperandIsNone);
|
||||
break;
|
||||
|
|
@ -4812,7 +4812,7 @@ GeneralParser<ParseHandler, CharT>::arrayBindingPattern(DeclarationKind kind,
|
|||
}
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::Rb, TokenStream::Operand,
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::RightBracket, TokenStream::Operand,
|
||||
reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
|
||||
JSMSG_BRACKET_OPENED, begin));
|
||||
|
||||
|
|
@ -4827,9 +4827,9 @@ GeneralParser<ParseHandler, CharT>::destructuringDeclaration(DeclarationKind kin
|
|||
TokenKind tt)
|
||||
{
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(tt));
|
||||
MOZ_ASSERT(tt == TokenKind::Lb || tt == TokenKind::Lc);
|
||||
MOZ_ASSERT(tt == TokenKind::LeftBracket || tt == TokenKind::LeftCurly);
|
||||
|
||||
return tt == TokenKind::Lb
|
||||
return tt == TokenKind::LeftBracket
|
||||
? arrayBindingPattern(kind, yieldHandling)
|
||||
: objectBindingPattern(kind, yieldHandling);
|
||||
}
|
||||
|
|
@ -4861,7 +4861,7 @@ typename ParseHandler::Node
|
|||
GeneralParser<ParseHandler, CharT>::blockStatement(YieldHandling yieldHandling,
|
||||
unsigned errorNumber)
|
||||
{
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Lc));
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
|
||||
uint32_t openedPos = pos().begin;
|
||||
|
||||
ParseContext::Statement stmt(pc, StatementKind::Block);
|
||||
|
|
@ -4873,7 +4873,7 @@ GeneralParser<ParseHandler, CharT>::blockStatement(YieldHandling yieldHandling,
|
|||
if (!list)
|
||||
return null();
|
||||
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::Rc, TokenStream::Operand,
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::RightCurly, TokenStream::Operand,
|
||||
reportMissingClosing(errorNumber, JSMSG_CURLY_OPENED,
|
||||
openedPos));
|
||||
|
||||
|
|
@ -4900,8 +4900,8 @@ GeneralParser<ParseHandler, CharT>::declarationPattern(DeclarationKind declKind,
|
|||
ParseNodeKind* forHeadKind,
|
||||
Node* forInOrOfExpression)
|
||||
{
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Lb) ||
|
||||
anyChars.isCurrentTokenType(TokenKind::Lc));
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket) ||
|
||||
anyChars.isCurrentTokenType(TokenKind::LeftCurly));
|
||||
|
||||
Node pattern = destructuringDeclaration(declKind, yieldHandling, tt);
|
||||
if (!pattern)
|
||||
|
|
@ -5124,7 +5124,7 @@ GeneralParser<ParseHandler, CharT>::declarationList(YieldHandling yieldHandling,
|
|||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
|
||||
Node binding = (tt == TokenKind::Lb || tt == TokenKind::Lc)
|
||||
Node binding = (tt == TokenKind::LeftBracket || tt == TokenKind::LeftCurly)
|
||||
? declarationPattern(declKind, tt, initialDeclaration, yieldHandling,
|
||||
forHeadKind, forInOrOfExpression)
|
||||
: declarationName(declKind, tt, initialDeclaration, yieldHandling,
|
||||
|
|
@ -5180,7 +5180,7 @@ template <typename CharT>
|
|||
bool
|
||||
Parser<FullParseHandler, CharT>::namedImportsOrNamespaceImport(TokenKind tt, Node importSpecSet)
|
||||
{
|
||||
if (tt == TokenKind::Lc) {
|
||||
if (tt == TokenKind::LeftCurly) {
|
||||
while (true) {
|
||||
// Handle the forms |import {} from 'a'| and
|
||||
// |import { ..., } from 'a'| (where ... is non empty), by
|
||||
|
|
@ -5188,7 +5188,7 @@ Parser<FullParseHandler, CharT>::namedImportsOrNamespaceImport(TokenKind tt, Nod
|
|||
if (!tokenStream.getToken(&tt))
|
||||
return false;
|
||||
|
||||
if (tt == TokenKind::Rc)
|
||||
if (tt == TokenKind::RightCurly)
|
||||
break;
|
||||
|
||||
if (!TokenKindIsPossibleIdentifierName(tt)) {
|
||||
|
|
@ -5247,7 +5247,7 @@ Parser<FullParseHandler, CharT>::namedImportsOrNamespaceImport(TokenKind tt, Nod
|
|||
if (!tokenStream.getToken(&next))
|
||||
return false;
|
||||
|
||||
if (next == TokenKind::Rc)
|
||||
if (next == TokenKind::RightCurly)
|
||||
break;
|
||||
|
||||
if (next != TokenKind::Comma) {
|
||||
|
|
@ -5318,7 +5318,7 @@ Parser<FullParseHandler, CharT>::importDeclaration()
|
|||
// equivalent to |import {} from 'a'|.
|
||||
importSpecSet->pn_pos.end = importSpecSet->pn_pos.begin;
|
||||
} else {
|
||||
if (tt == TokenKind::Lc || tt == TokenKind::Mul) {
|
||||
if (tt == TokenKind::LeftCurly || tt == TokenKind::Mul) {
|
||||
if (!namedImportsOrNamespaceImport(tt, importSpecSet))
|
||||
return null();
|
||||
} else if (TokenKindIsPossibleIdentifierName(tt)) {
|
||||
|
|
@ -5355,7 +5355,7 @@ Parser<FullParseHandler, CharT>::importDeclaration()
|
|||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
|
||||
if (tt != TokenKind::Lc && tt != TokenKind::Mul) {
|
||||
if (tt != TokenKind::LeftCurly && tt != TokenKind::Mul) {
|
||||
error(JSMSG_NAMED_IMPORTS_OR_NAMESPACE_IMPORT);
|
||||
return null();
|
||||
}
|
||||
|
|
@ -5799,7 +5799,7 @@ GeneralParser<ParseHandler, CharT>::exportClause(uint32_t begin)
|
|||
if (!abortIfSyntaxParser())
|
||||
return null();
|
||||
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Lc));
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
|
||||
|
||||
Node kid = handler.newList(ParseNodeKind::ExportSpecList, pos());
|
||||
if (!kid)
|
||||
|
|
@ -5812,7 +5812,7 @@ GeneralParser<ParseHandler, CharT>::exportClause(uint32_t begin)
|
|||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
|
||||
if (tt == TokenKind::Rc)
|
||||
if (tt == TokenKind::RightCurly)
|
||||
break;
|
||||
|
||||
if (!TokenKindIsPossibleIdentifierName(tt)) {
|
||||
|
|
@ -5847,7 +5847,7 @@ GeneralParser<ParseHandler, CharT>::exportClause(uint32_t begin)
|
|||
if (!tokenStream.getToken(&next))
|
||||
return null();
|
||||
|
||||
if (next == TokenKind::Rc)
|
||||
if (next == TokenKind::RightCurly)
|
||||
break;
|
||||
|
||||
if (next != TokenKind::Comma) {
|
||||
|
|
@ -6147,7 +6147,7 @@ GeneralParser<ParseHandler, CharT>::exportDeclaration()
|
|||
case TokenKind::Mul:
|
||||
return exportBatch(begin);
|
||||
|
||||
case TokenKind::Lc:
|
||||
case TokenKind::LeftCurly:
|
||||
return exportClause(begin);
|
||||
|
||||
case TokenKind::Var:
|
||||
|
|
@ -6383,7 +6383,7 @@ GeneralParser<ParseHandler, CharT>::forHeadStart(YieldHandling yieldHandling,
|
|||
Maybe<ParseContext::Scope>& forLoopLexicalScope,
|
||||
Node* forInOrOfExpression)
|
||||
{
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Lp));
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftParen));
|
||||
|
||||
TokenKind tt;
|
||||
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
|
||||
|
|
@ -6555,7 +6555,7 @@ GeneralParser<ParseHandler, CharT>::forStatement(YieldHandling yieldHandling)
|
|||
}
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::Lp, TokenStream::None,
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::LeftParen, TokenStream::None,
|
||||
error((token == TokenKind::Await && !pc->isAsync())
|
||||
? JSMSG_FOR_AWAIT_OUTSIDE_ASYNC
|
||||
: JSMSG_PAREN_AFTER_FOR));
|
||||
|
|
@ -6635,7 +6635,7 @@ GeneralParser<ParseHandler, CharT>::forStatement(YieldHandling yieldHandling)
|
|||
return null();
|
||||
|
||||
Node update;
|
||||
if (tt == TokenKind::Rp) {
|
||||
if (tt == TokenKind::RightParen) {
|
||||
update = null();
|
||||
} else {
|
||||
update = expr(InAllowed, yieldHandling, TripledotProhibited);
|
||||
|
|
@ -6643,7 +6643,7 @@ GeneralParser<ParseHandler, CharT>::forStatement(YieldHandling yieldHandling)
|
|||
return null();
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::Rp, TokenStream::Operand, JSMSG_PAREN_AFTER_FOR_CTRL);
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::RightParen, TokenStream::Operand, JSMSG_PAREN_AFTER_FOR_CTRL);
|
||||
|
||||
TokenPos headPos(begin, pos().end);
|
||||
forHead = handler.newForHead(init, test, update, headPos);
|
||||
|
|
@ -6666,7 +6666,7 @@ GeneralParser<ParseHandler, CharT>::forStatement(YieldHandling yieldHandling)
|
|||
// Parser::declaration consumed everything up to the closing ')'. That
|
||||
// token follows an {Assignment,}Expression and so must be interpreted
|
||||
// as an operand to be consistent with normal expression tokenizing.
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::Rp, TokenStream::Operand, JSMSG_PAREN_AFTER_FOR_CTRL);
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::RightParen, TokenStream::Operand, JSMSG_PAREN_AFTER_FOR_CTRL);
|
||||
|
||||
TokenPos headPos(begin, pos().end);
|
||||
forHead = handler.newForInOrOfHead(headKind, target, iteratedExpr, headPos);
|
||||
|
|
@ -6695,14 +6695,14 @@ GeneralParser<ParseHandler, CharT>::switchStatement(YieldHandling yieldHandling)
|
|||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Switch));
|
||||
uint32_t begin = pos().begin;
|
||||
|
||||
MUST_MATCH_TOKEN(TokenKind::Lp, JSMSG_PAREN_BEFORE_SWITCH);
|
||||
MUST_MATCH_TOKEN(TokenKind::LeftParen, JSMSG_PAREN_BEFORE_SWITCH);
|
||||
|
||||
Node discriminant = exprInParens(InAllowed, yieldHandling, TripledotProhibited);
|
||||
if (!discriminant)
|
||||
return null();
|
||||
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::Rp, TokenStream::Operand, JSMSG_PAREN_AFTER_SWITCH);
|
||||
MUST_MATCH_TOKEN(TokenKind::Lc, JSMSG_CURLY_BEFORE_SWITCH);
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::RightParen, TokenStream::Operand, JSMSG_PAREN_AFTER_SWITCH);
|
||||
MUST_MATCH_TOKEN(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_SWITCH);
|
||||
|
||||
ParseContext::Statement stmt(pc, StatementKind::Switch);
|
||||
ParseContext::Scope scope(this);
|
||||
|
|
@ -6718,7 +6718,7 @@ GeneralParser<ParseHandler, CharT>::switchStatement(YieldHandling yieldHandling)
|
|||
while (true) {
|
||||
if (!tokenStream.getToken(&tt, TokenStream::Operand))
|
||||
return null();
|
||||
if (tt == TokenKind::Rc)
|
||||
if (tt == TokenKind::RightCurly)
|
||||
break;
|
||||
uint32_t caseBegin = pos().begin;
|
||||
|
||||
|
|
@ -6756,7 +6756,7 @@ GeneralParser<ParseHandler, CharT>::switchStatement(YieldHandling yieldHandling)
|
|||
while (true) {
|
||||
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
|
||||
return null();
|
||||
if (tt == TokenKind::Rc || tt == TokenKind::Case || tt == TokenKind::Default)
|
||||
if (tt == TokenKind::RightCurly || tt == TokenKind::Case || tt == TokenKind::Default)
|
||||
break;
|
||||
if (afterReturn) {
|
||||
if (!tokenStream.peekOffset(&statementBegin, TokenStream::Operand))
|
||||
|
|
@ -6886,7 +6886,7 @@ GeneralParser<ParseHandler, CharT>::returnStatement(YieldHandling yieldHandling)
|
|||
case TokenKind::Eol:
|
||||
case TokenKind::Eof:
|
||||
case TokenKind::Semi:
|
||||
case TokenKind::Rc:
|
||||
case TokenKind::RightCurly:
|
||||
exprNode = null();
|
||||
break;
|
||||
default: {
|
||||
|
|
@ -6929,9 +6929,9 @@ GeneralParser<ParseHandler, CharT>::yieldExpression(InHandling inHandling)
|
|||
// start an expression.
|
||||
case TokenKind::Eof:
|
||||
case TokenKind::Semi:
|
||||
case TokenKind::Rc:
|
||||
case TokenKind::Rb:
|
||||
case TokenKind::Rp:
|
||||
case TokenKind::RightCurly:
|
||||
case TokenKind::RightBracket:
|
||||
case TokenKind::RightParen:
|
||||
case TokenKind::Colon:
|
||||
case TokenKind::Comma:
|
||||
case TokenKind::In:
|
||||
|
|
@ -6970,13 +6970,13 @@ GeneralParser<ParseHandler, CharT>::withStatement(YieldHandling yieldHandling)
|
|||
return null();
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN(TokenKind::Lp, JSMSG_PAREN_BEFORE_WITH);
|
||||
MUST_MATCH_TOKEN(TokenKind::LeftParen, JSMSG_PAREN_BEFORE_WITH);
|
||||
|
||||
Node objectExpr = exprInParens(InAllowed, yieldHandling, TripledotProhibited);
|
||||
if (!objectExpr)
|
||||
return null();
|
||||
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::Rp, TokenStream::Operand, JSMSG_PAREN_AFTER_WITH);
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::RightParen, TokenStream::Operand, JSMSG_PAREN_AFTER_WITH);
|
||||
|
||||
Node innerBlock;
|
||||
{
|
||||
|
|
@ -7067,7 +7067,7 @@ GeneralParser<ParseHandler, CharT>::throwStatement(YieldHandling yieldHandling)
|
|||
TokenKind tt = TokenKind::Eof;
|
||||
if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand))
|
||||
return null();
|
||||
if (tt == TokenKind::Eof || tt == TokenKind::Semi || tt == TokenKind::Rc) {
|
||||
if (tt == TokenKind::Eof || tt == TokenKind::Semi || tt == TokenKind::RightCurly) {
|
||||
error(JSMSG_MISSING_EXPR_AFTER_THROW);
|
||||
return null();
|
||||
}
|
||||
|
|
@ -7105,14 +7105,14 @@ GeneralParser<ParseHandler, CharT>::tryStatement(YieldHandling yieldHandling)
|
|||
*
|
||||
* catch lvalue nodes are either:
|
||||
* a single identifier
|
||||
* TokenKind::Rb or TokenKind::Rc for a destructuring left-hand side
|
||||
* TokenKind::RightBracket or TokenKind::RightCurly for a destructuring left-hand side
|
||||
*
|
||||
* finally nodes are TokenKind::Lc statement lists.
|
||||
* finally nodes are TokenKind::LeftCurly statement lists.
|
||||
*/
|
||||
|
||||
Node innerBlock;
|
||||
{
|
||||
MUST_MATCH_TOKEN(TokenKind::Lc, JSMSG_CURLY_BEFORE_TRY);
|
||||
MUST_MATCH_TOKEN(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_TRY);
|
||||
|
||||
uint32_t openedPos = pos().begin;
|
||||
|
||||
|
|
@ -7129,7 +7129,7 @@ GeneralParser<ParseHandler, CharT>::tryStatement(YieldHandling yieldHandling)
|
|||
if (!innerBlock)
|
||||
return null();
|
||||
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::Rc, TokenStream::Operand,
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::RightCurly, TokenStream::Operand,
|
||||
reportMissingClosing(JSMSG_CURLY_AFTER_TRY,
|
||||
JSMSG_CURLY_OPENED, openedPos));
|
||||
}
|
||||
|
|
@ -7155,20 +7155,20 @@ GeneralParser<ParseHandler, CharT>::tryStatement(YieldHandling yieldHandling)
|
|||
* where lhs is a name or a destructuring left-hand side.
|
||||
*/
|
||||
bool omittedBinding;
|
||||
if (!tokenStream.matchToken(&omittedBinding, TokenKind::Lc))
|
||||
if (!tokenStream.matchToken(&omittedBinding, TokenKind::LeftCurly))
|
||||
return null();
|
||||
|
||||
Node catchName;
|
||||
if (omittedBinding) {
|
||||
catchName = null();
|
||||
} else {
|
||||
MUST_MATCH_TOKEN(TokenKind::Lp, JSMSG_PAREN_BEFORE_CATCH);
|
||||
MUST_MATCH_TOKEN(TokenKind::LeftParen, JSMSG_PAREN_BEFORE_CATCH);
|
||||
|
||||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
switch (tt) {
|
||||
case TokenKind::Lb:
|
||||
case TokenKind::Lc:
|
||||
case TokenKind::LeftBracket:
|
||||
case TokenKind::LeftCurly:
|
||||
catchName = destructuringDeclaration(DeclarationKind::CatchParameter,
|
||||
yieldHandling, tt);
|
||||
if (!catchName)
|
||||
|
|
@ -7189,9 +7189,9 @@ GeneralParser<ParseHandler, CharT>::tryStatement(YieldHandling yieldHandling)
|
|||
}
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::Rp, TokenStream::Operand, JSMSG_PAREN_AFTER_CATCH);
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::RightParen, TokenStream::Operand, JSMSG_PAREN_AFTER_CATCH);
|
||||
|
||||
MUST_MATCH_TOKEN(TokenKind::Lc, JSMSG_CURLY_BEFORE_CATCH);
|
||||
MUST_MATCH_TOKEN(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_CATCH);
|
||||
}
|
||||
|
||||
Node catchBody = catchBlockStatement(yieldHandling, scope);
|
||||
|
|
@ -7213,7 +7213,7 @@ GeneralParser<ParseHandler, CharT>::tryStatement(YieldHandling yieldHandling)
|
|||
Node finallyBlock = null();
|
||||
|
||||
if (tt == TokenKind::Finally) {
|
||||
MUST_MATCH_TOKEN(TokenKind::Lc, JSMSG_CURLY_BEFORE_FINALLY);
|
||||
MUST_MATCH_TOKEN(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_FINALLY);
|
||||
|
||||
uint32_t openedPos = pos().begin;
|
||||
|
||||
|
|
@ -7230,7 +7230,7 @@ GeneralParser<ParseHandler, CharT>::tryStatement(YieldHandling yieldHandling)
|
|||
if (!finallyBlock)
|
||||
return null();
|
||||
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::Rc, TokenStream::Operand,
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::RightCurly, TokenStream::Operand,
|
||||
reportMissingClosing(JSMSG_CURLY_AFTER_FINALLY,
|
||||
JSMSG_CURLY_OPENED, openedPos));
|
||||
} else {
|
||||
|
|
@ -7270,7 +7270,7 @@ GeneralParser<ParseHandler, CharT>::catchBlockStatement(YieldHandling yieldHandl
|
|||
if (!list)
|
||||
return null();
|
||||
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::Rc, TokenStream::Operand,
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::RightCurly, TokenStream::Operand,
|
||||
reportMissingClosing(JSMSG_CURLY_AFTER_CATCH,
|
||||
JSMSG_CURLY_OPENED, openedPos));
|
||||
|
||||
|
|
@ -7385,7 +7385,7 @@ GeneralParser<ParseHandler, CharT>::classDefinition(YieldHandling yieldHandling,
|
|||
return null();
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN(TokenKind::Lc, JSMSG_CURLY_BEFORE_CLASS);
|
||||
MUST_MATCH_TOKEN(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_CLASS);
|
||||
|
||||
Node classMethods = handler.newClassMethodList(pos().begin);
|
||||
if (!classMethods)
|
||||
|
|
@ -7396,7 +7396,7 @@ GeneralParser<ParseHandler, CharT>::classDefinition(YieldHandling yieldHandling,
|
|||
TokenKind tt;
|
||||
if (!tokenStream.getToken(&tt))
|
||||
return null();
|
||||
if (tt == TokenKind::Rc)
|
||||
if (tt == TokenKind::RightCurly)
|
||||
break;
|
||||
|
||||
if (tt == TokenKind::Semi)
|
||||
|
|
@ -7406,13 +7406,13 @@ GeneralParser<ParseHandler, CharT>::classDefinition(YieldHandling yieldHandling,
|
|||
if (tt == TokenKind::Static) {
|
||||
if (!tokenStream.peekToken(&tt))
|
||||
return null();
|
||||
if (tt == TokenKind::Rc) {
|
||||
if (tt == TokenKind::RightCurly) {
|
||||
tokenStream.consumeKnownToken(tt);
|
||||
error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt));
|
||||
return null();
|
||||
}
|
||||
|
||||
if (tt != TokenKind::Lp)
|
||||
if (tt != TokenKind::LeftParen)
|
||||
isStatic = true;
|
||||
else
|
||||
anyChars.ungetToken();
|
||||
|
|
@ -7458,7 +7458,7 @@ GeneralParser<ParseHandler, CharT>::classDefinition(YieldHandling yieldHandling,
|
|||
switch (propType) {
|
||||
case PropertyType::Getter:
|
||||
case PropertyType::Setter:
|
||||
if (!anyChars.isCurrentTokenType(TokenKind::Rb)) {
|
||||
if (!anyChars.isCurrentTokenType(TokenKind::RightBracket)) {
|
||||
funName = prefixAccessorName(propType, propAtom);
|
||||
if (!funName)
|
||||
return null();
|
||||
|
|
@ -7469,7 +7469,7 @@ GeneralParser<ParseHandler, CharT>::classDefinition(YieldHandling yieldHandling,
|
|||
funName = name;
|
||||
break;
|
||||
default:
|
||||
if (!anyChars.isCurrentTokenType(TokenKind::Rb))
|
||||
if (!anyChars.isCurrentTokenType(TokenKind::RightBracket))
|
||||
funName = propAtom;
|
||||
}
|
||||
|
||||
|
|
@ -7547,7 +7547,7 @@ ParserBase::nextTokenContinuesLetDeclaration(TokenKind next)
|
|||
TokenStreamShared::verifyConsistentModifier(TokenStreamShared::None, anyChars.nextToken());
|
||||
|
||||
// Destructuring continues a let declaration.
|
||||
if (next == TokenKind::Lb || next == TokenKind::Lc)
|
||||
if (next == TokenKind::LeftBracket || next == TokenKind::LeftCurly)
|
||||
return true;
|
||||
|
||||
// A "let" edge case deserves special comment. Consider this:
|
||||
|
|
@ -7592,7 +7592,7 @@ GeneralParser<ParseHandler, CharT>::statement(YieldHandling yieldHandling)
|
|||
|
||||
switch (tt) {
|
||||
// BlockStatement[?Yield, ?Return]
|
||||
case TokenKind::Lc:
|
||||
case TokenKind::LeftCurly:
|
||||
return blockStatement(yieldHandling);
|
||||
|
||||
// VariableStatement[?Yield]
|
||||
|
|
@ -7641,10 +7641,10 @@ GeneralParser<ParseHandler, CharT>::statement(YieldHandling yieldHandling)
|
|||
if (tt == TokenKind::Let) {
|
||||
bool forbiddenLetDeclaration = false;
|
||||
|
||||
if (next == TokenKind::Lb) {
|
||||
if (next == TokenKind::LeftBracket) {
|
||||
// Enforce ExpressionStatement's 'let [' lookahead restriction.
|
||||
forbiddenLetDeclaration = true;
|
||||
} else if (next == TokenKind::Lc || TokenKindIsPossibleIdentifier(next)) {
|
||||
} else if (next == TokenKind::LeftCurly || TokenKindIsPossibleIdentifier(next)) {
|
||||
// 'let {' and 'let foo' aren't completely forbidden, if ASI
|
||||
// causes 'let' to be the entire Statement. But if they're
|
||||
// same-line, we can aggressively give a better error message.
|
||||
|
|
@ -7656,7 +7656,7 @@ GeneralParser<ParseHandler, CharT>::statement(YieldHandling yieldHandling)
|
|||
return null();
|
||||
|
||||
MOZ_ASSERT(TokenKindIsPossibleIdentifier(nextSameLine) ||
|
||||
nextSameLine == TokenKind::Lc ||
|
||||
nextSameLine == TokenKind::LeftCurly ||
|
||||
nextSameLine == TokenKind::Eol);
|
||||
|
||||
forbiddenLetDeclaration = nextSameLine != TokenKind::Eol;
|
||||
|
|
@ -7810,7 +7810,7 @@ GeneralParser<ParseHandler, CharT>::statementListItem(YieldHandling yieldHandlin
|
|||
|
||||
switch (tt) {
|
||||
// BlockStatement[?Yield, ?Return]
|
||||
case TokenKind::Lc:
|
||||
case TokenKind::LeftCurly:
|
||||
return blockStatement(yieldHandling);
|
||||
|
||||
// VariableStatement[?Yield]
|
||||
|
|
@ -8019,13 +8019,13 @@ GeneralParser<ParseHandler, CharT>::expr(InHandling inHandling, YieldHandling yi
|
|||
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
|
||||
return null();
|
||||
|
||||
if (tt == TokenKind::Rp) {
|
||||
tokenStream.consumeKnownToken(TokenKind::Rp, TokenStream::Operand);
|
||||
if (tt == TokenKind::RightParen) {
|
||||
tokenStream.consumeKnownToken(TokenKind::RightParen, TokenStream::Operand);
|
||||
|
||||
if (!tokenStream.peekToken(&tt))
|
||||
return null();
|
||||
if (tt != TokenKind::Arrow) {
|
||||
error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TokenKind::Rp));
|
||||
error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TokenKind::RightParen));
|
||||
return null();
|
||||
}
|
||||
|
||||
|
|
@ -8362,7 +8362,7 @@ GeneralParser<ParseHandler, CharT>::assignExpr(InHandling inHandling, YieldHandl
|
|||
// The AsyncArrowFunction production are
|
||||
// async [no LineTerminator here] AsyncArrowBindingIdentifier ...
|
||||
// async [no LineTerminator here] ArrowFormalParameters ...
|
||||
if (TokenKindIsPossibleIdentifier(nextSameLine) || nextSameLine == TokenKind::Lp)
|
||||
if (TokenKindIsPossibleIdentifier(nextSameLine) || nextSameLine == TokenKind::LeftParen)
|
||||
asyncKind = FunctionAsyncKind::AsyncFunction;
|
||||
else
|
||||
anyChars.ungetToken();
|
||||
|
|
@ -8683,7 +8683,7 @@ GeneralParser<ParseHandler, CharT>::argumentList(YieldHandling yieldHandling, bo
|
|||
return null();
|
||||
|
||||
bool matched;
|
||||
if (!tokenStream.matchToken(&matched, TokenKind::Rp, TokenStream::Operand))
|
||||
if (!tokenStream.matchToken(&matched, TokenKind::RightParen, TokenStream::Operand))
|
||||
return null();
|
||||
if (matched) {
|
||||
handler.setEndPosition(argsList, pos().end);
|
||||
|
|
@ -8721,11 +8721,11 @@ GeneralParser<ParseHandler, CharT>::argumentList(YieldHandling yieldHandling, bo
|
|||
TokenKind tt;
|
||||
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
|
||||
return null();
|
||||
if (tt == TokenKind::Rp)
|
||||
if (tt == TokenKind::RightParen)
|
||||
break;
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::Rp, TokenStream::Operand, JSMSG_PAREN_AFTER_ARGS);
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::RightParen, TokenStream::Operand, JSMSG_PAREN_AFTER_ARGS);
|
||||
|
||||
handler.setEndPosition(argsList, pos().end);
|
||||
return argsList;
|
||||
|
|
@ -8775,7 +8775,7 @@ GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
|
|||
return null();
|
||||
|
||||
bool matched;
|
||||
if (!tokenStream.matchToken(&matched, TokenKind::Lp))
|
||||
if (!tokenStream.matchToken(&matched, TokenKind::LeftParen))
|
||||
return null();
|
||||
|
||||
bool isSpread = false;
|
||||
|
|
@ -8843,12 +8843,12 @@ GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
|
|||
error(JSMSG_NAME_AFTER_DOT);
|
||||
return null();
|
||||
}
|
||||
} else if (tt == TokenKind::Lb) {
|
||||
} else if (tt == TokenKind::LeftBracket) {
|
||||
Node propExpr = expr(InAllowed, yieldHandling, TripledotProhibited);
|
||||
if (!propExpr)
|
||||
return null();
|
||||
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::Rb, TokenStream::Operand, JSMSG_BRACKET_IN_INDEX);
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::RightBracket, TokenStream::Operand, JSMSG_BRACKET_IN_INDEX);
|
||||
|
||||
if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) {
|
||||
error(JSMSG_BAD_SUPERPROP, "member");
|
||||
|
|
@ -8857,7 +8857,7 @@ GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
|
|||
nextMember = handler.newPropertyByValue(lhs, propExpr, pos().end);
|
||||
if (!nextMember)
|
||||
return null();
|
||||
} else if ((allowCallSyntax && tt == TokenKind::Lp) ||
|
||||
} else if ((allowCallSyntax && tt == TokenKind::LeftParen) ||
|
||||
tt == TokenKind::TemplateHead ||
|
||||
tt == TokenKind::NoSubsTemplate)
|
||||
{
|
||||
|
|
@ -8867,7 +8867,7 @@ GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
|
|||
return null();
|
||||
}
|
||||
|
||||
if (tt != TokenKind::Lp) {
|
||||
if (tt != TokenKind::LeftParen) {
|
||||
error(JSMSG_BAD_SUPER);
|
||||
return null();
|
||||
}
|
||||
|
|
@ -8912,7 +8912,7 @@ GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
|
|||
} else if (prop == context->names().call) {
|
||||
op = JSOP_FUNCALL;
|
||||
}
|
||||
} else if (tt == TokenKind::Lp) {
|
||||
} else if (tt == TokenKind::LeftParen) {
|
||||
if (handler.isAsyncKeyword(lhs, context)) {
|
||||
// |async (| can be the start of an async arrow
|
||||
// function, so we need to defer reporting possible
|
||||
|
|
@ -8941,7 +8941,7 @@ GeneralParser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
|
|||
}
|
||||
}
|
||||
|
||||
if (tt == TokenKind::Lp) {
|
||||
if (tt == TokenKind::LeftParen) {
|
||||
bool isSpread = false;
|
||||
PossibleError* asyncPossibleError = maybeAsyncArrow ? possibleError : nullptr;
|
||||
Node args = argumentList(yieldHandling, &isSpread, asyncPossibleError);
|
||||
|
|
@ -9342,7 +9342,7 @@ typename ParseHandler::Node
|
|||
GeneralParser<ParseHandler, CharT>::arrayInitializer(YieldHandling yieldHandling,
|
||||
PossibleError* possibleError)
|
||||
{
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Lb));
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket));
|
||||
|
||||
uint32_t begin = pos().begin;
|
||||
Node literal = handler.newArrayLiteral(begin);
|
||||
|
|
@ -9353,7 +9353,7 @@ GeneralParser<ParseHandler, CharT>::arrayInitializer(YieldHandling yieldHandling
|
|||
if (!tokenStream.getToken(&tt, TokenStream::Operand))
|
||||
return null();
|
||||
|
||||
if (tt == TokenKind::Rb) {
|
||||
if (tt == TokenKind::RightBracket) {
|
||||
/*
|
||||
* Mark empty arrays as non-constant, since we cannot easily
|
||||
* determine their type.
|
||||
|
|
@ -9371,7 +9371,7 @@ GeneralParser<ParseHandler, CharT>::arrayInitializer(YieldHandling yieldHandling
|
|||
TokenKind tt;
|
||||
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
|
||||
return null();
|
||||
if (tt == TokenKind::Rb)
|
||||
if (tt == TokenKind::RightBracket)
|
||||
break;
|
||||
|
||||
if (tt == TokenKind::Comma) {
|
||||
|
|
@ -9432,7 +9432,7 @@ GeneralParser<ParseHandler, CharT>::arrayInitializer(YieldHandling yieldHandling
|
|||
possibleError->setPendingDestructuringErrorAt(pos(), JSMSG_REST_WITH_COMMA);
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::Rb, TokenStream::Operand,
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::RightBracket, TokenStream::Operand,
|
||||
reportMissingClosing(JSMSG_BRACKET_AFTER_LIST,
|
||||
JSMSG_BRACKET_OPENED, begin));
|
||||
}
|
||||
|
|
@ -9453,7 +9453,7 @@ GeneralParser<ParseHandler, CharT>::propertyName(YieldHandling yieldHandling,
|
|||
if (!tokenStream.getToken(<ok))
|
||||
return null();
|
||||
|
||||
MOZ_ASSERT(ltok != TokenKind::Rc, "caller should have handled TokenKind::Rc");
|
||||
MOZ_ASSERT(ltok != TokenKind::RightCurly, "caller should have handled TokenKind::RightCurly");
|
||||
|
||||
bool isGenerator = false;
|
||||
bool isAsync = false;
|
||||
|
|
@ -9479,7 +9479,7 @@ GeneralParser<ParseHandler, CharT>::propertyName(YieldHandling yieldHandling,
|
|||
TokenKind tt = TokenKind::Eof;
|
||||
if (!tokenStream.peekTokenSameLine(&tt))
|
||||
return null();
|
||||
if (tt == TokenKind::String || tt == TokenKind::Number || tt == TokenKind::Lb ||
|
||||
if (tt == TokenKind::String || tt == TokenKind::Number || tt == TokenKind::LeftBracket ||
|
||||
TokenKindIsPossibleIdentifierName(tt) || tt == TokenKind::Mul)
|
||||
{
|
||||
isAsync = true;
|
||||
|
|
@ -9521,7 +9521,7 @@ GeneralParser<ParseHandler, CharT>::propertyName(YieldHandling yieldHandling,
|
|||
break;
|
||||
}
|
||||
|
||||
case TokenKind::Lb:
|
||||
case TokenKind::LeftBracket:
|
||||
propName = computedPropertyName(yieldHandling, maybeDecl, propList);
|
||||
if (!propName)
|
||||
return null();
|
||||
|
|
@ -9577,8 +9577,8 @@ GeneralParser<ParseHandler, CharT>::propertyName(YieldHandling yieldHandling,
|
|||
return null();
|
||||
return newNumber(anyChars.currentToken());
|
||||
}
|
||||
if (tt == TokenKind::Lb) {
|
||||
tokenStream.consumeKnownToken(TokenKind::Lb);
|
||||
if (tt == TokenKind::LeftBracket) {
|
||||
tokenStream.consumeKnownToken(TokenKind::LeftBracket);
|
||||
|
||||
return computedPropertyName(yieldHandling, maybeDecl, propList);
|
||||
}
|
||||
|
|
@ -9605,7 +9605,7 @@ GeneralParser<ParseHandler, CharT>::propertyName(YieldHandling yieldHandling,
|
|||
}
|
||||
|
||||
if (TokenKindIsPossibleIdentifierName(ltok) &&
|
||||
(tt == TokenKind::Comma || tt == TokenKind::Rc || tt == TokenKind::Assign))
|
||||
(tt == TokenKind::Comma || tt == TokenKind::RightCurly || tt == TokenKind::Assign))
|
||||
{
|
||||
if (isGenerator || isAsync) {
|
||||
error(JSMSG_BAD_PROP_ID);
|
||||
|
|
@ -9620,7 +9620,7 @@ GeneralParser<ParseHandler, CharT>::propertyName(YieldHandling yieldHandling,
|
|||
return propName;
|
||||
}
|
||||
|
||||
if (tt == TokenKind::Lp) {
|
||||
if (tt == TokenKind::LeftParen) {
|
||||
anyChars.ungetToken();
|
||||
|
||||
if (isGenerator && isAsync)
|
||||
|
|
@ -9644,7 +9644,7 @@ GeneralParser<ParseHandler, CharT>::computedPropertyName(YieldHandling yieldHand
|
|||
const Maybe<DeclarationKind>& maybeDecl,
|
||||
Node literal)
|
||||
{
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Lb));
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftBracket));
|
||||
|
||||
uint32_t begin = pos().begin;
|
||||
|
||||
|
|
@ -9659,7 +9659,7 @@ GeneralParser<ParseHandler, CharT>::computedPropertyName(YieldHandling yieldHand
|
|||
if (!assignNode)
|
||||
return null();
|
||||
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::Rb, TokenStream::Operand, JSMSG_COMP_PROP_UNTERM_EXPR);
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::RightBracket, TokenStream::Operand, JSMSG_COMP_PROP_UNTERM_EXPR);
|
||||
return handler.newComputedName(assignNode, begin, pos().end);
|
||||
}
|
||||
|
||||
|
|
@ -9668,7 +9668,7 @@ typename ParseHandler::Node
|
|||
GeneralParser<ParseHandler, CharT>::objectLiteral(YieldHandling yieldHandling,
|
||||
PossibleError* possibleError)
|
||||
{
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Lc));
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftCurly));
|
||||
|
||||
uint32_t openedPos = pos().begin;
|
||||
|
||||
|
|
@ -9684,7 +9684,7 @@ GeneralParser<ParseHandler, CharT>::objectLiteral(YieldHandling yieldHandling,
|
|||
TokenKind tt;
|
||||
if (!tokenStream.peekToken(&tt))
|
||||
return null();
|
||||
if (tt == TokenKind::Rc) {
|
||||
if (tt == TokenKind::RightCurly) {
|
||||
anyChars.addModifierException(TokenStream::OperandIsNone);
|
||||
break;
|
||||
}
|
||||
|
|
@ -9845,7 +9845,7 @@ GeneralParser<ParseHandler, CharT>::objectLiteral(YieldHandling yieldHandling,
|
|||
return null();
|
||||
} else {
|
||||
RootedAtom funName(context);
|
||||
if (!anyChars.isCurrentTokenType(TokenKind::Rb)) {
|
||||
if (!anyChars.isCurrentTokenType(TokenKind::RightBracket)) {
|
||||
funName = propAtom;
|
||||
|
||||
if (propType == PropertyType::Getter || propType == PropertyType::Setter) {
|
||||
|
|
@ -9879,7 +9879,7 @@ GeneralParser<ParseHandler, CharT>::objectLiteral(YieldHandling yieldHandling,
|
|||
possibleError->setPendingDestructuringErrorAt(pos(), JSMSG_REST_WITH_COMMA);
|
||||
}
|
||||
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::Rc, TokenStream::Operand,
|
||||
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TokenKind::RightCurly, TokenStream::Operand,
|
||||
reportMissingClosing(JSMSG_CURLY_AFTER_LIST,
|
||||
JSMSG_CURLY_OPENED, openedPos));
|
||||
|
||||
|
|
@ -10042,26 +10042,26 @@ GeneralParser<ParseHandler, CharT>::primaryExpr(YieldHandling yieldHandling,
|
|||
case TokenKind::Class:
|
||||
return classDefinition(yieldHandling, ClassExpression, NameRequired);
|
||||
|
||||
case TokenKind::Lb:
|
||||
case TokenKind::LeftBracket:
|
||||
return arrayInitializer(yieldHandling, possibleError);
|
||||
|
||||
case TokenKind::Lc:
|
||||
case TokenKind::LeftCurly:
|
||||
return objectLiteral(yieldHandling, possibleError);
|
||||
|
||||
case TokenKind::Lp: {
|
||||
case TokenKind::LeftParen: {
|
||||
TokenKind next;
|
||||
if (!tokenStream.peekToken(&next, TokenStream::Operand))
|
||||
return null();
|
||||
|
||||
if (next == TokenKind::Rp) {
|
||||
if (next == TokenKind::RightParen) {
|
||||
// Not valid expression syntax, but this is valid in an arrow function
|
||||
// with no params: `() => body`.
|
||||
tokenStream.consumeKnownToken(TokenKind::Rp, TokenStream::Operand);
|
||||
tokenStream.consumeKnownToken(TokenKind::RightParen, TokenStream::Operand);
|
||||
|
||||
if (!tokenStream.peekToken(&next))
|
||||
return null();
|
||||
if (next != TokenKind::Arrow) {
|
||||
error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TokenKind::Rp));
|
||||
error(JSMSG_UNEXPECTED_TOKEN, "expression", TokenKindToDesc(TokenKind::RightParen));
|
||||
return null();
|
||||
}
|
||||
|
||||
|
|
@ -10075,7 +10075,7 @@ GeneralParser<ParseHandler, CharT>::primaryExpr(YieldHandling yieldHandling,
|
|||
Node expr = exprInParens(InAllowed, yieldHandling, TripledotAllowed, possibleError);
|
||||
if (!expr)
|
||||
return null();
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::Rp, TokenStream::Operand, JSMSG_PAREN_IN_PAREN);
|
||||
MUST_MATCH_TOKEN_MOD(TokenKind::RightParen, TokenStream::Operand, JSMSG_PAREN_IN_PAREN);
|
||||
return handler.parenthesize(expr);
|
||||
}
|
||||
|
||||
|
|
@ -10153,7 +10153,7 @@ GeneralParser<ParseHandler, CharT>::primaryExpr(YieldHandling yieldHandling,
|
|||
if (!tokenStream.getToken(&next))
|
||||
return null();
|
||||
|
||||
if (next == TokenKind::Lb || next == TokenKind::Lc) {
|
||||
if (next == TokenKind::LeftBracket || next == TokenKind::LeftCurly) {
|
||||
// Validate, but don't store the pattern right now. The whole arrow
|
||||
// function is reparsed in functionFormalParametersAndBody().
|
||||
if (!destructuringDeclaration(DeclarationKind::CoverArrowParameter, yieldHandling,
|
||||
|
|
@ -10174,7 +10174,7 @@ GeneralParser<ParseHandler, CharT>::primaryExpr(YieldHandling yieldHandling,
|
|||
|
||||
if (!tokenStream.getToken(&next))
|
||||
return null();
|
||||
if (next != TokenKind::Rp) {
|
||||
if (next != TokenKind::RightParen) {
|
||||
error(JSMSG_UNEXPECTED_TOKEN, "closing parenthesis", TokenKindToDesc(next));
|
||||
return null();
|
||||
}
|
||||
|
|
@ -10190,7 +10190,7 @@ GeneralParser<ParseHandler, CharT>::primaryExpr(YieldHandling yieldHandling,
|
|||
|
||||
anyChars.ungetToken(); // put back right paren
|
||||
|
||||
// Return an arbitrary expression node. See case TokenKind::Rp above.
|
||||
// Return an arbitrary expression node. See case TokenKind::RightParen above.
|
||||
return handler.newNullLiteral(pos());
|
||||
}
|
||||
}
|
||||
|
|
@ -10203,7 +10203,7 @@ GeneralParser<ParseHandler, CharT>::exprInParens(InHandling inHandling,
|
|||
TripledotHandling tripledotHandling,
|
||||
PossibleError* possibleError /* = nullptr */)
|
||||
{
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::Lp));
|
||||
MOZ_ASSERT(anyChars.isCurrentTokenType(TokenKind::LeftParen));
|
||||
return expr(inHandling, yieldHandling, tripledotHandling, possibleError, PredictInvoked);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -66,12 +66,12 @@
|
|||
macro(Dec, "'--'") /* decrement */ \
|
||||
macro(Dot, "'.'") /* member operator */ \
|
||||
macro(TripleDot, "'...'") /* rest arguments and spread operator */ \
|
||||
macro(Lb, "'['") \
|
||||
macro(Rb, "']'") \
|
||||
macro(Lc, "'{'") \
|
||||
macro(Rc, "'}'") \
|
||||
macro(Lp, "'('") \
|
||||
macro(Rp, "')'") \
|
||||
macro(LeftBracket, "'['") \
|
||||
macro(RightBracket, "']'") \
|
||||
macro(LeftCurly, "'{'") \
|
||||
macro(RightCurly, "'}'") \
|
||||
macro(LeftParen, "'('") \
|
||||
macro(RightParen, "')'") \
|
||||
macro(Name, "identifier") \
|
||||
macro(Number, "numeric literal") \
|
||||
macro(String, "string literal") \
|
||||
|
|
|
|||
|
|
@ -443,9 +443,9 @@ TokenStreamAnyChars::TokenStreamAnyChars(JSContext* cx, const ReadOnlyCompileOpt
|
|||
isExprEnding[size_t(TokenKind::Comma)] = true;
|
||||
isExprEnding[size_t(TokenKind::Semi)] = true;
|
||||
isExprEnding[size_t(TokenKind::Colon)] = true;
|
||||
isExprEnding[size_t(TokenKind::Rp)] = true;
|
||||
isExprEnding[size_t(TokenKind::Rb)] = true;
|
||||
isExprEnding[size_t(TokenKind::Rc)] = true;
|
||||
isExprEnding[size_t(TokenKind::RightParen)] = true;
|
||||
isExprEnding[size_t(TokenKind::RightBracket)] = true;
|
||||
isExprEnding[size_t(TokenKind::RightCurly)] = true;
|
||||
}
|
||||
|
||||
template<typename CharT>
|
||||
|
|
@ -1974,14 +1974,14 @@ enum FirstCharKind {
|
|||
#define T_COMMA size_t(TokenKind::Comma)
|
||||
#define T_COLON size_t(TokenKind::Colon)
|
||||
#define T_BITNOT size_t(TokenKind::BitNot)
|
||||
#define T_LP size_t(TokenKind::Lp)
|
||||
#define T_RP size_t(TokenKind::Rp)
|
||||
#define T_LP size_t(TokenKind::LeftParen)
|
||||
#define T_RP size_t(TokenKind::RightParen)
|
||||
#define T_SEMI size_t(TokenKind::Semi)
|
||||
#define T_HOOK size_t(TokenKind::Hook)
|
||||
#define T_LB size_t(TokenKind::Lb)
|
||||
#define T_RB size_t(TokenKind::Rb)
|
||||
#define T_LC size_t(TokenKind::Lc)
|
||||
#define T_RC size_t(TokenKind::Rc)
|
||||
#define T_LB size_t(TokenKind::LeftBracket)
|
||||
#define T_RB size_t(TokenKind::RightBracket)
|
||||
#define T_LC size_t(TokenKind::LeftCurly)
|
||||
#define T_RC size_t(TokenKind::RightCurly)
|
||||
#define _______ Other
|
||||
static const uint8_t firstCharKinds[] = {
|
||||
/* 0 1 2 3 4 5 6 7 8 9 */
|
||||
|
|
|
|||
|
|
@ -5643,7 +5643,7 @@ CheckModuleReturn(ModuleValidator& m)
|
|||
return false;
|
||||
auto& ts = m.parser().tokenStream;
|
||||
if (tk != TokenKind::Return) {
|
||||
return m.failCurrentOffset((tk == TokenKind::Rc || tk == TokenKind::Eof)
|
||||
return m.failCurrentOffset((tk == TokenKind::RightCurly || tk == TokenKind::Eof)
|
||||
? "expecting return statement"
|
||||
: "invalid asm.js. statement");
|
||||
}
|
||||
|
|
@ -5675,7 +5675,7 @@ CheckModuleEnd(ModuleValidator &m)
|
|||
if (!GetToken(m.parser(), &tk))
|
||||
return false;
|
||||
|
||||
if (tk != TokenKind::Eof && tk != TokenKind::Rc)
|
||||
if (tk != TokenKind::Eof && tk != TokenKind::RightCurly)
|
||||
return m.failCurrentOffset("top-level export (return) must be the last statement");
|
||||
|
||||
m.parser().tokenStream.anyCharsAccess().ungetToken();
|
||||
|
|
|
|||
|
|
@ -4612,7 +4612,7 @@ nsBlockFrame::PlaceLine(BlockReflowInput& aState,
|
|||
0 == mLines.front()->BSize() &&
|
||||
aLine == mLines.begin().next()))) {
|
||||
ReflowOutput metrics(aState.mReflowInput);
|
||||
nsIFrame* bullet = GetOutsideBullet();
|
||||
nsBulletFrame* bullet = GetOutsideBullet();
|
||||
ReflowBullet(bullet, aState, metrics, aState.mBCoord);
|
||||
NS_ASSERTION(!BulletIsEmpty() || metrics.BSize(wm) == 0,
|
||||
"empty bullet took up space");
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include "LayoutLogging.h"
|
||||
#include "SVGTextFrame.h"
|
||||
#include "nsBlockFrame.h"
|
||||
#include "nsBulletFrame.h"
|
||||
#include "nsFontMetrics.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsContainerFrame.h"
|
||||
|
|
@ -1448,7 +1449,7 @@ nsLineLayout::PlaceFrame(PerFrameData* pfd, ReflowOutput& aMetrics)
|
|||
}
|
||||
|
||||
void
|
||||
nsLineLayout::AddBulletFrame(nsIFrame* aFrame,
|
||||
nsLineLayout::AddBulletFrame(nsBulletFrame* aFrame,
|
||||
const ReflowOutput& aMetrics)
|
||||
{
|
||||
NS_ASSERTION(mCurrentSpan == mRootSpan, "bad linelayout user");
|
||||
|
|
@ -1464,7 +1465,14 @@ nsLineLayout::AddBulletFrame(nsIFrame* aFrame,
|
|||
|
||||
WritingMode lineWM = mRootSpan->mWritingMode;
|
||||
PerFrameData* pfd = NewPerFrameData(aFrame);
|
||||
mRootSpan->AppendFrame(pfd);
|
||||
PerSpanData* psd = mRootSpan;
|
||||
|
||||
MOZ_ASSERT(psd->mFirstFrame, "adding bullet to an empty line?");
|
||||
// Prepend the bullet frame to the line.
|
||||
psd->mFirstFrame->mPrev = pfd;
|
||||
pfd->mNext = psd->mFirstFrame;
|
||||
psd->mFirstFrame = pfd;
|
||||
|
||||
pfd->mIsBullet = true;
|
||||
if (aMetrics.BlockStartAscent() == ReflowOutput::ASK_FOR_BASELINE) {
|
||||
pfd->mAscent = aFrame->GetLogicalBaseline(lineWM);
|
||||
|
|
@ -1477,6 +1485,21 @@ nsLineLayout::AddBulletFrame(nsIFrame* aFrame,
|
|||
pfd->mOverflowAreas = aMetrics.mOverflowAreas;
|
||||
}
|
||||
|
||||
void
|
||||
nsLineLayout::RemoveBulletFrame(nsBulletFrame* aFrame)
|
||||
{
|
||||
PerSpanData* psd = mCurrentSpan;
|
||||
MOZ_ASSERT(psd == mRootSpan, "bullet on non-root span?");
|
||||
MOZ_ASSERT(psd->mFirstFrame->mFrame == aFrame,
|
||||
"bullet is not the first frame?");
|
||||
PerFrameData* pfd = psd->mFirstFrame;
|
||||
MOZ_ASSERT(pfd != psd->mLastFrame,
|
||||
"bullet is the only frame?");
|
||||
pfd->mNext->mPrev = nullptr;
|
||||
psd->mFirstFrame = pfd->mNext;
|
||||
FreeFrame(pfd);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
nsLineLayout::DumpPerSpanData(PerSpanData* psd, int32_t aIndent)
|
||||
|
|
@ -3286,7 +3309,15 @@ nsLineLayout::TextAlignLine(nsLineBox* aLine,
|
|||
|
||||
if (mPresContext->BidiEnabled() &&
|
||||
(!mPresContext->IsVisualMode() || !lineWM.IsBidiLTR())) {
|
||||
nsBidiPresUtils::ReorderFrames(psd->mFirstFrame->mFrame,
|
||||
PerFrameData* startFrame = psd->mFirstFrame;
|
||||
MOZ_ASSERT(startFrame, "empty line?");
|
||||
if (startFrame->mIsBullet) {
|
||||
// Bullet shouldn't participate in bidi reordering.
|
||||
startFrame = startFrame->mNext;
|
||||
MOZ_ASSERT(startFrame, "no frame after bullet?");
|
||||
MOZ_ASSERT(!startFrame->mIsBullet, "multiple bullets?");
|
||||
}
|
||||
nsBidiPresUtils::ReorderFrames(startFrame->mFrame,
|
||||
aLine->GetChildCount(),
|
||||
lineWM, mContainerSize,
|
||||
psd->mIStart + mTextIndent + dx);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include "BlockReflowInput.h"
|
||||
#include "nsLineBox.h"
|
||||
|
||||
class nsBulletFrame;
|
||||
class nsFloatManager;
|
||||
struct nsStyleText;
|
||||
|
||||
|
|
@ -101,11 +102,9 @@ public:
|
|||
ReflowOutput* aMetrics,
|
||||
bool& aPushedFrame);
|
||||
|
||||
void AddBulletFrame(nsIFrame* aFrame, const ReflowOutput& aMetrics);
|
||||
void AddBulletFrame(nsBulletFrame* aFrame, const ReflowOutput& aMetrics);
|
||||
|
||||
void RemoveBulletFrame(nsIFrame* aFrame) {
|
||||
PushFrame(aFrame);
|
||||
}
|
||||
void RemoveBulletFrame(nsBulletFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Place frames in the block direction (CSS property vertical-align)
|
||||
|
|
@ -547,10 +546,9 @@ protected:
|
|||
nscoord* mBaseline;
|
||||
|
||||
void AppendFrame(PerFrameData* pfd) {
|
||||
if (nullptr == mLastFrame) {
|
||||
if (!mLastFrame) {
|
||||
mFirstFrame = pfd;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
mLastFrame->mNext = pfd;
|
||||
pfd->mPrev = mLastFrame;
|
||||
}
|
||||
|
|
|
|||
11
layout/reftests/list-item/bullet-justify-1-ref.html
Normal file
11
layout/reftests/list-item/bullet-justify-1-ref.html
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<style>
|
||||
li {
|
||||
margin-left: 100px;
|
||||
font-size: 100px;
|
||||
}
|
||||
span {
|
||||
color: transparent;
|
||||
}
|
||||
</style>
|
||||
<li><span>x x</span></li>
|
||||
12
layout/reftests/list-item/bullet-justify-1.html
Normal file
12
layout/reftests/list-item/bullet-justify-1.html
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<style>
|
||||
li {
|
||||
margin-left: 100px;
|
||||
font-size: 100px;
|
||||
text-align-last: justify;
|
||||
}
|
||||
span {
|
||||
color: transparent;
|
||||
}
|
||||
</style>
|
||||
<li><span>x x</span></li>
|
||||
|
|
@ -12,3 +12,4 @@ asserts(1) == ol-reversed-1b.html ol-reversed-1-ref.html # bug 478135
|
|||
== bullet-space-2.html bullet-space-2-ref.html
|
||||
== bullet-intrinsic-isize-1.html bullet-intrinsic-isize-1-ref.html
|
||||
== bullet-intrinsic-isize-2.html bullet-intrinsic-isize-2-ref.html
|
||||
== bullet-justify-1.html bullet-justify-1-ref.html
|
||||
|
|
|
|||
|
|
@ -1102,6 +1102,7 @@ function runTests() {
|
|||
|
||||
test_parseable(":-moz-tree-row(selected)");
|
||||
test_parseable("::-moz-tree-row(selected)");
|
||||
test_parseable("::-MoZ-trEE-RoW(sElEcTeD)");
|
||||
test_parseable(":-moz-tree-row(selected focus)");
|
||||
test_parseable(":-moz-tree-row(selected , focus)");
|
||||
test_parseable("::-moz-tree-row(selected ,focus)");
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public class FirstrunPanel extends Fragment {
|
|||
@Override
|
||||
public void onClick(View v) {
|
||||
Telemetry.sendUIEvent(TelemetryContract.Event.ACTION, TelemetryContract.Method.BUTTON, "firstrun-next");
|
||||
pagerNavigation.next();
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -103,12 +103,6 @@ component {5850c76e-b916-4218-b99a-31f004e0a7e7} TabSource.js
|
|||
contract @mozilla.org/tab-source-service;1 {5850c76e-b916-4218-b99a-31f004e0a7e7}
|
||||
#endif
|
||||
|
||||
# Snippets.js
|
||||
component {a78d7e59-b558-4321-a3d6-dffe2f1e76dd} Snippets.js
|
||||
contract @mozilla.org/snippets;1 {a78d7e59-b558-4321-a3d6-dffe2f1e76dd}
|
||||
category browser-delayed-startup-finished Snippets @mozilla.org/snippets;1
|
||||
category update-timer Snippets @mozilla.org/snippets;1,getService,snippets-update-timer,browser.snippets.updateInterval,86400
|
||||
|
||||
# ColorPicker.js
|
||||
component {430b987f-bb9f-46a3-99a5-241749220b29} ColorPicker.js
|
||||
contract @mozilla.org/colorpicker;1 {430b987f-bb9f-46a3-99a5-241749220b29}
|
||||
|
|
|
|||
|
|
@ -1,449 +0,0 @@
|
|||
/* 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/. */
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Accounts.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyGlobalGetters(this, ["XMLHttpRequest"]);
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Home", "resource://gre/modules/Home.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "Task", "resource://gre/modules/Task.jsm");
|
||||
ChromeUtils.defineModuleGetter(this, "UITelemetry", "resource://gre/modules/UITelemetry.jsm");
|
||||
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gEncoder", function() { return new gChromeWin.TextEncoder(); });
|
||||
XPCOMUtils.defineLazyGetter(this, "gDecoder", function() { return new gChromeWin.TextDecoder(); });
|
||||
|
||||
// URL to fetch snippets, in the urlFormatter service format.
|
||||
const SNIPPETS_UPDATE_URL_PREF = "browser.snippets.updateUrl";
|
||||
|
||||
// URL to send stats data to metrics.
|
||||
const SNIPPETS_STATS_URL_PREF = "browser.snippets.statsUrl";
|
||||
|
||||
// URL to fetch country code, a value that's cached and refreshed once per month.
|
||||
const SNIPPETS_GEO_URL_PREF = "browser.snippets.geoUrl";
|
||||
|
||||
// Timestamp when we last updated the user's country code.
|
||||
const SNIPPETS_GEO_LAST_UPDATE_PREF = "browser.snippets.geoLastUpdate";
|
||||
|
||||
// Pref where we'll cache the user's country.
|
||||
const SNIPPETS_COUNTRY_CODE_PREF = "browser.snippets.countryCode";
|
||||
|
||||
// Pref where we store an array IDs of snippets that should not be shown again
|
||||
const SNIPPETS_REMOVED_IDS_PREF = "browser.snippets.removedIds";
|
||||
|
||||
// How frequently we update the user's country code from the server (30 days).
|
||||
const SNIPPETS_GEO_UPDATE_INTERVAL_MS = 86400000*30;
|
||||
|
||||
// Should be bumped up if the snippets content format changes.
|
||||
const SNIPPETS_VERSION = 1;
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gSnippetsURL", function() {
|
||||
let updateURL = Services.prefs.getCharPref(SNIPPETS_UPDATE_URL_PREF).replace("%SNIPPETS_VERSION%", SNIPPETS_VERSION);
|
||||
return Services.urlFormatter.formatURL(updateURL);
|
||||
});
|
||||
|
||||
// Where we cache snippets data
|
||||
XPCOMUtils.defineLazyGetter(this, "gSnippetsPath", function() {
|
||||
return OS.Path.join(OS.Constants.Path.profileDir, "snippets.json");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gStatsURL", function() {
|
||||
return Services.prefs.getCharPref(SNIPPETS_STATS_URL_PREF);
|
||||
});
|
||||
|
||||
// Where we store stats about which snippets have been shown
|
||||
XPCOMUtils.defineLazyGetter(this, "gStatsPath", function() {
|
||||
return OS.Path.join(OS.Constants.Path.profileDir, "snippets-stats.txt");
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gGeoURL", function() {
|
||||
return Services.prefs.getCharPref(SNIPPETS_GEO_URL_PREF);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gCountryCode", function() {
|
||||
try {
|
||||
return Services.prefs.getCharPref(SNIPPETS_COUNTRY_CODE_PREF);
|
||||
} catch (e) {
|
||||
// Return an empty string if the country code pref isn't set yet.
|
||||
return "";
|
||||
}
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gChromeWin", function() {
|
||||
return Services.wm.getMostRecentWindow("navigator:browser");
|
||||
});
|
||||
|
||||
/**
|
||||
* Updates snippet data and country code (if necessary).
|
||||
*/
|
||||
function update() {
|
||||
// Check to see if we should update the user's country code from the geo server.
|
||||
let lastUpdate = 0;
|
||||
try {
|
||||
lastUpdate = parseFloat(Services.prefs.getCharPref(SNIPPETS_GEO_LAST_UPDATE_PREF));
|
||||
} catch (e) {}
|
||||
|
||||
if (Date.now() - lastUpdate > SNIPPETS_GEO_UPDATE_INTERVAL_MS) {
|
||||
// We should update the snippets after updating the country code,
|
||||
// so that we can filter snippets to add to the banner.
|
||||
updateCountryCode(updateSnippets);
|
||||
} else {
|
||||
updateSnippets();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the user's country code from the geo server and stores the value in a pref.
|
||||
*
|
||||
* @param callback function called once country code is updated
|
||||
*/
|
||||
function updateCountryCode(callback) {
|
||||
_httpGetRequest(gGeoURL, function(responseText) {
|
||||
// Store the country code in a pref.
|
||||
let data = JSON.parse(responseText);
|
||||
Services.prefs.setCharPref(SNIPPETS_COUNTRY_CODE_PREF, data.country_code);
|
||||
|
||||
// Set last update time.
|
||||
Services.prefs.setCharPref(SNIPPETS_GEO_LAST_UPDATE_PREF, Date.now());
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads snippets from snippets server, caches the response, and
|
||||
* updates the home banner with the new set of snippets.
|
||||
*/
|
||||
function updateSnippets() {
|
||||
_httpGetRequest(gSnippetsURL, function(responseText) {
|
||||
try {
|
||||
let messages = JSON.parse(responseText);
|
||||
updateBanner(messages);
|
||||
|
||||
// Only cache the response if it is valid JSON.
|
||||
cacheSnippets(responseText);
|
||||
} catch (e) {
|
||||
Cu.reportError("Error parsing snippets responseText: " + e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches snippets server response text to `snippets.json` in profile directory.
|
||||
*
|
||||
* @param response responseText returned from snippets server
|
||||
*/
|
||||
function cacheSnippets(response) {
|
||||
let data = gEncoder.encode(response);
|
||||
let promise = OS.File.writeAtomic(gSnippetsPath, data, { tmpPath: gSnippetsPath + ".tmp" });
|
||||
promise.catch(e => Cu.reportError("Error caching snippets: " + e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads snippets from cached `snippets.json`.
|
||||
*/
|
||||
function loadSnippetsFromCache() {
|
||||
let promise = OS.File.read(gSnippetsPath);
|
||||
promise.then(array => {
|
||||
let messages = JSON.parse(gDecoder.decode(array));
|
||||
updateBanner(messages);
|
||||
}, e => {
|
||||
if (e instanceof OS.File.Error && e.becauseNoSuchFile) {
|
||||
Services.console.logStringMessage("Couldn't show snippets because cache does not exist yet.");
|
||||
} else {
|
||||
Cu.reportError("Error loading snippets from cache: " + e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Array of the message ids added to the home banner, used to remove
|
||||
// older set of snippets when new ones are available.
|
||||
var gMessageIds = [];
|
||||
|
||||
/**
|
||||
* Updates set of snippets in the home banner message rotation.
|
||||
*
|
||||
* @param messages JSON array of message data JSON objects.
|
||||
* Each message object should have the following properties:
|
||||
* - id (?): Unique identifier for this snippets message
|
||||
* - text (string): Text to show as banner message
|
||||
* - url (string): URL to open when banner is clicked
|
||||
* - icon (data URI): Icon to appear in banner
|
||||
* - countries (list of strings): Country codes for where this message should be shown (e.g. ["US", "GR"])
|
||||
*/
|
||||
function updateBanner(messages) {
|
||||
// Remove the current messages, if there are any.
|
||||
gMessageIds.forEach(function(id) {
|
||||
Home.banner.remove(id);
|
||||
})
|
||||
gMessageIds = [];
|
||||
|
||||
try {
|
||||
let removedSnippetIds = JSON.parse(Services.prefs.getCharPref(SNIPPETS_REMOVED_IDS_PREF));
|
||||
messages = messages.filter(function(message) {
|
||||
// Only include the snippet if it has not been previously removed.
|
||||
return !removedSnippetIds.includes(message.id);
|
||||
});
|
||||
} catch (e) {
|
||||
// If the pref doesn't exist, there aren't any snippets to filter out.
|
||||
}
|
||||
|
||||
messages.forEach(function(message) {
|
||||
// Don't add this message to the banner if it's not supposed to be shown in this country.
|
||||
if ("countries" in message && !message.countries.includes(gCountryCode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let id = Home.banner.add({
|
||||
text: message.text,
|
||||
icon: message.icon,
|
||||
weight: message.weight,
|
||||
onclick: function() {
|
||||
gChromeWin.BrowserApp.loadURI(message.url);
|
||||
removeSnippet(id, message.id);
|
||||
UITelemetry.addEvent("action.1", "banner", null, message.id);
|
||||
},
|
||||
ondismiss: function() {
|
||||
removeSnippet(id, message.id);
|
||||
UITelemetry.addEvent("cancel.1", "banner", null, message.id);
|
||||
},
|
||||
onshown: function() {
|
||||
// 10% of the time, record the snippet id and a timestamp
|
||||
if (Math.random() < .1) {
|
||||
writeStat(message.id, new Date().toISOString());
|
||||
}
|
||||
}
|
||||
});
|
||||
// Keep track of the message we added so that we can remove it later.
|
||||
gMessageIds.push(id);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a snippet message from the home banner rotation, and stores its
|
||||
* snippet id in a pref so we'll never show it again.
|
||||
*
|
||||
* @param messageId unique id for home banner message, returned from Home.banner API
|
||||
* @param snippetId unique id for snippet, sent from snippets server
|
||||
*/
|
||||
function removeSnippet(messageId, snippetId) {
|
||||
// Remove the message from the home banner rotation.
|
||||
Home.banner.remove(messageId);
|
||||
|
||||
// Remove the message from the stored message ids.
|
||||
gMessageIds.splice(gMessageIds.indexOf(messageId), 1);
|
||||
|
||||
let removedSnippetIds;
|
||||
try {
|
||||
removedSnippetIds = JSON.parse(Services.prefs.getCharPref(SNIPPETS_REMOVED_IDS_PREF));
|
||||
} catch (e) {
|
||||
removedSnippetIds = [];
|
||||
}
|
||||
|
||||
removedSnippetIds.push(snippetId);
|
||||
Services.prefs.setCharPref(SNIPPETS_REMOVED_IDS_PREF, JSON.stringify(removedSnippetIds));
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends snippet id and timestamp to the end of `snippets-stats.txt`.
|
||||
*
|
||||
* @param snippetId unique id for snippet, sent from snippets server
|
||||
* @param timestamp in ISO8601
|
||||
*/
|
||||
function writeStat(snippetId, timestamp) {
|
||||
let data = gEncoder.encode(snippetId + "," + timestamp + ";");
|
||||
|
||||
Task.spawn(function*() {
|
||||
try {
|
||||
let file = yield OS.File.open(gStatsPath, { append: true, write: true });
|
||||
try {
|
||||
yield file.write(data);
|
||||
} finally {
|
||||
yield file.close();
|
||||
}
|
||||
} catch (ex) {
|
||||
if (!(ex instanceof OS.File.Error && ex.becauseNoSuchFile)) {
|
||||
throw ex;
|
||||
}
|
||||
// If the file doesn't exist yet, create it.
|
||||
yield OS.File.writeAtomic(gStatsPath, data, { tmpPath: gStatsPath + ".tmp" });
|
||||
}
|
||||
}).catch(e => Cu.reportError("Error writing snippets stats: " + e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads snippets stats data from `snippets-stats.txt` and sends the data to metrics.
|
||||
*/
|
||||
function sendStats() {
|
||||
let promise = OS.File.read(gStatsPath);
|
||||
promise.then(array => sendStatsRequest(gDecoder.decode(array)), e => {
|
||||
if (e instanceof OS.File.Error && e.becauseNoSuchFile) {
|
||||
// If the file doesn't exist, there aren't any stats to send.
|
||||
} else {
|
||||
Cu.reportError("Error eading snippets stats: " + e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends stats to metrics about which snippets have been shown.
|
||||
* Appends snippet ids and timestamps as parameters to a GET request.
|
||||
* e.g. https://snippets-stats.mozilla.org/mobile?s1=3825&t1=2013-11-17T18:27Z&s2=6326&t2=2013-11-18T18:27Z
|
||||
*
|
||||
* @param data contents of stats data file
|
||||
*/
|
||||
function sendStatsRequest(data) {
|
||||
let params = [];
|
||||
let stats = data.split(";");
|
||||
|
||||
// The last item in the array will be an empty string, so stop before then.
|
||||
for (let i = 0; i < stats.length - 1; i++) {
|
||||
let stat = stats[i].split(",");
|
||||
params.push("s" + i + "=" + encodeURIComponent(stat[0]));
|
||||
params.push("t" + i + "=" + encodeURIComponent(stat[1]));
|
||||
}
|
||||
|
||||
let url = gStatsURL + "?" + params.join("&");
|
||||
|
||||
// Remove the file after succesfully sending the data.
|
||||
_httpGetRequest(url, removeStats);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes text file where we store snippets stats.
|
||||
*/
|
||||
function removeStats() {
|
||||
let promise = OS.File.remove(gStatsPath);
|
||||
promise.catch(e => Cu.reportError("Error removing snippets stats: " + e));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to make HTTP GET requests.
|
||||
*
|
||||
* @param url where we send the request
|
||||
* @param callback function that is called with the xhr responseText
|
||||
*/
|
||||
function _httpGetRequest(url, callback) {
|
||||
let xhr = new XMLHttpRequest();
|
||||
try {
|
||||
xhr.open("GET", url, true);
|
||||
} catch (e) {
|
||||
Cu.reportError("Error opening request to " + url + ": " + e);
|
||||
return;
|
||||
}
|
||||
xhr.onerror = function onerror(e) {
|
||||
Cu.reportError("Error making request to " + url + ": " + e.error);
|
||||
}
|
||||
xhr.onload = function onload(event) {
|
||||
if (xhr.status !== 200) {
|
||||
Cu.reportError("Request to " + url + " returned status " + xhr.status);
|
||||
return;
|
||||
}
|
||||
if (callback) {
|
||||
callback(xhr.responseText);
|
||||
}
|
||||
}
|
||||
xhr.send(null);
|
||||
}
|
||||
|
||||
function loadSyncPromoBanner() {
|
||||
Accounts.anySyncAccountsExist().then(
|
||||
(exist) => {
|
||||
// Don't show the banner if sync accounts exist.
|
||||
if (exist) {
|
||||
return;
|
||||
}
|
||||
|
||||
let stringBundle = Services.strings.createBundle("chrome://browser/locale/sync.properties");
|
||||
let text = stringBundle.GetStringFromName("promoBanner.message.text");
|
||||
let link = stringBundle.GetStringFromName("promoBanner.message.link");
|
||||
|
||||
let id = Home.banner.add({
|
||||
text: text + "<a href=\"#\">" + link + "</a>",
|
||||
icon: "drawable://sync_promo",
|
||||
onclick: function() {
|
||||
// Remove the message, so that it won't show again for the rest of the app lifetime.
|
||||
Home.banner.remove(id);
|
||||
Accounts.launchSetup();
|
||||
|
||||
UITelemetry.addEvent("action.1", "banner", null, "syncpromo");
|
||||
},
|
||||
ondismiss: function() {
|
||||
// Remove the sync promo message from the banner and never try to show it again.
|
||||
Home.banner.remove(id);
|
||||
Services.prefs.setBoolPref("browser.snippets.syncPromo.enabled", false);
|
||||
|
||||
UITelemetry.addEvent("cancel.1", "banner", null, "syncpromo");
|
||||
}
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
Cu.reportError("Error checking whether sync account exists: " + err);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function loadHomePanelsBanner() {
|
||||
let stringBundle = Services.strings.createBundle("chrome://browser/locale/aboutHome.properties");
|
||||
let text = stringBundle.GetStringFromName("banner.firstrunHomepage.text");
|
||||
|
||||
let id = Home.banner.add({
|
||||
text: text,
|
||||
icon: "drawable://homepage_banner_firstrun",
|
||||
onclick: function() {
|
||||
// Remove the message, so that it won't show again for the rest of the app lifetime.
|
||||
Home.banner.remove(id);
|
||||
// User has interacted with this snippet so don't show it again.
|
||||
Services.prefs.setBoolPref("browser.snippets.firstrunHomepage.enabled", false);
|
||||
|
||||
UITelemetry.addEvent("action.1", "banner", null, "firstrun-homepage");
|
||||
},
|
||||
ondismiss: function() {
|
||||
Home.banner.remove(id);
|
||||
Services.prefs.setBoolPref("browser.snippets.firstrunHomepage.enabled", false);
|
||||
|
||||
UITelemetry.addEvent("cancel.1", "banner", null, "firstrun-homepage");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function Snippets() {}
|
||||
|
||||
Snippets.prototype = {
|
||||
QueryInterface: ChromeUtils.generateQI([Ci.nsIObserver, Ci.nsITimerCallback]),
|
||||
classID: Components.ID("{a78d7e59-b558-4321-a3d6-dffe2f1e76dd}"),
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
switch(topic) {
|
||||
case "browser-delayed-startup-finished":
|
||||
// Add snippets to be cycled through.
|
||||
if (Services.prefs.getBoolPref("browser.snippets.firstrunHomepage.enabled")) {
|
||||
loadHomePanelsBanner();
|
||||
}
|
||||
|
||||
if (Services.prefs.getBoolPref("browser.snippets.syncPromo.enabled")) {
|
||||
loadSyncPromoBanner();
|
||||
}
|
||||
|
||||
if (Services.prefs.getBoolPref("browser.snippets.enabled")) {
|
||||
loadSnippetsFromCache();
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
// By default, this timer fires once every 24 hours. See the "browser.snippets.updateInterval" pref.
|
||||
notify: function(timer) {
|
||||
if (!Services.prefs.getBoolPref("browser.snippets.enabled")) {
|
||||
return;
|
||||
}
|
||||
update();
|
||||
sendStats();
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Snippets]);
|
||||
|
|
@ -36,7 +36,6 @@ EXTRA_COMPONENTS += [
|
|||
'PresentationRequestUIGlue.js',
|
||||
'PromptService.js',
|
||||
'SessionStore.js',
|
||||
'Snippets.js',
|
||||
'TabSource.js',
|
||||
'XPIDialogService.js',
|
||||
]
|
||||
|
|
|
|||
|
|
@ -373,7 +373,6 @@
|
|||
@BINPATH@/components/PresentationRequestUIGlue.js
|
||||
@BINPATH@/components/PromptService.js
|
||||
@BINPATH@/components/SessionStore.js
|
||||
@BINPATH@/components/Snippets.js
|
||||
@BINPATH@/components/XPIDialogService.js
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -441,6 +441,13 @@ VARCACHE_PREF(
|
|||
bool, false
|
||||
)
|
||||
|
||||
// Does arbitrary ::-webkit-* pseudo-element parsed?
|
||||
VARCACHE_PREF(
|
||||
"layout.css.unknown-webkit-pseudo-element",
|
||||
layout_css_unknown_webkit_pseudo_element,
|
||||
bool, false
|
||||
)
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// JavaScript prefs
|
||||
//---------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -49,12 +49,12 @@ TLSServerSocket::SetSocketDefaults()
|
|||
SSL_OptionSet(mFD, SSL_SECURITY, true);
|
||||
SSL_OptionSet(mFD, SSL_HANDSHAKE_AS_CLIENT, false);
|
||||
SSL_OptionSet(mFD, SSL_HANDSHAKE_AS_SERVER, true);
|
||||
SSL_OptionSet(mFD, SSL_NO_CACHE, true);
|
||||
|
||||
// We don't currently notify the server API consumer of renegotiation events
|
||||
// (to revalidate peer certs, etc.), so disable it for now.
|
||||
SSL_OptionSet(mFD, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_NEVER);
|
||||
|
||||
SetSessionCache(true);
|
||||
SetSessionTickets(true);
|
||||
SetRequestClientCertificate(REQUEST_NEVER);
|
||||
|
||||
|
|
@ -168,18 +168,6 @@ TLSServerSocket::SetServerCert(nsIX509Cert* aCert)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerSocket::SetSessionCache(bool aEnabled)
|
||||
{
|
||||
// If AsyncListen was already called (and set mListener), it's too late to set
|
||||
// this.
|
||||
if (NS_WARN_IF(mListener)) {
|
||||
return NS_ERROR_IN_PROGRESS;
|
||||
}
|
||||
SSL_OptionSet(mFD, SSL_NO_CACHE, !aEnabled);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TLSServerSocket::SetSessionTickets(bool aEnabled)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,15 +19,6 @@ interface nsITLSServerSocket : nsIServerSocket
|
|||
*/
|
||||
attribute nsIX509Cert serverCert;
|
||||
|
||||
/**
|
||||
* setSessionCache
|
||||
*
|
||||
* Whether the server should use a session cache. Defaults to true. This
|
||||
* should be set before calling |asyncListen| if you wish to change the
|
||||
* default.
|
||||
*/
|
||||
void setSessionCache(in boolean aSessionCache);
|
||||
|
||||
/**
|
||||
* setSessionTickets
|
||||
*
|
||||
|
|
|
|||
|
|
@ -152,7 +152,22 @@ IsLowPriority(uint16_t flags)
|
|||
// this macro filters out any flags that are not used when constructing the
|
||||
// host key. the significant flags are those that would affect the resulting
|
||||
// host record (i.e., the flags that are passed down to PR_GetAddrInfoByName).
|
||||
#define RES_KEY_FLAGS(_f) ((_f) & nsHostResolver::RES_CANON_NAME)
|
||||
#define RES_KEY_FLAGS(_f) ((_f) & (nsHostResolver::RES_CANON_NAME | \
|
||||
nsHostResolver::RES_DISABLE_TRR))
|
||||
|
||||
nsHostKey::nsHostKey(const nsACString& aHost, uint16_t aFlags,
|
||||
uint16_t aAf, bool aPb, const nsACString& aOriginsuffix)
|
||||
: host(aHost)
|
||||
, flags(aFlags)
|
||||
, af(aAf)
|
||||
, pb(aPb)
|
||||
, originSuffix(aOriginsuffix)
|
||||
{
|
||||
if (TRR_DISABLED(gTRRService->Mode())) {
|
||||
// When not using TRR, lookup all answers as TRR-disabled
|
||||
flags |= nsHostResolver::RES_DISABLE_TRR;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsHostKey::operator==(const nsHostKey& other) const
|
||||
|
|
|
|||
|
|
@ -57,16 +57,8 @@ struct nsHostKey
|
|||
uint16_t af;
|
||||
bool pb;
|
||||
const nsCString originSuffix;
|
||||
|
||||
nsHostKey(const nsACString& host, uint16_t flags,
|
||||
uint16_t af, bool pb, const nsACString& originSuffix)
|
||||
: host(host)
|
||||
, flags(flags)
|
||||
, af(af)
|
||||
, pb(pb)
|
||||
, originSuffix(originSuffix) {
|
||||
}
|
||||
|
||||
explicit nsHostKey(const nsACString& host, uint16_t flags,
|
||||
uint16_t af, bool pb, const nsACString& originSuffix);
|
||||
bool operator==(const nsHostKey& other) const;
|
||||
size_t SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
PLDHashNumber Hash() const;
|
||||
|
|
|
|||
|
|
@ -5121,7 +5121,7 @@ nsHttpConnectionMgr::nsHalfOpenSocket::OnTransportStatus(nsITransport *trans,
|
|||
if (NS_SUCCEEDED(rv) && !addressSet.IsEmpty()) {
|
||||
for (uint32_t i = 0; i < addressSet.Length(); ++i) {
|
||||
nsCString *newKey = mEnt->mCoalescingKeys.AppendElement(nsCString());
|
||||
newKey->SetCapacity(kIPv6CStrBufSize + 26);
|
||||
newKey->SetLength(kIPv6CStrBufSize + 26);
|
||||
NetAddrToString(&addressSet[i], newKey->BeginWriting(), kIPv6CStrBufSize);
|
||||
newKey->SetLength(strlen(newKey->BeginReading()));
|
||||
if (mEnt->mConnInfo->GetAnonymous()) {
|
||||
|
|
|
|||
|
|
@ -139,7 +139,6 @@ function startServer(cert, minServerVersion, maxServerVersion) {
|
|||
tlsServer.init(-1, true, -1);
|
||||
tlsServer.serverCert = cert;
|
||||
tlsServer.setVersionRange(minServerVersion, maxServerVersion);
|
||||
tlsServer.setSessionCache(false);
|
||||
tlsServer.setSessionTickets(false);
|
||||
tlsServer.asyncListen(new ServerSocketListener());
|
||||
return tlsServer;
|
||||
|
|
|
|||
|
|
@ -139,7 +139,6 @@ function startServer(cert, minServerVersion, maxServerVersion) {
|
|||
tlsServer.init(-1, true, -1);
|
||||
tlsServer.serverCert = cert;
|
||||
tlsServer.setVersionRange(minServerVersion, maxServerVersion);
|
||||
tlsServer.setSessionCache(false);
|
||||
tlsServer.setSessionTickets(false);
|
||||
tlsServer.asyncListen(new ServerSocketListener());
|
||||
return tlsServer;
|
||||
|
|
|
|||
|
|
@ -118,7 +118,6 @@ function startServer(cert, minServerVersion, maxServerVersion, expectedVersion)
|
|||
tlsServer.init(-1, true, -1);
|
||||
tlsServer.serverCert = cert;
|
||||
tlsServer.setVersionRange(minServerVersion, maxServerVersion);
|
||||
tlsServer.setSessionCache(false);
|
||||
tlsServer.setSessionTickets(false);
|
||||
|
||||
let listener = {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,6 @@ function startServer(cert, expectingPeerCert, clientCertificateConfig,
|
|||
}
|
||||
};
|
||||
|
||||
tlsServer.setSessionCache(false);
|
||||
tlsServer.setSessionTickets(false);
|
||||
tlsServer.setRequestClientCertificate(clientCertificateConfig);
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@ function startServer(cert) {
|
|||
onStopListening: function() {}
|
||||
};
|
||||
|
||||
tlsServer.setSessionCache(true);
|
||||
tlsServer.setSessionTickets(false);
|
||||
|
||||
tlsServer.asyncListen(listener);
|
||||
|
|
|
|||
|
|
@ -307,10 +307,15 @@ class TupBackend(CommonBackend):
|
|||
args += ['-j%d' % jobs]
|
||||
else:
|
||||
args += ['-j%d' % multiprocessing.cpu_count()]
|
||||
|
||||
tiers = output.monitor.tiers
|
||||
tiers.set_tiers(('tup',))
|
||||
tiers.begin_tier('tup')
|
||||
status = config.run_process(args=args,
|
||||
line_handler=output.on_line,
|
||||
ensure_exit_code=False,
|
||||
append_env=self._get_mozconfig_env(config))
|
||||
tiers.finish_tier('tup')
|
||||
if not status and self.environment.substs.get('MOZ_AUTOMATION'):
|
||||
src = mozpath.join(self.environment.topsrcdir, '.tup')
|
||||
dst = os.environ['UPLOAD_PATH']
|
||||
|
|
|
|||
|
|
@ -1264,7 +1264,7 @@ class PackageFrontend(MachCommandBase):
|
|||
help='Use the given url as tooltool server')
|
||||
@CommandArgument('--no-unpack', action='store_true',
|
||||
help='Do not unpack any downloaded file')
|
||||
@CommandArgument('--retry', type=int, default=0,
|
||||
@CommandArgument('--retry', type=int, default=4,
|
||||
help='Number of times to retry failed downloads')
|
||||
@CommandArgument('--artifact-manifest', metavar='FILE',
|
||||
help='Store a manifest about the downloaded taskcluster artifacts')
|
||||
|
|
|
|||
|
|
@ -848,7 +848,7 @@ class TestEmitterBasic(unittest.TestCase):
|
|||
objs = [o for o in self.read_topsrcdir(reader)
|
||||
if isinstance(o, TestManifest)]
|
||||
|
||||
self.assertEqual(len(objs), 9)
|
||||
self.assertEqual(len(objs), 8)
|
||||
|
||||
metadata = {
|
||||
'a11y.ini': {
|
||||
|
|
@ -868,13 +868,6 @@ class TestEmitterBasic(unittest.TestCase):
|
|||
'support2': False,
|
||||
},
|
||||
},
|
||||
'metro.ini': {
|
||||
'flavor': 'metro-chrome',
|
||||
'installs': {
|
||||
'metro.ini': False,
|
||||
'test_metro.js': True,
|
||||
},
|
||||
},
|
||||
'mochitest.ini': {
|
||||
'flavor': 'mochitest',
|
||||
'installs': {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ TEST_MANIFESTS = dict(
|
|||
MARIONETTE_UNIT=('marionette', 'marionette', '.', False),
|
||||
MARIONETTE_WEBAPI=('marionette', 'marionette', '.', False),
|
||||
|
||||
METRO_CHROME=('metro-chrome', 'testing/mochitest', 'metro', True),
|
||||
MOCHITEST=('mochitest', 'testing/mochitest', 'tests', True),
|
||||
MOCHITEST_CHROME=('chrome', 'testing/mochitest', 'chrome', True),
|
||||
WEBRTC_SIGNALLING_TEST=('steeplechase', 'steeplechase', '.', True),
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ nsNSSComponent::nsNSSComponent()
|
|||
, mLoadableRootsLoadedResult(NS_ERROR_FAILURE)
|
||||
, mMutex("nsNSSComponent.mMutex")
|
||||
, mMitmDetecionEnabled(false)
|
||||
, mNonIdempotentCleanupMustHappen(false)
|
||||
, mLoadLoadableRootsTaskDispatched(false)
|
||||
{
|
||||
MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("nsNSSComponent::ctor\n"));
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread());
|
||||
|
|
@ -1945,17 +1945,6 @@ nsNSSComponent::InitializeNSS()
|
|||
MOZ_ALWAYS_SUCCEEDS(handle->TrustLoaded3rdPartyRoots());
|
||||
}));
|
||||
|
||||
// TLSServerSocket may be run with the session cache enabled. It is
|
||||
// necessary to call this once before that can happen. This specifies a
|
||||
// maximum of 1000 cache entries (the default number of cache entries is
|
||||
// 10000, which seems a little excessive as there probably won't be that
|
||||
// many clients connecting to any TLSServerSockets the browser runs.) Note
|
||||
// that this must occur before any calls to SSL_ClearSessionCache (otherwise
|
||||
// memory will leak).
|
||||
if (SSL_ConfigServerSessionIDCache(1000, 0, 0, nullptr) != SECSuccess) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Set dynamic options from prefs. This has to run after
|
||||
// SSL_ConfigServerSessionIDCache.
|
||||
setValidationOptions(true, lock);
|
||||
|
|
@ -1967,7 +1956,7 @@ nsNSSComponent::InitializeNSS()
|
|||
return rv;
|
||||
}
|
||||
|
||||
mNonIdempotentCleanupMustHappen = true;
|
||||
mLoadLoadableRootsTaskDispatched = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
|
@ -1986,16 +1975,9 @@ nsNSSComponent::ShutdownNSS()
|
|||
// it to fail to find the roots it is expecting. However, if initialization
|
||||
// failed, we won't have dispatched the load loadable roots background task.
|
||||
// In that case, we don't want to block on an event that will never happen.
|
||||
if (mNonIdempotentCleanupMustHappen) {
|
||||
if (mLoadLoadableRootsTaskDispatched) {
|
||||
Unused << BlockUntilLoadableRootsLoaded();
|
||||
|
||||
// We can only run SSL_ShutdownServerSessionIDCache once (the rest of
|
||||
// these operations are idempotent).
|
||||
SSL_ClearSessionCache();
|
||||
// TLSServerSocket may be run with the session cache enabled. This ensures
|
||||
// those resources are cleaned up.
|
||||
Unused << SSL_ShutdownServerSessionIDCache();
|
||||
mNonIdempotentCleanupMustHappen = false;
|
||||
mLoadLoadableRootsTaskDispatched = false;
|
||||
}
|
||||
|
||||
::mozilla::psm::UnloadLoadableRoots();
|
||||
|
|
|
|||
|
|
@ -118,21 +118,13 @@ private:
|
|||
|
||||
// The following members are accessed only on the main thread:
|
||||
static int mInstanceCount;
|
||||
// If initialization (i.e. InitializeNSS) succeeds, we have called
|
||||
// SSL_ConfigServerSessionIDCache. To clean this up, we must call
|
||||
// SSL_ClearSessionCache and SSL_ShutdownServerSessionIDCache exactly once
|
||||
// each (and if we haven't called SSL_ConfigServerSessionIDCache - for example
|
||||
// if initialization failed - then we mustn't call the cleanup functions
|
||||
// ever). There are multiple events that can cause us to enter our cleanup
|
||||
// function (ShutdownNSS) and so we keep track of if we need to call these
|
||||
// non-idempotent functions in the following boolean.
|
||||
// Similarly, if InitializeNSS succeeds, then we have dispatched an event to
|
||||
// load the loadable roots module on a background thread. We must wait for it
|
||||
// to complete before attempting to unload the module again in ShutdownNSS. If
|
||||
// we never dispatched the event, then we can't wait for it to complete
|
||||
// (because it will never complete) so we again use this boolean to keep track
|
||||
// of if we should wait.
|
||||
bool mNonIdempotentCleanupMustHappen;
|
||||
// If InitializeNSS succeeds, then we have dispatched an event to load the
|
||||
// loadable roots module on a background thread. We must wait for it to
|
||||
// complete before attempting to unload the module again in ShutdownNSS. If we
|
||||
// never dispatched the event, then we can't wait for it to complete (because
|
||||
// it will never complete) so we use this boolean to keep track of if we
|
||||
// should wait.
|
||||
bool mLoadLoadableRootsTaskDispatched;
|
||||
};
|
||||
|
||||
inline nsresult
|
||||
|
|
|
|||
|
|
@ -138,7 +138,6 @@ function getStartedServer(cert) {
|
|||
.createInstance(Ci.nsITLSServerSocket);
|
||||
tlsServer.init(-1, true, -1);
|
||||
tlsServer.serverCert = cert;
|
||||
tlsServer.setSessionCache(false);
|
||||
tlsServer.setSessionTickets(false);
|
||||
tlsServer.asyncListen(new ServerSocketListener());
|
||||
return tlsServer;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use properties::{ComputedValues, PropertyFlags};
|
|||
use properties::longhands::display::computed_value::T as Display;
|
||||
use selector_parser::{NonTSPseudoClass, PseudoElementCascadeType, SelectorImpl};
|
||||
use std::fmt;
|
||||
use str::{starts_with_ignore_ascii_case, string_as_ascii_lowercase};
|
||||
use string_cache::Atom;
|
||||
use thin_slice::ThinBoxedSlice;
|
||||
use values::serialize_atom_identifier;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue